protected override void Decode(IChannelHandlerContext context, IHttpObject message, List <object> output)
        {
            // Determine if we're already handling an upgrade request or just starting a new one.
            this.handlingUpgrade |= IsUpgradeRequest(message);
            if (!this.handlingUpgrade)
            {
                // Not handling an upgrade request, just pass it to the next handler.
                ReferenceCountUtil.Retain(message);
                output.Add(message);
                return;
            }

            if (message is IFullHttpRequest fullRequest)
            {
                ReferenceCountUtil.Retain(fullRequest);
                output.Add(fullRequest);
            }
            else
            {
                // Call the base class to handle the aggregation of the full request.
                base.Decode(context, message, output);
                if (output.Count == 0)
                {
                    // The full request hasn't been created yet, still awaiting more data.
                    return;
                }

                // Finished aggregating the full request, get it from the output list.
                Debug.Assert(output.Count == 1);
                this.handlingUpgrade = false;
                fullRequest          = (IFullHttpRequest)output[0];
            }

            if (this.Upgrade(context, fullRequest))
            {
                // The upgrade was successful, remove the message from the output list
                // so that it's not propagated to the next handler. This request will
                // be propagated as a user event instead.
                output.Clear();
            }

            // The upgrade did not succeed, just allow the full request to propagate to the
            // next handler.
        }
        async void StartQueueProcessingAsync(IChannelHandlerContext context)
        {
            try
            {
                Queue <T> queue = this.backlogQueue;
                while (queue.Count > 0 && this.state != State.Closed)
                {
                    T message = queue.Dequeue();
                    try
                    {
                        await this.ProcessAsync(context, message);

                        message = default(T); // dismissing packet reference as it has been successfully handed off in a form of message
                    }
                    finally
                    {
                        if (message != null)
                        {
                            ReferenceCountUtil.SafeRelease(message);
                        }
                    }
                }

                switch (this.state)
                {
                case State.Processing:
                    this.state = State.Idle;
                    break;

                case State.Closed:
                    this.closedPromise.TryComplete();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            catch (Exception ex)
            {
                this.closedPromise.TrySetException(new ChannelMessageProcessingException(ex, context));
                this.Close();
            }
        }
        public void DecodeError(string value)
        {
            var channel = new EmbeddedChannel(
                new RedisDecoder(),
                new RedisBulkStringAggregator(),
                new RedisArrayAggregator());

            Assert.False(channel.WriteInbound("-".Buffer()));
            Assert.False(channel.WriteInbound(value.Buffer()));
            Assert.False(channel.WriteInbound("\r".Buffer()));
            Assert.True(channel.WriteInbound("\n".Buffer()));

            var message = channel.ReadInbound <ErrorRedisMessage>();

            Assert.Equal(value, message.Content);

            ReferenceCountUtil.Release(message);
            Assert.False(channel.Finish());
        }
Beispiel #4
0
        public void DecodeBulkString()
        {
            const string Buf1 = "bulk\nst";
            const string Buf2 = "ring\ntest\n1234";

            byte[] content = BytesOf(Buf1 + Buf2);
            Assert.False(this.channel.WriteInbound(ByteBufOf("$")));
            Assert.False(this.channel.WriteInbound(ByteBufOf(Convert.ToString(content.Length))));
            Assert.False(this.channel.WriteInbound(ByteBufOf("\r\n")));
            Assert.False(this.channel.WriteInbound(ByteBufOf(Buf1)));
            Assert.False(this.channel.WriteInbound(ByteBufOf(Buf2)));
            Assert.True(this.channel.WriteInbound(ByteBufOf("\r\n")));

            var msg = this.channel.ReadInbound <FullBulkStringRedisMessage>();

            Assert.Equal(content, BytesOf(msg.Content));

            ReferenceCountUtil.Release(msg);
        }
Beispiel #5
0
        public override void ChannelRead(IChannelHandlerContext context, object msg)
        {
            Contract.Requires(context != null);
            var channel = context.Channel;
            var session = _appSessionContainer.Get(channel.Id.ToString());

            if (session != null)
            {
                session.LastAccessTime = DateTime.Now;
            }

            bool release = true;

            try
            {
                if (msg is IPacket packet)
                {
                    _logger.LogInformation($"The msg {msg} from {channel} has been read.");
                    var requestContext = new RequestContext()
                    {
                        AppSession = session, Request = packet
                    };
                    _messageRouter.Route(requestContext);
                }
                else
                {
                    _logger.LogInformation($"The msg {msg} is not type of IMessage.");
                    release = false;
                    context.FireChannelRead(msg);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"ChannelRead error", ex);
            }
            finally
            {
                if (_autoRelease && release)
                {
                    ReferenceCountUtil.Release(msg);
                }
            }
        }
Beispiel #6
0
        static object SafeDuplicate(FABMessage message)
        {
            //AbstractByteBuffer buffer = new AbstractByteBuffer(message.DataLength);
            var buffer = message.Data as IByteBuffer;

            if (buffer != null)
            {
                return(buffer.Duplicate().Retain());
            }

            var byteBufferHolder = message.Data as IByteBufferHolder;

            if (byteBufferHolder != null)
            {
                return(byteBufferHolder.Duplicate().Retain());
            }

            return(ReferenceCountUtil.Retain(message));
        }
Beispiel #7
0
        public Task HandshakeAsync(IChannel channel, IHttpRequest req, HttpHeaders responseHeaders)
        {
            if (req is IFullHttpRequest request)
            {
                return(this.HandshakeAsync(channel, request, responseHeaders));
            }
            if (Logger.DebugEnabled)
            {
                Logger.Debug("{} WebSocket version {} server handshake", channel, this.version);
            }
            IChannelPipeline       p   = channel.Pipeline;
            IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>();

            if (ctx == null)
            {
                // this means the user use a HttpServerCodec
                ctx = p.Context <HttpServerCodec>();
                if (ctx == null)
                {
                    return(TaskEx.FromException(new InvalidOperationException("No HttpDecoder and no HttpServerCodec in the pipeline")));
                }
            }

            // Add aggregator and ensure we feed the HttpRequest so it is aggregated. A limit o 8192 should be more then
            // enough for the websockets handshake payload.
            //
            // TODO: Make handshake work without HttpObjectAggregator at all.
            string aggregatorName = "httpAggregator";

            p.AddAfter(ctx.Name, aggregatorName, new HttpObjectAggregator(8192));
            var completion = new TaskCompletionSource();

            p.AddAfter(aggregatorName, "handshaker", new Handshaker(this, channel, responseHeaders, completion));
            try
            {
                ctx.FireChannelRead(ReferenceCountUtil.Retain(req));
            }
            catch (Exception cause)
            {
                completion.TrySetException(cause);
            }
            return(completion.Task);
        }
Beispiel #8
0
        public void UnsupportedVersion()
        {
            var ch = new EmbeddedChannel();

            WebSocketServerHandshakerFactory.SendUnsupportedVersionResponse(ch);
            ch.RunPendingTasks();
            var response = ch.ReadOutbound <IFullHttpResponse>();

            Assert.NotNull(response);

            Assert.Equal(HttpResponseStatus.UpgradeRequired, response.Status);
            Assert.True(response.Headers.TryGet(HttpHeaderNames.SecWebsocketVersion, out ICharSequence value));
            Assert.Equal(WebSocketVersion.V13.ToHttpHeaderValue(), value);
            Assert.True(HttpUtil.IsContentLengthSet(response));
            Assert.Equal(0, HttpUtil.GetContentLength(response));

            ReferenceCountUtil.Release(response);
            Assert.False(ch.Finish());
        }
Beispiel #9
0
        /// <summary>
        /// Compose <paramref name="cumulation"/> and <paramref name="next"/> into a new <see cref="CompositeByteBuffer"/>.
        /// </summary>
        /// <param name="alloc"></param>
        /// <param name="cumulation"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        protected IByteBuffer ComposeIntoComposite(IByteBufferAllocator alloc, IByteBuffer cumulation, IByteBuffer next)
        {
            // Create a composite buffer to accumulate this pair and potentially all the buffers
            // in the queue. Using +2 as we have already dequeued current and next.
            var composite = alloc.CompositeBuffer(Size() + 2);

            try
            {
                _ = composite.AddComponent(true, cumulation);
                _ = composite.AddComponent(true, next);
            }
            catch (Exception)
            {
                _ = composite.Release();
                ReferenceCountUtil.SafeRelease(next);
                throw;
            }
            return(composite);
        }
Beispiel #10
0
        public void ShortCircuitWithoutConnectionShouldStayOpen()
        {
            CorsConfig config = CorsConfigBuilder.ForOrigin((AsciiString)"http://localhost:8080")
                                .ShortCircuit().Build();
            var channel = new EmbeddedChannel(new CorsHandler(config));
            IFullHttpRequest request = CreateHttpRequest(HttpMethod.Get);

            request.Headers.Set(HttpHeaderNames.Origin, (AsciiString)"http://localhost:8888");

            Assert.False(channel.WriteInbound(request));
            var response = channel.ReadOutbound <IHttpResponse>();

            Assert.True(HttpUtil.IsKeepAlive(response));

            Assert.True(channel.IsOpen);
            Assert.Equal(HttpResponseStatus.Forbidden, response.Status);
            Assert.True(ReferenceCountUtil.Release(response));
            Assert.False(channel.Finish());
        }
        /// <summary>
        /// Performs the opening handshake
        /// When call this method you <c>MUST NOT</c> retain the <see cref="IHttpRequest"/> which is passed in.
        /// </summary>
        /// <param name="channel">Channel</param>
        /// <param name="req">HTTP Request</param>
        /// <param name="responseHeaders">Extra headers to add to the handshake response or <code>null</code> if no extra headers should be added</param>
        /// <returns></returns>
        public Task HandshakeAsync(IChannel channel, IHttpRequest req, HttpHeaders responseHeaders)
        {
            if (req is IFullHttpRequest request)
            {
                return(HandshakeAsync(channel, request, responseHeaders));
            }
            if (Logger.DebugEnabled)
            {
                Logger.WebSocketVersionServerHandshake(channel, _version);
            }
            IChannelPipeline       p   = channel.Pipeline;
            IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>();

            if (ctx is null)
            {
                // this means the user use an HttpServerCodec
                ctx = p.Context <HttpServerCodec>();
                if (ctx is null)
                {
                    return(ThrowHelper.ThrowInvalidOperationException_NoHttpDecoderAndServerCodec());
                }
            }

            // Add aggregator and ensure we feed the HttpRequest so it is aggregated. A limit o 8192 should be more then
            // enough for the websockets handshake payload.
            //
            // TODO: Make handshake work without HttpObjectAggregator at all.
            string aggregatorName = "httpAggregator";

            _ = p.AddAfter(ctx.Name, aggregatorName, new HttpObjectAggregator(8192));
            var completion = channel.NewPromise();

            _ = p.AddAfter(aggregatorName, "handshaker", new Handshaker(this, channel, responseHeaders, completion));
            try
            {
                _ = ctx.FireChannelRead(ReferenceCountUtil.Retain(req));
            }
            catch (Exception cause)
            {
                _ = completion.TrySetException(cause);
            }
            return(completion.Task);
        }
Beispiel #12
0
        public void TooManyResponses()
        {
            var ch = new EmbeddedChannel(new HttpContentCompressor());

            ch.WriteInbound(NewRequest());

            ch.WriteOutbound(new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.OK, Unpooled.Empty));

            try
            {
                ch.WriteOutbound(new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.OK, Unpooled.Empty));
                Assert.True(false, "Should not get here, expecting exception thrown");
            }
            catch (AggregateException e)
            {
                Assert.Single(e.InnerExceptions);
                Assert.IsType <EncoderException>(e.InnerExceptions[0]);
                Exception exception = e.InnerExceptions[0];
                Assert.IsType <InvalidOperationException>(exception.InnerException);
            }

            Assert.True(ch.Finish());

            for (;;)
            {
                var message = ch.ReadOutbound <object>();
                if (message == null)
                {
                    break;
                }
                ReferenceCountUtil.Release(message);
            }
            for (;;)
            {
                var message = ch.ReadInbound <object>();
                if (message == null)
                {
                    break;
                }
                ReferenceCountUtil.Release(message);
            }
        }
