Пример #1
0
        public void Decode()
        {
            EmbeddedChannel ch = new EmbeddedChannel(
                new DelimiterBasedFrameDecoder(8192, true, Delimiters.LineDelimiter()));

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

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

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

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

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

            ReferenceCountUtil.Release(ch.ReadInbound <IByteBuffer>());

            buf.Release();
            buf2.Release();
        }
Пример #2
0
        public void Clear(DnsSection section)
        {
            object recordOrList = SectionAt(section);

            SetSection(section, null);

            if (recordOrList is IReferenceCounted)
            {
                ((IReferenceCounted)recordOrList).Release();
            }
            else if (recordOrList is IList)
            {
                List <IDnsRecord> list = (List <IDnsRecord>)recordOrList;
                if (list.Count == 0)
                {
                    foreach (var r in list)
                    {
                        ReferenceCountUtil.Release(r);
                    }
                }
            }
        }
Пример #3
0
        public void DecodeSimpleArray()
        {
            Assert.False(this.channel.WriteInbound(ByteBufOf("*3\r\n")));
            Assert.False(this.channel.WriteInbound(ByteBufOf(":1234\r\n")));
            Assert.False(this.channel.WriteInbound(ByteBufOf("+sim")));
            Assert.False(this.channel.WriteInbound(ByteBufOf("ple\r\n-err")));
            Assert.True(this.channel.WriteInbound(ByteBufOf("or\r\n")));

            var msg = this.channel.ReadInbound <IArrayRedisMessage>();
            IList <IRedisMessage> children = msg.Children;

            Assert.Equal(3, msg.Children.Count);

            Assert.IsType <IntegerRedisMessage>(children[0]);
            Assert.Equal(1234L, ((IntegerRedisMessage)children[0]).Value);
            Assert.IsType <SimpleStringRedisMessage>(children[1]);
            Assert.Equal("simple", ((SimpleStringRedisMessage)children[1]).Content);
            Assert.IsType <ErrorRedisMessage>(children[2]);
            Assert.Equal("error", ((ErrorRedisMessage)children[2]).Content);

            ReferenceCountUtil.Release(msg);
        }
Пример #4
0
            public Task WriteAsync(object msg)
            {
                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(ClosedChannelException));
                }

                int size;

                try
                {
                    msg  = this.channel.FilterOutboundMessage(msg);
                    size = this.channel.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);
            }
Пример #5
0
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            IByteBuffer byteBuffer = message as IByteBuffer;

            if (byteBuffer != null)
            {
                if (byteBuffer.HasArray)
                {
                    int    length = byteBuffer.ReadableBytes;
                    byte[] array  = new byte[length];
                    byteBuffer.GetBytes(byteBuffer.ReaderIndex, array);

                    _ms.OnReceiveUpTransmisstion(array);
                }
                else
                {
                    Logger.Log.Info(true, "主节点,没有读到有效的数据");
                }

                ReferenceCountUtil.Release(message);
            }
        }
Пример #6
0
        public void DecodeInlineCommand()
        {
            EmbeddedChannel ch = NewChannel(true);

            try
            {
                Assert.False(ch.WriteInbound(ByteBufOf("P")));
                Assert.False(ch.WriteInbound(ByteBufOf("I")));
                Assert.False(ch.WriteInbound(ByteBufOf("N")));
                Assert.False(ch.WriteInbound(ByteBufOf("G")));
                Assert.True(ch.WriteInbound(ByteBufOf("\r\n")));

                var msg = ch.ReadInbound <InlineCommandRedisMessage>();

                Assert.Equal("PING", msg.Content);
                ReferenceCountUtil.Release(msg);
            }
            finally
            {
                ch.CloseAsync().Wait(TimeSpan.FromSeconds(10));
            }
        }
