/// <summary>
 ///     Decodes the specified region of the buffer into an unadjusted frame length.  The default implementation is
 ///     capable of decoding the specified region into an unsigned 8/16/24/32/64 bit integer.  Override this method to
 ///     decode the length field encoded differently.
 ///     Note that this method must not modify the state of the specified buffer (e.g.
 ///     <see cref="IByteBuffer.ReaderIndex" />,
 ///     <see cref="IByteBuffer.WriterIndex" />, and the content of the buffer.)
 /// </summary>
 /// <param name="buffer">The buffer we'll be extracting the frame length from.</param>
 /// <param name="offset">The offset from the absolute <see cref="IByteBuffer.ReaderIndex" />.</param>
 /// <param name="length">The length of the framelenght field. Expected: 1, 2, 3, 4, or 8.</param>
 /// <returns>A long integer that represents the unadjusted length of the next frame.</returns>
 protected static long GetUnadjustedFrameLength(IByteBuffer buffer, int offset, int length)
 {
     return(length switch
     {
         1 => buffer.GetByte(offset),
         2 => buffer.GetUnsignedShort(offset),
         3 => buffer.GetUnsignedMedium(offset),
         4 => buffer.GetInt(offset),
         8 => buffer.GetLong(offset),
         _ => CThrowHelper.ThrowDecoderException(length),
     });
예제 #2
0
        /// <inheritdoc />
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            if (message is IByteBuffer data)
            {
                ThreadLocalObjectList output = ThreadLocalObjectList.NewInstance();
                try
                {
                    _first      = _cumulation is null;
                    _cumulation = _cumulator.Cumulate(context.Allocator, _first ? Unpooled.Empty : _cumulation, data);
                    CallDecode(context, _cumulation, output);
                }
                catch (DecoderException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    CThrowHelper.ThrowDecoderException(ex);
                }
                finally
                {
                    try
                    {
                        if (_cumulation is object && !_cumulation.IsReadable())
                        {
                            _numReads   = 0;
                            _           = _cumulation.Release();
                            _cumulation = null;
                        }
                        else if (++_numReads >= _discardAfterReads)
                        {
                            // We did enough reads already try to discard some bytes so we not risk to see a OOME.
                            // See https://github.com/netty/netty/issues/4275
                            _numReads = 0;
                            DiscardSomeReadBytes();
                        }

                        int size = output.Count;
                        _firedChannelRead |= (uint)size > 0u;
                        FireChannelRead(context, output, size);
                    }
                    finally
                    {
                        output.Return();
                    }
                }
            }
            else
            {
                _ = context.FireChannelRead(message);
            }
        }
예제 #3
0
        /// <inheritdoc />
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            ThreadLocalObjectList output = ThreadLocalObjectList.NewInstance();

            try
            {
                if (this.AcceptInboundMessage(message))
                {
                    var cast = (T)message;
                    try
                    {
                        this.Decode(context, cast, output);
                    }
                    finally
                    {
                        _ = ReferenceCountUtil.Release(cast);
                    }
                }
                else
                {
                    output.Add(message);
                }
            }
            catch (DecoderException)
            {
                throw;
            }
            catch (Exception e)
            {
                CThrowHelper.ThrowDecoderException(e);
            }
            finally
            {
                try
                {
                    int size = output.Count;
                    for (int i = 0; i < size; i++)
                    {
                        _ = context.FireChannelRead(output[i]);
                    }
                }
                finally
                {
                    output.Return();
                }
            }
        }