Beispiel #13
0
        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 e)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new DecoderException(e);
            }
            finally
            {
                int size = output.Count;
                for (int i = 0; i < size; i++)
                {
                    context.FireChannelRead(output[i]);
                }
                output.Return();
            }
            base.ChannelRead(context, message);
        }
        public override void channelRead(ChannelHandlerContext ctx, Object msg)
        {
//			CodecOutputList outBuffers = CodecOutputList.newInstance();

            try
            {
                if (acceptInboundMessage(msg))
                {
                    I cast = (I)msg;

                    try
                    {
//						decode(ctx, cast, outBuffers);
                    }
                    finally
                    {
                        ReferenceCountUtil.release(cast);
                    }
                }
                else
                {
//					outBuffers.add(msg);
                }
            }
            catch (DecoderException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new DecoderException("channelRead", e);
            }
            finally
            {
//              int size = outBuffers.size();
//              for (int i = 0; i < size; i++)
//              {
//                  ctx.fireChannelRead(outBuffers.getUnsafe(i));
//              }
//              outBuffers.recycle();
            }
        }
Beispiel #15
0
        public Task WriteAndFlushAsync(object message, IChannelMatcher matcher, bool voidPromise)
        {
            if (message is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.message);
            }
            if (matcher is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.matcher);
            }

            Task result;

            if (voidPromise)
            {
                foreach (IChannel c in _nonServerChannels.Values)
                {
                    if (matcher.Matches(c))
                    {
                        _ = c.WriteAndFlushAsync(SafeDuplicate(message), c.VoidPromise());
                    }
                }

                result = TaskUtil.Completed;
            }
            else
            {
                var futures = new Dictionary <IChannel, Task>(_nonServerChannels.Count, ChannelComparer.Default);
                foreach (IChannel c in _nonServerChannels.Values)
                {
                    if (matcher.Matches(c))
                    {
                        futures.Add(c, c.WriteAndFlushAsync(SafeDuplicate(message)));
                    }
                }

                result = new DefaultChannelGroupCompletionSource(this, futures /*, this.executor*/).Task;
            }

            _ = ReferenceCountUtil.Release(message);
            return(result);
        }
        public DefaultHttp2FrameWriterTest()
        {
            _http2HeadersEncoder = new DefaultHttp2HeadersEncoder(
                NeverSensitiveDetector.Instance, new HpackEncoder(false, 16, 0));

            _frameWriter = new DefaultHttp2FrameWriter(new DefaultHttp2HeadersEncoder(
                                                           NeverSensitiveDetector.Instance, new HpackEncoder(false, 16, 0)));

            _outbound = Unpooled.Buffer();

            _expectedOutbound = Unpooled.Empty;

            _promise = new TaskCompletionSource();

            _channel = new Mock <IChannel>();

            Task localAnswer(object msg)
            {
                if (msg is IByteBuffer buf)
                {
                    _outbound.WriteBytes(buf);
                }
                ReferenceCountUtil.Release(msg);
                return(TaskUtil.Completed);
            }

            Task localAnswer0(object msg, IPromise promise)
            {
                if (msg is IByteBuffer buf)
                {
                    _outbound.WriteBytes(buf);
                }
                ReferenceCountUtil.Release(msg);
                return(TaskUtil.Completed);
            }

            _ctx = new Mock <IChannelHandlerContext>();
            _ctx.Setup(x => x.WriteAsync(It.IsAny <object>())).Returns <object>(localAnswer);
            _ctx.Setup(x => x.WriteAsync(It.IsAny <object>(), It.IsAny <IPromise>())).Returns <object, IPromise>(localAnswer0);
            _ctx.Setup(x => x.Allocator).Returns(UnpooledByteBufferAllocator.Default);
            _ctx.Setup(x => x.Channel).Returns(_channel.Object);
        }