Пример #7
0
            public void Write(object msg, IPromise promise)
            {
                AssertEventLoop();

                ChannelOutboundBuffer outboundBuffer = Volatile.Read(ref v_outboundBuffer);

                if (outboundBuffer is 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
                    Util.SafeSetFailure(promise, WriteClosedChannelException, Logger);
                    // release message now to prevent resource-leak
                    _ = ReferenceCountUtil.Release(msg);
                    return;
                }

                int size;

                try
                {
                    var ch = _channel;
                    msg  = ch.FilterOutboundMessage(msg);
                    size = ch._pipeline.EstimatorHandle.Size(msg);
                    if ((uint)size > SharedConstants.TooBigOrNegative) // < 0
                    {
                        size = 0;
                    }
                }
                catch (Exception t)
                {
                    Util.SafeSetFailure(promise, t, Logger);
                    _ = ReferenceCountUtil.Release(msg);
                    return;
                }

                outboundBuffer.AddMessage(msg, size, promise);
            }
        public Task InvokeWriteAsync(IChannelHandlerContext ctx, object msg)
        {
            Contract.Requires(msg != null);
            // todo: check for cancellation
            //if (!validatePromise(ctx, promise, false)) {
            //    // promise cancelled
            //    return;
            //}

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

            try
            {
                var size = channel.EstimatorHandle.Size(msg);
                if (size > 0)
                {
                    var 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);
                    }
                }

                Executor.Execute(InvokeWriteAsyncAction, promise, msg);
            }
            catch (Exception cause)
            {
                ReferenceCountUtil.Release(msg);
                promise.TrySetException(cause);
            }
            return(promise.Task);
        }
        /// <summary>
        ///     Closes channel
        /// </summary>
        async void Shutdown(IChannelHandlerContext context, Exception cause)
        {
            if (this.IsInState(StateFlags.Closed))
            {
                return;
            }

            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);
            }
        }
Пример #10
0
        static void AssertHasOutboundMessages(EmbeddedChannel channel, bool hasMessages)
        {
            object o;

            if (hasMessages)
            {
                while (true)
                {
                    o = channel.ReadOutbound <object>();
                    Assert.NotNull(o);
                    ReferenceCountUtil.Release(o);
                    if (o is ILastHttpContent)
                    {
                        break;
                    }
                }
            }
            else
            {
                o = channel.ReadOutbound <object>();
                Assert.Null(o);
            }
        }