예제 #4
0
        /// <inheritdoc />
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            ThreadLocalObjectList output = ThreadLocalObjectList.NewInstance();

            try
            {
                if (message is IByteBuffer byteBuffer)
                {
                    try
                    {
                        var reader = new ByteBufferReader(byteBuffer);
                        Decode(context, ref reader, output);
                    }
                    finally
                    {
                        _ = ReferenceCountUtil.Release(message);
                    }
                }
                else
                {
                    output.Add(message);
                }
            }
            catch (DecoderException)
            {
                throw;
            }
            catch (Exception e)
            {
                CThrowHelper.ThrowDecoderException(e);
            }
            finally
            {
                try
                {
                    int size = output.Count;
                    for (int i = 0; i < size; i++)
                    {
                        _ = context.FireChannelRead(output[i]);
                    }
                }
                finally
                {
                    output.Return();
                }
            }
        }
예제 #5
0
        private void ChannelInputClosed(IChannelHandlerContext ctx, bool callChannelInactive)
        {
            ThreadLocalObjectList output = ThreadLocalObjectList.NewInstance();

            try
            {
                ChannelInputClosed(ctx, output);
            }
            catch (DecoderException)
            {
                throw;
            }
            catch (Exception e)
            {
                CThrowHelper.ThrowDecoderException(e);
            }
            finally
            {
                try
                {
                    if (_cumulation is object)
                    {
                        _           = _cumulation.Release();
                        _cumulation = null;
                    }
                    int size = output.Count;
                    if ((uint)size > 0u)
                    {
                        FireChannelRead(ctx, output, size);
                        // Something was read, call fireChannelReadComplete()
                        _ = ctx.FireChannelReadComplete();
                    }
                    if (callChannelInactive)
                    {
                        _ = ctx.FireChannelInactive();
                    }
                }
                finally
                {
                    // Recycle in all cases
                    output.Return();
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Called once data should be decoded from the given <see cref="IByteBuffer"/>. This method will call
        /// <see cref="Decode(IChannelHandlerContext, IByteBuffer, List{object})"/> as long as decoding should take place.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="input"></param>
        /// <param name="output"></param>
        protected virtual void CallDecode(IChannelHandlerContext context, IByteBuffer input, List <object> output)
        {
            if (context is null)
            {
                CThrowHelper.ThrowArgumentNullException(CExceptionArgument.context);
            }
            if (input is null)
            {
                CThrowHelper.ThrowArgumentNullException(CExceptionArgument.input);
            }
            if (output is null)
            {
                CThrowHelper.ThrowArgumentNullException(CExceptionArgument.output);
            }

            try
            {
                while (input.IsReadable())
                {
                    int initialOutputCount = output.Count;
                    if ((uint)initialOutputCount > 0u)
                    {
                        FireChannelRead(context, output, initialOutputCount);
                        output.Clear();

                        // Check if this handler was removed before continuing with decoding.
                        // If it was removed, it is not safe to continue to operate on the buffer.
                        //
                        // See:
                        // - https://github.com/netty/netty/issues/4635
                        if (context.IsRemoved)
                        {
                            break;
                        }
                        initialOutputCount = 0;
                    }

                    int oldInputLength = input.ReadableBytes;
                    DecodeRemovalReentryProtection(context, input, output);

                    // Check if this handler was removed before continuing the loop.
                    // If it was removed, it is not safe to continue to operate on the buffer.
                    //
                    // See https://github.com/netty/netty/issues/1664
                    if (context.IsRemoved)
                    {
                        break;
                    }

                    bool noOutgoingMessages = 0u >= (uint)(oldInputLength - input.ReadableBytes);
                    if (0u >= (uint)(initialOutputCount - output.Count))
                    {
                        // no outgoing messages have been produced

                        if (noOutgoingMessages)
                        {
                            break;
                        }
                        else
                        {
                            continue;
                        }
                    }

                    if (noOutgoingMessages)
                    {
                        CThrowHelper.ThrowDecoderException_ByteToMessageDecoder(GetType());
                    }

                    if (SingleDecode)
                    {
                        break;
                    }
                }
            }
            catch (DecoderException)
            {
                throw;
            }
            catch (Exception cause)
            {
                CThrowHelper.ThrowDecoderException(cause);
            }
        }