Beispiel #17
0
        public void DecodeWithoutStrip()
        {
            EmbeddedChannel ch = new EmbeddedChannel(new LineBasedFrameDecoder(8192, false, false));

            ch.WriteInbound(Unpooled.CopiedBuffer("first\r\nsecond\nthird", Encoding.ASCII));

            var buf = ch.ReadInbound <IByteBuffer>();

            Assert.Equal("first\r\n", buf.ToString(Encoding.ASCII));

            var buf2 = ch.ReadInbound <IByteBuffer>();

            Assert.Equal("second\n", buf2.ToString(Encoding.ASCII));
            Assert.Null(ch.ReadInbound <IByteBuffer>());
            ch.Finish();
            ReferenceCountUtil.Release(ch.ReadInbound <IByteBuffer>());

            buf.Release();
            buf2.Release();
        }
Beispiel #18
0
        async void RetransmitPublishMessage(IChannelHandlerContext context, MessageWithFeedback messageWithFeedback, AckPendingMessageState messageInfo)
        {
            PublishPacket packet = null;

            try
            {
                using (IMessage message = messageWithFeedback.Message)
                {
                    message.Properties[TemplateParameters.DeviceIdTemplateParam] = this.DeviceId;
                    packet = Util.ComposePublishPacket(context, message, messageInfo.QualityOfService, context.Channel.Allocator);
                    messageInfo.ResetMessage(message, messageWithFeedback.FeedbackChannel);
                    await this.publishPubAckProcessor.RetransmitAsync(context, packet, messageInfo);
                }
            }
            catch (Exception ex)
            {
                ReferenceCountUtil.SafeRelease(packet);
                ShutdownOnError(context, "<- PUBLISH (retransmission)", ex);
            }
        }