Пример #11
0
        /// <summary>
        /// Puts the new work to backlog queue and resume work if worker is idle.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="workItem"></param>
        public virtual void Post(IChannelHandlerContext context, TWork workItem)
        {
            switch (this.State)
            {
            case States.Idle:
                this.backlogQueue.Enqueue(workItem);
                this.State = States.Processing;
                this.StartWorkQueueProcessingAsync(context);
                break;

            case States.Processing:
            case States.FinalProcessing:
                this.backlogQueue.Enqueue(workItem);
                break;

            case States.Aborted:
                ReferenceCountUtil.Release(workItem);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Пример #12
0
        private void Btn_tool_qqencrypt_calc_Click(object sender, EventArgs e)
        {
            string qq   = Frm.txt_tool_qqencrypt_qq.Text;
            string pass = Frm.txt_tool_qqencrypt_pass.Text;
            var    buf  = Unpooled.Buffer();

            try
            {
                buf.WriteBytes(Util.GenerateMD5Byte(pass))
                .WriteInt(0)
                .WriteInt((int)Convert.ToInt64(qq));

                Frm.txt_tool_qqencrypt_ret.Text = buf.Copy().Array.Md5().HexDump();
            }
            catch (Exception ex)
            {
                Toast.Warn(ex.Message);
            }
            finally
            {
                ReferenceCountUtil.Release(buf);
            }
        }
Пример #13
0
        public void DecodeSimpleString(string value)
        {
            var channel = new EmbeddedChannel(
                new RedisDecoder(),
                new RedisBulkStringAggregator(),
                new RedisArrayAggregator());

            Assert.False(channel.WriteInbound("+".Buffer()));
            foreach (char c in value)
            {
                string charValue = new string(new[] { c });
                Assert.False(channel.WriteInbound(charValue.Buffer()));
            }
            Assert.True(channel.WriteInbound("\r\n".Buffer()));

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

            Assert.NotNull(message);
            Assert.Equal(value, message.Content);

            ReferenceCountUtil.Release(message);
            Assert.False(channel.Finish());
        }
        private static void Upgrade0(EmbeddedChannel ch, WebSocketServerHandshaker13 handshaker)
        {
            var req = new DefaultFullHttpRequest(Http11, HttpMethod.Get, "/chat");

            req.Headers.Set(HttpHeaderNames.Host, "server.example.com");
            req.Headers.Set(HttpHeaderNames.Upgrade, HttpHeaderValues.Websocket);
            req.Headers.Set(HttpHeaderNames.Connection, "Upgrade");
            req.Headers.Set(HttpHeaderNames.SecWebsocketKey, "dGhlIHNhbXBsZSBub25jZQ==");
            req.Headers.Set(HttpHeaderNames.SecWebsocketOrigin, "http://example.com");
            req.Headers.Set(HttpHeaderNames.SecWebsocketProtocol, "chat, superchat");
            req.Headers.Set(HttpHeaderNames.SecWebsocketVersion, "13");

            Assert.True(handshaker.HandshakeAsync(ch, req).Wait(TimeSpan.FromSeconds(2)));

            var resBuf = ch.ReadOutbound <IByteBuffer>();

            var ch2 = new EmbeddedChannel(new HttpResponseDecoder());

            ch2.WriteInbound(resBuf);
            var res = ch2.ReadInbound <IHttpResponse>();

            Assert.True(res.Headers.TryGet(HttpHeaderNames.SecWebsocketAccept, out ICharSequence value));
            Assert.Equal("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", value.ToString());
            var subProtocols = handshaker.Subprotocols();

            if (subProtocols.Any())
            {
                Assert.True(res.Headers.TryGet(HttpHeaderNames.SecWebsocketProtocol, out value));
                Assert.Equal("chat", value.ToString());
            }
            else
            {
                Assert.False(res.Headers.TryGet(HttpHeaderNames.SecWebsocketProtocol, out _));
            }
            ReferenceCountUtil.Release(res);
            req.Release();
        }
Пример #15
0
        public void DecodeEmptyBulkString()
        {
            var channel = new EmbeddedChannel(
                new RedisDecoder(),
                new RedisBulkStringAggregator(),
                new RedisArrayAggregator());

            byte[] content = "".Bytes();
            Assert.False(channel.WriteInbound("$".Buffer()));
            Assert.False(channel.WriteInbound(content.Length.ToString().Buffer()));
            Assert.False(channel.WriteInbound("\r\n".Buffer()));
            Assert.False(channel.WriteInbound(content.Buffer()));
            Assert.True(channel.WriteInbound("\r\n".Buffer()));

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

            byte[] output = message.Content.Bytes();

            Assert.Equal(content.Length, output.Length);
            Assert.True(content.SequenceEqual(output));

            ReferenceCountUtil.Release(message);
            Assert.False(channel.Finish());
        }
        public override void ChannelRead(IChannelHandlerContext ctx, object msg)
        {
            bool release = true;

            try
            {
                if (TryAcceptInboundMessage(msg, out I imsg))
                {
                    ChannelRead0(ctx, imsg);
                }
                else
                {
                    release = false;
                    _       = ctx.FireChannelRead(msg);
                }
            }
            finally
            {
                if (_autoRelease && release)
                {
                    _ = ReferenceCountUtil.Release(msg);
                }
            }
        }
        public void Abort()
        {
            switch (this.state)
            {
            case State.Idle:
            case State.Processing:
            case State.FinalProcessing:
                this.state = State.Aborted;

                Queue <T> queue = this.backlogQueue;
                while (queue.Count > 0)
                {
                    T packet = queue.Dequeue();
                    ReferenceCountUtil.Release(packet);
                }
                break;

            case State.Aborted:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Пример #18
0
        public void DecodeNullBulkString()
        {
            Assert.False(this.channel.WriteInbound(ByteBufOf("$")));
            Assert.False(this.channel.WriteInbound(ByteBufOf(Convert.ToString(-1))));
            Assert.True(this.channel.WriteInbound(ByteBufOf("\r\n")));

            Assert.True(this.channel.WriteInbound(ByteBufOf("$")));
            Assert.True(this.channel.WriteInbound(ByteBufOf(Convert.ToString(-1))));
            Assert.True(this.channel.WriteInbound(ByteBufOf("\r\n")));

            var msg1 = this.channel.ReadInbound <IFullBulkStringRedisMessage>();

            Assert.True(msg1.IsNull);
            ReferenceCountUtil.Release(msg1);

            var msg2 = this.channel.ReadInbound <IFullBulkStringRedisMessage>();

            Assert.True(msg2.IsNull);
            ReferenceCountUtil.Release(msg2);

            var msg3 = this.channel.ReadInbound <IFullBulkStringRedisMessage>();

            Assert.Null(msg3);
        }
Пример #19
0
 public void UserEventTriggered(IChannelHandlerContext context, object evt) => ReferenceCountUtil.Release(evt);
        public async Task TestFlowToggleAutoRead()
        {
            IChannel channel = null;
            var      mre     = new ManualResetEventSlim(false);

            var msgRcvLatch1      = new CountdownEvent(1);
            var msgRcvLatch2      = new CountdownEvent(1);
            var msgRcvLatch3      = new CountdownEvent(1);
            var setAutoReadLatch1 = new CountdownEvent(1);
            var setAutoReadLatch2 = new CountdownEvent(1);

            int msgRcvCount               = 0;
            int expectedMsgCount          = 0;
            ChannelHandlerAdapter handler = new TestHandler(
                onActive: ctx =>
            {
                Interlocked.Exchange(ref channel, ctx.Channel);
                mre.Set();
                ctx.FireChannelActive();
            },
                onRead: (ctx, msg) =>
            {
                ReferenceCountUtil.Release(msg);

                // Disable auto reading after each message
                ctx.Channel.Configuration.AutoRead = false;

                if (msgRcvCount++ != expectedMsgCount)
                {
                    return;
                }
                switch (msgRcvCount)
                {
                case 1:
                    msgRcvLatch1.Signal();
                    if (setAutoReadLatch1.Wait(TimeSpan.FromSeconds(1)))
                    {
                        ++expectedMsgCount;
                    }
                    break;

                case 2:
                    msgRcvLatch2.Signal();
                    if (setAutoReadLatch2.Wait(TimeSpan.FromSeconds(1)))
                    {
                        ++expectedMsgCount;
                    }
                    break;

                default:
                    msgRcvLatch3.Signal();
                    break;
                }
            }
                );

            var      flow   = new FlowControlHandler();
            IChannel server = await this.NewServer(true, flow, handler);

            IChannel client = await this.NewClient(server.LocalAddress);

            try
            {
                // The client connection on the server side
                mre.Wait(TimeSpan.FromSeconds(1));
                IChannel peer = Interlocked.Exchange(ref channel, null);

                await client.WriteAndFlushAsync(NewOneMessage());

                // channelRead(1)
                Assert.True(msgRcvLatch1.Wait(TimeSpan.FromSeconds(1)));

                // channelRead(2)
                peer.Configuration.AutoRead = true;
                setAutoReadLatch1.Signal();
                Assert.True(msgRcvLatch1.Wait(TimeSpan.FromSeconds(1)));

                // channelRead(3)
                peer.Configuration.AutoRead = true;
                setAutoReadLatch2.Signal();
                Assert.True(msgRcvLatch3.Wait(TimeSpan.FromSeconds(1)));
                Assert.True(flow.IsQueueEmpty);
            }
            finally
            {
                Task.WhenAll(client.CloseAsync(), server.CloseAsync()).Wait(TimeSpan.FromSeconds(5));
            }
        }
Пример #21
0
 public override void ChannelRead(IChannelHandlerContext context, object message)
 {
     ReferenceCountUtil.Release(message);
 }
Пример #22
0
 public override void ChannelRead(IChannelHandlerContext ctx, object msg)
 {
     //consume this msg
     ReferenceCountUtil.Release(msg);
 }
Пример #23
0
 public void Fail(Exception error)
 {
     _ = ReferenceCountUtil.Release(Message);
     _ = Promise.TrySetException(error);
 }
Пример #24
0
        void DoFlush(IChannelHandlerContext context)
        {
            IChannel channel = context.Channel;

            if (!channel.Active)
            {
                Discard();
                return;
            }

            bool requiresFlush             = true;
            IByteBufferAllocator allocator = context.Allocator;

            while (channel.IsWritable)
            {
                PendingWrite currentWrite = _queue.FirstOrDefault;
                if (currentWrite is null)
                {
                    break;
                }

                if (currentWrite.Promise.IsCompleted)
                {
                    // This might happen e.g. in the case when a write operation
                    // failed, but there're still unconsumed chunks left.
                    // Most chunked input sources would stop generating chunks
                    // and report end of input, but this doesn't work with any
                    // source wrapped in HttpChunkedInput.
                    // Note, that we're not trying to release the message/chunks
                    // as this had to be done already by someone who resolved the
                    // promise (using ChunkedInput.close method).
                    // See https://github.com/netty/netty/issues/8700.
                    _ = _queue.RemoveFromFront();
                    continue;
                }

                object pendingMessage = currentWrite.Message;

                if (pendingMessage is IChunkedInput <T> chunks)
                {
                    bool   endOfInput;
                    bool   suspend;
                    object message = null;

                    try
                    {
                        message    = chunks.ReadChunk(allocator);
                        endOfInput = chunks.IsEndOfInput;
                        if (message is null)
                        {
                            // No need to suspend when reached at the end.
                            suspend = !endOfInput;
                        }
                        else
                        {
                            suspend = false;
                        }
                    }
                    catch (Exception exception)
                    {
                        _ = _queue.RemoveFromFront();

                        if (message is object)
                        {
                            _ = ReferenceCountUtil.Release(message);
                        }

                        CloseInput(chunks);
                        currentWrite.Fail(exception);

                        break;
                    }

                    if (suspend)
                    {
                        // ChunkedInput.nextChunk() returned null and it has
                        // not reached at the end of input. Let's wait until
                        // more chunks arrive. Nothing to write or notify.
                        break;
                    }

                    if (message is null)
                    {
                        // If message is null write an empty ByteBuf.
                        // See https://github.com/netty/netty/issues/1671
                        message = Unpooled.Empty;
                    }

                    // Flush each chunk to conserve memory
                    Task future = context.WriteAndFlushAsync(message);
                    if (endOfInput)
                    {
                        _ = _queue.RemoveFromFront();

                        if (future.IsCompleted)
                        {
                            HandleEndOfInputFuture(future, currentWrite);
                        }
                        else
                        {
                            // Register a listener which will close the input once the write is complete.
                            // This is needed because the Chunk may have some resource bound that can not
                            // be closed before its not written.
                            //
                            // See https://github.com/netty/netty/issues/303
                            _ = future.ContinueWith(LinkOutcomeWhenIsEndOfChunkedInputAction, currentWrite, TaskContinuationOptions.ExecuteSynchronously);
                        }
                    }
                    else
                    {
                        var resume = !channel.IsWritable;
                        if (future.IsCompleted)
                        {
                            HandleFuture(future, this, channel, currentWrite, resume);
                        }
                        else
                        {
                            _ = future.ContinueWith(LinkOutcomeAction,
                                                    Tuple.Create(this, channel, currentWrite, resume), TaskContinuationOptions.ExecuteSynchronously);
                        }
                    }

                    requiresFlush = false;
                }
                else
                {
                    _             = _queue.RemoveFromFront();
                    _             = context.WriteAsync(pendingMessage, currentWrite.Promise);
                    requiresFlush = true;
                }

                if (!channel.Active)
                {
                    Discard(new ClosedChannelException());
                    break;
                }
            }

            if (requiresFlush)
            {
                _ = context.Flush();
            }
        }
Пример #25
0
        void DoFlush(IChannelHandlerContext context)
        {
            IChannel channel = context.Channel;

            if (!channel.Active)
            {
                this.Discard();
                return;
            }

            bool requiresFlush             = true;
            IByteBufferAllocator allocator = context.Allocator;

            while (channel.IsWritable)
            {
                if (this.currentWrite == null)
                {
                    this.currentWrite = this.queue.Count > 0 ? this.queue.Dequeue() : null;
                }

                if (this.currentWrite == null)
                {
                    break;
                }

                PendingWrite current        = this.currentWrite;
                object       pendingMessage = current.Message;

                var chunks = pendingMessage as IChunkedInput <T>;
                if (chunks != null)
                {
                    bool   endOfInput;
                    bool   suspend;
                    object message = null;

                    try
                    {
                        message    = chunks.ReadChunk(allocator);
                        endOfInput = chunks.IsEndOfInput;
                        if (message == null)
                        {
                            // No need to suspend when reached at the end.
                            suspend = !endOfInput;
                        }
                        else
                        {
                            suspend = false;
                        }
                    }
                    catch (Exception exception)
                    {
                        this.currentWrite = null;

                        if (message != null)
                        {
                            ReferenceCountUtil.Release(message);
                        }

                        current.Fail(exception);
                        CloseInput(chunks);

                        break;
                    }

                    if (suspend)
                    {
                        // ChunkedInput.nextChunk() returned null and it has
                        // not reached at the end of input. Let's wait until
                        // more chunks arrive. Nothing to write or notify.
                        break;
                    }

                    if (message == null)
                    {
                        // If message is null write an empty ByteBuf.
                        // See https://github.com/netty/netty/issues/1671
                        message = Unpooled.Empty;
                    }

                    Task future = context.WriteAsync(message);
                    if (endOfInput)
                    {
                        this.currentWrite = null;

                        // Register a listener which will close the input once the write is complete.
                        // This is needed because the Chunk may have some resource bound that can not
                        // be closed before its not written.
                        //
                        // See https://github.com/netty/netty/issues/303
                        future.ContinueWith((_, state) =>
                        {
                            var pendingTask = (PendingWrite)state;
                            CloseInput((IChunkedInput <T>)pendingTask.Message);
                            pendingTask.Success();
                        },
                                            current,
                                            TaskContinuationOptions.ExecuteSynchronously);
                    }
                    else if (channel.IsWritable)
                    {
                        future.ContinueWith((task, state) =>
                        {
                            var pendingTask = (PendingWrite)state;
                            if (task.IsFaulted)
                            {
                                CloseInput((IChunkedInput <T>)pendingTask.Message);
                                pendingTask.Fail(task.Exception);
                            }
                            else
                            {
                                pendingTask.Progress(chunks.Progress, chunks.Length);
                            }
                        },
                                            current,
                                            TaskContinuationOptions.ExecuteSynchronously);
                    }
                    else
                    {
                        future.ContinueWith((task, state) =>
                        {
                            var handler = (ChunkedWriteHandler <T>)state;
                            if (task.IsFaulted)
                            {
                                CloseInput((IChunkedInput <T>)handler.currentWrite.Message);
                                handler.currentWrite.Fail(task.Exception);
                            }
                            else
                            {
                                handler.currentWrite.Progress(chunks.Progress, chunks.Length);
                                if (channel.IsWritable)
                                {
                                    handler.ResumeTransfer();
                                }
                            }
                        },
                                            this,
                                            TaskContinuationOptions.ExecuteSynchronously);
                    }

                    // Flush each chunk to conserve memory
                    context.Flush();
                    requiresFlush = false;
                }
                else
                {
                    context.WriteAsync(pendingMessage)
                    .ContinueWith((task, state) =>
                    {
                        var pendingTask = (PendingWrite)state;
                        if (task.IsFaulted)
                        {
                            pendingTask.Fail(task.Exception);
                        }
                        else
                        {
                            pendingTask.Success();
                        }
                    },
                                  current,
                                  TaskContinuationOptions.ExecuteSynchronously);

                    this.currentWrite = null;
                    requiresFlush     = true;
                }

                if (!channel.Active)
                {
                    this.Discard(new ClosedChannelException());
                    break;
                }
            }

            if (requiresFlush)
            {
                context.Flush();
            }
        }
        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);
        }
        /// <summary>
        /// Handles conversion of <see cref="IHttpMessage"/> and <see cref="IHttpContent"/> to HTTP/2 frames.
        /// </summary>
        public override void Write(IChannelHandlerContext ctx, object msg, IPromise promise)
        {
            var httpMsg    = msg as IHttpMessage;
            var contentMsg = msg as IHttpContent;

            if (httpMsg is null && contentMsg is null)
            {
                _ = ctx.WriteAsync(msg, promise);
                return;
            }

            var release           = true;
            var promiseAggregator = new SimplePromiseAggregator(promise);

            try
            {
                var encoder   = Encoder;
                var endStream = false;
                if (httpMsg is object)
                {
                    // Provide the user the opportunity to specify the streamId
                    _currentStreamId = GetStreamId(httpMsg.Headers);

                    // Convert and write the headers.
                    var http2Headers = HttpConversionUtil.ToHttp2Headers(httpMsg, _validateHeaders);
                    endStream = msg is IFullHttpMessage fullHttpMsg && !fullHttpMsg.Content.IsReadable();
                    WriteHeaders(ctx, encoder, _currentStreamId, httpMsg.Headers, http2Headers, endStream, promiseAggregator);
                }

                if (!endStream && contentMsg is object)
                {
                    var           isLastContent = false;
                    HttpHeaders   trailers      = EmptyHttpHeaders.Default;
                    IHttp2Headers http2Trailers = EmptyHttp2Headers.Instance;
                    if (msg is ILastHttpContent lastContentMsg)
                    {
                        isLastContent = true;

                        // Convert any trailing headers.
                        trailers      = lastContentMsg.TrailingHeaders;
                        http2Trailers = HttpConversionUtil.ToHttp2Headers(trailers, _validateHeaders);
                    }

                    // Write the data
                    var content = contentMsg.Content;
                    endStream = isLastContent && trailers.IsEmpty;
                    _         = encoder.WriteDataAsync(ctx, _currentStreamId, content, 0, endStream, promiseAggregator.NewPromise());
                    release   = false;

                    if (!trailers.IsEmpty)
                    {
                        // Write trailing headers.
                        WriteHeaders(ctx, encoder, _currentStreamId, trailers, http2Trailers, true, promiseAggregator);
                    }
                }
            }
            catch (Exception t)
            {
                OnError(ctx, true, t);
                promiseAggregator.SetException(t);
            }
            finally
            {
                if (release)
                {
                    _ = ReferenceCountUtil.Release(msg);
                }
                _ = promiseAggregator.DoneAllocatingPromises();
            }
        }
Пример #28
0
 static void AssertNotNullAndRelease(object msg)
 {
     Assert.NotNull(msg);
     ReferenceCountUtil.Release(msg);
 }
Пример #29
0
 public void Fail(Exception error)
 {
     ReferenceCountUtil.Release(this.Message);
     this.promise.TrySetException(error);
 }
Пример #30
0
        /// <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();
                    }
                }
            }
        }