public override void ChannelInactive(IChannelHandlerContext ctx) { ThreadLocalObjectList output = ThreadLocalObjectList.NewInstance(); try { if (this.cumulation != null) { this.CallDecode(ctx, this.cumulation, output); this.DecodeLast(ctx, this.cumulation, output); } else { this.DecodeLast(ctx, Unpooled.Empty, output); } } catch (DecoderException e) { throw e; } catch (Exception e) { throw new DecoderException(e); } finally { try { if (this.cumulation != null) { this.cumulation.Release(); this.cumulation = null; } int size = output.Count; for (int i = 0; i < size; i++) { ctx.FireChannelRead(output[i]); } if (size > 0) { // Something was read, call fireChannelReadComplete() ctx.FireChannelReadComplete(); } ctx.FireChannelInactive(); } finally { // recycle in all cases output.Return(); } } }
/// <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); } }
public override void ChannelRead(IChannelHandlerContext context, object message) { var data = message as IByteBuffer; if (data != null) { ThreadLocalObjectList output = ThreadLocalObjectList.NewInstance(); try { this.first = this.cumulation == null; if (this.first) { this.cumulation = data; } else { this.cumulation = this.cumulator(context.Allocator, this.cumulation, data); } this.CallDecode(context, this.cumulation, output); } catch (DecoderException) { throw; } catch (Exception ex) { throw new DecoderException(ex); } finally { if (this.cumulation != null && !this.cumulation.IsReadable()) { this.cumulation.Release(); this.cumulation = null; } int size = output.Count; this.decodeWasNull = size == 0; for (int i = 0; i < size; i++) { context.FireChannelRead(output[i]); } 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(); } } }
/// <summary> /// Write messages to the outbound of this <see cref="IChannel" />. /// </summary> /// <param name="msgs">The messages to be written.</param> /// <returns><c>true</c> if the write operation did add something to the inbound buffer</returns> public bool WriteOutbound(params object[] msgs) { EnsureOpen(); if (0u >= (uint)msgs.Length) { return(_outboundMessages.NonEmpty); } ThreadLocalObjectList futures = ThreadLocalObjectList.NewInstance(msgs.Length); try { for (int i = 0; i < msgs.Length; i++) { object m = msgs[i]; if (m is null) { break; } futures.Add(WriteAsync(m)); } FlushOutbound0(); int size = futures.Count; for (int i = 0; i < size; i++) { var future = (Task)futures[i]; if (future.IsCompleted) { RecordException(future); } else { // The write may be delayed to run later by RunPendingTasks() future.ContinueWith(t => RecordException(t), TaskContinuationOptions.ExecuteSynchronously); } } CheckException(); return(_outboundMessages.NonEmpty); } finally { futures.Return(); } }
static void EncodeSubscribeMessage(IByteBufferAllocator bufferAllocator, SubscribePacket packet, List <object> output) { const int VariableHeaderSize = PacketIdLength; int payloadBufferSize = 0; ThreadLocalObjectList encodedTopicFilters = ThreadLocalObjectList.NewInstance(); IByteBuffer buf = null; try { foreach (SubscriptionRequest topic in packet.Requests) { byte[] topicFilterBytes = EncodeStringInUtf8(topic.TopicFilter); payloadBufferSize += StringSizeLength + topicFilterBytes.Length + 1; // length, value, QoS encodedTopicFilters.Add(topicFilterBytes); } int variablePartSize = VariableHeaderSize + payloadBufferSize; int fixedHeaderBufferSize = 1 + MaxVariableLength; buf = bufferAllocator.Buffer(fixedHeaderBufferSize + variablePartSize); buf.WriteByte(CalculateFirstByteOfFixedHeader(packet)); WriteVariableLengthInt(buf, variablePartSize); // Variable Header buf.WriteShort(packet.PacketId); // todo: review: validate? // Payload for (int i = 0; i < encodedTopicFilters.Count; i++) { var topicFilterBytes = (byte[])encodedTopicFilters[i]; buf.WriteShort(topicFilterBytes.Length); buf.WriteBytes(topicFilterBytes, 0, topicFilterBytes.Length); buf.WriteByte((int)packet.Requests[i].QualityOfService); } output.Add(buf); buf = null; } finally { buf?.SafeRelease(); encodedTopicFilters.Return(); } }
static void EncodeUnsubscribeMessage(IByteBufferAllocator bufferAllocator, UnsubscribePacket packet, List <Object> output) { const Int32 VariableHeaderSize = 2; var payloadBufferSize = 0; ThreadLocalObjectList encodedTopicFilters = ThreadLocalObjectList.NewInstance(); Packet buf = null; try { foreach (var topic in packet.TopicFilters) { var topicFilterBytes = EncodeStringInUtf8(topic); payloadBufferSize += StringSizeLength + topicFilterBytes.Length; // length, value encodedTopicFilters.Add(topicFilterBytes); } var variablePartSize = VariableHeaderSize + payloadBufferSize; var fixedHeaderBufferSize = 1 + MaxVariableLength; buf = bufferAllocator.Buffer(fixedHeaderBufferSize + variablePartSize); buf.WriteByte(CalculateFirstByteOfFixedHeader(packet)); WriteVariableLengthInt(buf, variablePartSize); // Variable Header buf.WriteShort(packet.PacketId); // todo: review: validate? // Payload for (var i = 0; i < encodedTopicFilters.Count; i++) { var topicFilterBytes = (Byte[])encodedTopicFilters[i]; buf.WriteShort(topicFilterBytes.Length); buf.WriteBytes(topicFilterBytes, 0, topicFilterBytes.Length); } output.Add(buf); buf = null; } finally { buf?.SafeRelease(); encodedTopicFilters.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> /// Write messages to the outbound of this <see cref="IChannel" />. /// </summary> /// <param name="msgs">The messages to be written.</param> /// <returns><c>true</c> if the write operation did add something to the inbound buffer</returns> public bool WriteOutbound(params object[] msgs) { this.EnsureOpen(); if (msgs.Length == 0) { return(IsNotEmpty(this.outboundMessages)); } ThreadLocalObjectList futures = ThreadLocalObjectList.NewInstance(msgs.Length); foreach (object m in msgs) { if (m == null) { break; } futures.Add(this.WriteAsync(m)); } // We need to call RunPendingTasks first as a IChannelHandler may have used IEventLoop.Execute(...) to // delay the write on the next event loop run. this.RunPendingTasks(); this.Flush(); int size = futures.Count; for (int i = 0; i < size; i++) { var future = (Task)futures[i]; if (future.IsCompleted) { this.RecordException(future); } else { // The write may be delayed to run later by runPendingTasks() future.ContinueWith(t => this.RecordException(t)); } } futures.Return(); this.RunPendingTasks(); this.CheckException(); return(IsNotEmpty(this.outboundMessages)); }
public override Task WriteAsync(IChannelHandlerContext ctx, object msg) { Task result; ThreadLocalObjectList output = null; try { if (this.AcceptOutboundMessage(msg)) { output = ThreadLocalObjectList.NewInstance(); var cast = (T)msg; try { this.Encode(ctx, cast, output); } finally { ReferenceCountUtil.Release(cast); } if (output.Count == 0) { output.Return(); output = null; throw new EncoderException(this.GetType().Name + " must produce at least one message."); } } else { return(ctx.WriteAsync(msg)); } } catch (EncoderException e) { return(TaskEx.FromException(e)); } catch (Exception ex) { return(TaskEx.FromException(new EncoderException(ex))); // todo: we don't have a stack on EncoderException but it's present on inner exception. } finally { if (output != null) { int lastItemIndex = output.Count - 1; if (lastItemIndex == 0) { result = ctx.WriteAsync(output[0]); } else if (lastItemIndex > 0) { for (int i = 0; i < lastItemIndex; i++) { // we don't care about output from these messages as failure while sending one of these messages will fail all messages up to the last message - which will be observed by the caller in Task result. ctx.WriteAsync(output[i]); // todo: optimize: once IChannelHandlerContext allows, pass "not interested in task" flag } result = ctx.WriteAsync(output[lastItemIndex]); } else { // 0 items in output - must never get here result = null; } output.Return(); } else { // output was reset during exception handling - must never get here result = null; } } return(result); }
/// <inheritdoc /> public override void Write(IChannelHandlerContext ctx, object msg, IPromise promise) { ThreadLocalObjectList output = null; try { if (AcceptOutboundMessage(msg)) { output = ThreadLocalObjectList.NewInstance(); var cast = (T)msg; try { Encode(ctx, cast, output); } finally { _ = ReferenceCountUtil.Release(cast); } if (0u >= (uint)output.Count) { CThrowHelper.ThrowEncoderException_MustProduceAtLeastOneMsg(GetType()); } } else { _ = ctx.WriteAsync(msg, promise); } } catch (EncoderException) { throw; } catch (Exception ex) { CThrowHelper.ThrowEncoderException(ex); // todo: we don't have a stack on EncoderException but it's present on inner exception. } finally { if (output is object) { try { int lastItemIndex = output.Count - 1; if (0u >= (uint)lastItemIndex) { _ = ctx.WriteAsync(output[0], promise); } else if (lastItemIndex > 0) { // Check if we can use a voidPromise for our extra writes to reduce GC-Pressure // See https://github.com/netty/netty/issues/2525 if (promise == ctx.VoidPromise()) { WriteVoidPromise(ctx, output); } else { WritePromiseCombiner(ctx, output, promise); } } } finally { output.Return(); } } } }
public override void HandlerRemoved(IChannelHandlerContext ctx) { FireBufferedMessages(); _bufferedMessages.Return(); base.HandlerRemoved(ctx); }
public override Task WriteAsync(IChannelHandlerContext ctx, object msg) { Task result; ThreadLocalObjectList output = null; try { if (base.AcceptOutboundMessage(msg)) { output = ThreadLocalObjectList.NewInstance(); var cast = (PacketInfo)msg; try { base.Encode(ctx, cast, output); } finally { ReferenceCountUtil.Release(cast); } if (output.Count == 0) { output.Return(); output = null; throw new EncoderException(this.GetType().Name + " must produce at least one message."); } } else { return(ctx.WriteAsync(msg)); } } catch (EncoderException e) { throw new EncoderException(e); } catch (Exception ex) { throw new EncoderException(ex); } finally { if (output != null) { if (output.Count > 0) { IByteBuffer byteBuffer = Unpooled.CopiedBuffer(output.ConvertAll(v => v as IByteBuffer).ToArray()); result = ctx.WriteAsync(new BinaryWebSocketFrame(byteBuffer)); } else { // 0 items in output - must never get here result = null; } output.Return(); } else { // output was reset during exception handling - must never get here result = null; } } return(result); }