Beispiel #19
0
            public int Cancel()
            {
                if (!this.Cancelled)
                {
                    this.Cancelled = true;
                    int pSize = this.PendingSize;

                    // release message and replace with an empty buffer
                    ReferenceCountUtil.SafeRelease(this.Message);
                    this.Message = Unpooled.Empty;

                    this.PendingSize = 0;
                    this.Total       = 0;
                    this.Progress    = 0;
                    this.Buffers     = null;
                    this.Buffer      = null;
                    return(pSize);
                }
                return(0);
            }
        IByteBuffer CreateNewDirectBuffer(IByteBuffer buffer)
        {
            Contract.Requires(buffer != null);

            int readableBytes = buffer.ReadableBytes;

            if (readableBytes == 0)
            {
                ReferenceCountUtil.SafeRelease(buffer);
                return(Unpooled.Empty);
            }

            // Composite
            IByteBuffer data = this.Allocator.Buffer(readableBytes);

            data.WriteBytes(buffer, buffer.ReaderIndex, readableBytes);
            ReferenceCountUtil.SafeRelease(buffer);

            return(data);
        }
Beispiel #21
0
        /// <summary>
        /// Remove a pending write operation and fail it with the given <see cref="Exception"/>. The message will be
        /// released via <see cref="ReferenceCountUtil.SafeRelease(object)"/>.
        /// </summary>
        /// <param name="cause">The <see cref="Exception"/> to fail with.</param>
        public void RemoveAndFail(Exception cause)
        {
            Debug.Assert(_ctx.Executor.InEventLoop);
            if (cause is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.cause);
            }

            PendingWrite write = _head;

            if (write is null)
            {
                return;
            }
            ReferenceCountUtil.SafeRelease(write.Msg);
            IPromise promise = write.Promise;

            Util.SafeSetFailure(promise, cause, Logger);
            Recycle(write, true);
        }
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            if (message is IHttpRequest req && HttpUtil.Is100ContinueExpected(req))
            {
                IHttpResponse accept = this.AcceptMessage(req);

                if (accept is null)
                {
                    // the expectation failed so we refuse the request.
                    IHttpResponse rejection = this.RejectResponse(req);
                    _ = ReferenceCountUtil.Release(message);
                    _ = context.WriteAndFlushAsync(rejection).ContinueWith(CloseOnFailureAction, context, TaskContinuationOptions.ExecuteSynchronously);
                    return;
                }

                _ = context.WriteAndFlushAsync(accept).ContinueWith(CloseOnFailureAction, context, TaskContinuationOptions.ExecuteSynchronously);
                _ = req.Headers.Remove(HttpHeaderNames.Expect);
            }
            _ = context.FireChannelRead(message);
        }
            public int Cancel()
            {
                if (!Cancelled)
                {
                    Cancelled = true;
                    int pSize = PendingSize;

                    // release message and replace with an empty buffer
                    ReferenceCountUtil.SafeRelease(Message);
                    Message = Unpooled.Empty;

                    PendingSize = 0;
                    Total       = 0L;
                    Progress    = 0L;
                    Buffers     = null;
                    Buffer      = new ArraySegment <byte>();
                    return(pSize);
                }
                return(0);
            }
