/// <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), });
/// <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); } }
/// <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(); } } }
/// <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(); } } }
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(); } } }
/// <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); } }