Beispiel #24
0
 public override void ChannelRead(IChannelHandlerContext ctx, object message)
 {
     Task.Factory.StartNew(() => {
         if (message is IFullHttpRequest request)
         {
             try
             {
                 this.Process(ctx, request);
             }
             finally
             {
                 ReferenceCountUtil.Release(message);
             }
         }
         else
         {
             ctx.FireChannelRead(message);
         }
     });
 }
Beispiel #25
0
 public static string HexDump(this IByteBuffer buffer)
 {
     try
     {
         string        hexStr = ByteBufferUtil.HexDump(buffer);
         StringBuilder sb     = new StringBuilder();
         for (int i = 0; i < hexStr.Length; i++)
         {
             if (i % 2 == 0)
             {
                 sb.Append(hexStr, i, 2).Append(" ");
             }
         }
         return(sb.ToString().Trim().ToUpper());
     }
     finally
     {
         ReferenceCountUtil.Release(buffer);
     }
 }
Beispiel #26
0
        public void TestRpcCodecWithBody()
        {
            var inputBody = new byte[3] {
                1, 2, 3
            };
            var req = new RequestHeartBeat()
            {
                MilliSeconds = 456
            };
            var rpcMessage = new RpcMessage(req, inputBody);

            var buffer       = rpcCodec.Encode(allocator, rpcMessage) as IByteBuffer;
            var bufferLength = buffer.ReadableBytes;

            var(length, typeName, msg) = rpcCodec.Decode(buffer);

            RpcMessageEqual(rpcMessage, bufferLength, msg as RpcMessage, (int)length);

            ReferenceCountUtil.Release(buffer);
        }
Beispiel #27
0
            public Task WriteAsync(object msg)
            {
                this.AssertEventLoop();

                ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;

                if (outboundBuffer == null)
                {
                    // If the outboundBuffer is null we know the channel was closed and so
                    // need to fail the future right away. If it is not null the handling of the rest
                    // will be done input flush0()
                    // See https://github.com/netty/netty/issues/2362

                    // release message now to prevent resource-leak
                    ReferenceCountUtil.Release(msg);
                    return(TaskEx.FromException(new ClosedChannelException()));
                }

                int size;

                try
                {
                    msg  = this.channel.FilterOutboundMessage(msg);
                    size = this.channel.pipeline.EstimatorHandle.Size(msg);
                    if (size < 0)
                    {
                        size = 0;
                    }
                }
                catch (Exception t)
                {
                    ReferenceCountUtil.Release(msg);

                    return(TaskEx.FromException(t));
                }

                var promise = new TaskCompletionSource();

                outboundBuffer.AddMessage(msg, size, promise);
                return(promise.Task);
            }
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            var output = RecyclableArrayList.Take();

            try
            {
                if (AcceptInboundMessage(message))
                {
                    var cast = (TMessage)message;
                    try
                    {
                        Decode(context, cast, output);
                    }
                    finally
                    {
                        ReferenceCountUtil.Release(cast);
                    }
                }
                else
                {
                    output.Add(message);
                }
            }
            catch (DecoderException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new DecoderException(ex);
            }
            finally
            {
                var size = output.Count;
                for (var i = 0; i < size; i++)
                {
                    context.FireChannelRead(output[i]);
                }
                output.Return();
            }
        }
        /// <summary>
        ///     Closes channel
        /// </summary>
        async void Shutdown(IChannelHandlerContext context, Exception cause)
        {
            if (this.IsInState(StateFlags.Closed))
            {
                return;
            }

            this.lifetimeCancellation.Cancel();
            this.qos2Semaphore?.Dispose();

            try
            {
                this.stateFlags |= StateFlags.Closed; // "or" not to interfere with ongoing logic which has to honor Closed state when it's right time to do (case by case)

                // only decrement connection current counter if the state had connected state in this session
                if (this.IsInState(StateFlags.Connected))
                {
                    PerformanceCounters.ConnectionsCurrent.Decrement();
                }

                Queue <Packet> connectQueue = this.connectPendingQueue;
                if (connectQueue != null)
                {
                    while (connectQueue.Count > 0)
                    {
                        Packet packet = connectQueue.Dequeue();
                        ReferenceCountUtil.Release(packet);
                    }
                }

                PublishPacket will = (cause != null) && this.IsInState(StateFlags.Connected) ? this.willPacket : null;

                await this.CloseServiceConnection(context, cause, will);

                await context.CloseAsync();
            }
            catch (Exception ex)
            {
                CommonEventSource.Log.Warning("Error occurred while shutting down the channel.", ex, this.ChannelId, this.Id);
            }
        }
        public Task InvokeWriteAsync(IChannelHandlerContext ctx, object msg)
        {
            Contract.Requires(msg != null);
            // todo: check for cancellation
            //if (!validatePromise(ctx, promise, false)) {
            //    // promise cancelled
            //    return;
            //}

            if (this.executor.InEventLoop)
            {
                return(ChannelHandlerInvokerUtil.InvokeWriteAsyncNow(ctx, msg));
            }
            else
            {
                var channel = (AbstractChannel)ctx.Channel;
                var promise = new TaskCompletionSource(ctx);

                try
                {
                    int size = channel.EstimatorHandle.Size(msg);
                    if (size > 0)
                    {
                        ChannelOutboundBuffer buffer = channel.Unsafe.OutboundBuffer;
                        // Check for null as it may be set to null if the channel is closed already
                        if (buffer != null)
                        {
                            buffer.IncrementPendingOutboundBytes(size);
                        }
                    }

                    this.executor.Execute(InvokeWriteAsyncAction, promise, msg);
                }
                catch (Exception cause)
                {
                    ReferenceCountUtil.Release(msg); // todo: safe release?
                    promise.TrySetException(cause);
                }
                return(promise.Task);
            }
        }