public Task WriteAndFlushAsync(object message, IPromise promise)
 {
     try
     {
         _channel.WriteInbound(message);
         _channel.RunPendingTasks();
         promise.Complete();
     }
     catch (Exception exc)
     {
         promise.TrySetException(exc);
     }
     return(promise.Task);
 }
예제 #2
0
 public override void ChannelInactive(IChannelHandlerContext context)
 {
     if (_remaining.Decrement() == 0)
     {
         if (_received.ToString().Equals(EXPECTED_PAYLOAD))
         {
             _donePromise.Complete();
         }
         else
         {
             _donePromise.TrySetException(new Exception("Unexpected payload:" + _received));
         }
     }
 }
        public void AggregateWithPartialRead()
        {
            writeQueue.Add(cat, catPromise);
            writeQueue.Add(mouse, NewFutureListener());
            IPromise aggregatePromise = NewPromise();

            Assert.Equal("catm", Dequeue(4, aggregatePromise));
            AssertQueueSize(4, false);
            Assert.False(catPromise.IsSuccess);
            Assert.False(mouseDone);
            aggregatePromise.Complete();
            Assert.True(catPromise.IsSuccess);
            Assert.False(mouseDone);

            aggregatePromise = NewPromise();
            Assert.Equal("ouse", Dequeue(int.MaxValue, aggregatePromise));
            AssertQueueSize(0, true);
            Assert.False(mouseDone);
            aggregatePromise.Complete();
            Assert.True(mouseSuccess);
            Assert.Equal(0, cat.ReferenceCount);
            Assert.Equal(0, mouse.ReferenceCount);
        }
예제 #4
0
            protected override void ChannelRead0(IChannelHandlerContext ctx, string msg)
            {
                if (!s_data[_dataIndex].Equals(msg))
                {
                    _donePromise.TrySetException(new InvalidOperationException("index: " + _dataIndex + " didn't match!"));
                    ctx.CloseAsync();
                    return;
                }

                if (_channel.Parent != null)
                {
                    string delimiter = s_random.Next(0, 1) == 1 ? "\r\n" : "\n";
                    _channel.WriteAsync(msg + delimiter);
                }

                if (++_dataIndex >= s_data.Length)
                {
                    _donePromise.Complete();
                }
            }
        public void Merge()
        {
            writeQueue.Add(cat, catPromise);
            CoalescingBufferQueue otherQueue = new CoalescingBufferQueue(channel);

            otherQueue.Add(mouse, NewFutureListener());
            otherQueue.CopyTo(writeQueue);
            AssertQueueSize(8, false);
            IPromise aggregatePromise = NewPromise();

            Assert.Equal("catmouse", Dequeue(8, aggregatePromise));
            AssertQueueSize(0, true);
            Assert.False(catPromise.IsSuccess);
            Assert.False(mouseDone);
            aggregatePromise.Complete();
            Assert.True(catPromise.IsSuccess);
            Assert.True(mouseSuccess);
            Assert.Equal(0, cat.ReferenceCount);
            Assert.Equal(0, mouse.ReferenceCount);
        }
        public void EmptyBuffersAreCoalesced()
        {
            IByteBuffer empty = Unpooled.Buffer(0, 1);

            AssertQueueSize(0, true);
            writeQueue.Add(cat, catPromise);
            writeQueue.Add(empty, emptyPromise);
            AssertQueueSize(3, false);
            IPromise aggregatePromise = NewPromise();

            Assert.Equal("cat", Dequeue(3, aggregatePromise));
            AssertQueueSize(0, true);
            Assert.False(catPromise.IsSuccess);
            Assert.False(emptyPromise.IsSuccess);
            aggregatePromise.Complete();
            Assert.True(catPromise.IsSuccess);
            Assert.True(emptyPromise.IsSuccess);
            Assert.Equal(0, cat.ReferenceCount);
            Assert.Equal(0, empty.ReferenceCount);
        }
        public void AddFirstPromiseRetained()
        {
            writeQueue.Add(cat, catPromise);
            AssertQueueSize(3, false);
            writeQueue.Add(mouse, NewFutureListener());
            AssertQueueSize(8, false);
            IPromise aggregatePromise = NewPromise();

            Assert.Equal("catmous", Dequeue(7, aggregatePromise));
            IByteBuffer remainder = Unpooled.WrappedBuffer(Encoding.ASCII.GetBytes("mous"));

            writeQueue.AddFirst(remainder, aggregatePromise);
            IPromise aggregatePromise2 = NewPromise();

            Assert.Equal("mouse", Dequeue(5, aggregatePromise2));
            aggregatePromise2.Complete();
            Assert.True(catPromise.IsSuccess);
            Assert.True(mouseSuccess);
            Assert.Equal(0, cat.ReferenceCount);
            Assert.Equal(0, mouse.ReferenceCount);
        }
예제 #8
0
 public override Task WriteRstStreamAsync(IChannelHandlerContext ctx, int streamId, Http2Error errorCode, IPromise promise)
 {
     if (IsExistingStream(streamId))
     {
         return(base.WriteRstStreamAsync(ctx, streamId, errorCode, promise));
     }
     // Since the delegate doesn't know about any buffered streams we have to handle cancellation
     // of the promises and releasing of the ByteBufs here.
     if (_pendingStreams.TryGetValue(streamId, out var stream))
     {
         _ = _pendingStreams.Remove(streamId);
         // Sending a RST_STREAM to a buffered stream will succeed the promise of all frames
         // associated with the stream, as sending a RST_STREAM means that someone "doesn't care"
         // about the stream anymore and thus there is not point in failing the promises and invoking
         // error handling routines.
         stream.Close(null);
         promise.Complete();
     }
     else
     {
         promise.SetException(ThrowHelper.GetConnectionError_StreamDoesNotExist(streamId));
     }
     return(promise.Task);
 }
예제 #9
0
        /// <summary>
        /// Processes all <see cref="IHttp2Frame"/>s. <see cref="IHttp2StreamFrame"/>s may only originate in child streams.
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="msg"></param>
        /// <param name="promise"></param>
        public override void Write(IChannelHandlerContext ctx, object msg, IPromise promise)
        {
            switch (msg)
            {
            case IHttp2DataFrame dataFrame:
                _ = Encoder.WriteDataAsync(ctx, dataFrame.Stream.Id, dataFrame.Content,
                                           dataFrame.Padding, dataFrame.IsEndStream, promise);
                break;

            case IHttp2HeadersFrame headersFrame:
                WriteHeadersFrame(ctx, headersFrame, promise);
                break;

            case IHttp2WindowUpdateFrame windowUpdateFrame:
                var frameStream = windowUpdateFrame.Stream;
                // It is legit to send a WINDOW_UPDATE frame for the connection stream. The parent channel doesn't attempt
                // to set the Http2FrameStream so we assume if it is null the WINDOW_UPDATE is for the connection stream.
                try
                {
                    if (frameStream is null)
                    {
                        IncreaseInitialConnectionWindow(windowUpdateFrame.WindowSizeIncrement);
                    }
                    else
                    {
                        _ = ConsumeBytes(frameStream.Id, windowUpdateFrame.WindowSizeIncrement);
                    }
                    promise.Complete();
                }
                catch (Exception t)
                {
                    promise.SetException(t);
                }
                break;

            case IHttp2ResetFrame rstFrame:
                int id = rstFrame.Stream.Id;
                // Only ever send a reset frame if stream may have existed before as otherwise we may send a RST on a
                // stream in an invalid state and cause a connection error.
                if (Connection.StreamMayHaveExisted(id))
                {
                    _ = Encoder.WriteRstStreamAsync(ctx, id, rstFrame.ErrorCode, promise);
                }
                else
                {
                    _ = ReferenceCountUtil.Release(rstFrame);
                    promise.SetException(GetStreamNeverExistedException(id));
                }
                break;

            case IHttp2PingFrame pingFrame:
                _ = Encoder.WritePingAsync(ctx, pingFrame.Ack, pingFrame.Content, promise);
                break;

            case IHttp2SettingsAckFrame _:
                // In the event of manual SETTINGS ACK is is assumed the encoder will apply the earliest received but not
                // yet ACKed settings.
                _ = Encoder.WriteSettingsAckAsync(ctx, promise);
                break;

            case IHttp2SettingsFrame settingsFrame:
                _ = Encoder.WriteSettingsAsync(ctx, settingsFrame.Settings, promise);
                break;

            case IHttp2GoAwayFrame goAwayFrame:
                WriteGoAwayFrame(ctx, goAwayFrame, promise);
                break;

            case IHttp2UnknownFrame unknownFrame:
                _ = Encoder.WriteFrameAsync(ctx, unknownFrame.FrameType, unknownFrame.Stream.Id,
                                            unknownFrame.Flags, unknownFrame.Content, promise);
                break;

            default:
                if (msg is IHttp2Frame)
                {
                    _ = ReferenceCountUtil.Release(msg);
                    ThrowHelper.ThrowUnsupportedMessageTypeException();
                }
                _ = ctx.WriteAsync(msg, promise);
                break;
            }
        }
예제 #10
0
        protected void CleanupAndTerminate(bool success)
        {
            var thisState = Volatile.Read(ref v_executionState);
            int oldState;

            do
            {
                oldState = thisState;

                if ((uint)oldState >= ST_SHUTTING_DOWN)
                {
                    break;
                }

                thisState = Interlocked.CompareExchange(ref v_executionState, ST_SHUTTING_DOWN, oldState);
            } while (thisState != oldState);

            // Check if confirmShutdown() was called at the end of the loop.
            if (success && (_gracefulShutdownStartTime == PreciseTimeSpan.Zero))
            {
                Logger.BuggyImplementation();
                //$"Buggy {typeof(IEventExecutor).Name} implementation; {typeof(SingleThreadEventExecutor).Name}.ConfirmShutdown() must be called "
                //+ "before run() implementation terminates.");
            }

            try
            {
                // Run all remaining tasks and shutdown hooks. At this point the event loop
                // is in ST_SHUTTING_DOWN state still accepting tasks which is needed for
                // graceful shutdown with quietPeriod.
                while (true)
                {
                    if (ConfirmShutdown())
                    {
                        break;
                    }
                }

                // Now we want to make sure no more tasks can be added from this point. This is
                // achieved by switching the state. Any new tasks beyond this point will be rejected.
                thisState = Volatile.Read(ref v_executionState);
                do
                {
                    oldState = thisState;

                    if ((uint)oldState >= ST_SHUTDOWN)
                    {
                        break;
                    }

                    thisState = Interlocked.CompareExchange(ref v_executionState, ST_SHUTDOWN, oldState);
                } while (thisState != oldState);

                // We have the final set of tasks in the queue now, no more can be added, run all remaining.
                // No need to loop here, this is the final pass.
                _ = ConfirmShutdown();
            }
            finally
            {
                try
                {
                    Cleanup();
                }
                finally
                {
                    _ = Interlocked.Exchange(ref v_executionState, ST_TERMINATED);
                    int numUserTasks = DrainTasks();
                    if ((uint)numUserTasks > 0u && Logger.WarnEnabled)
                    {
                        Logger.AnEventExecutorTerminatedWithNonEmptyTaskQueue(numUserTasks);
                    }

                    //firstRun = true;
                    _terminationCompletionSource.Complete();
                }
            }
        }
        public override Task WriteDataAsync(IChannelHandlerContext ctx, int streamId, IByteBuffer data, int padding, bool endOfStream, IPromise promise)
        {
            IHttp2Stream    stream  = Connection.Stream(streamId);
            EmbeddedChannel channel = stream?.GetProperty <EmbeddedChannel>(_propertyKey);

            if (channel is null)
            {
                // The compressor may be null if no compatible encoding type was found in this stream's headers
                return(base.WriteDataAsync(ctx, streamId, data, padding, endOfStream, promise));
            }

            try
            {
                // The channel will release the buffer after being written
                _ = channel.WriteOutbound(data);
                var buf = NextReadableBuf(channel);
                if (buf is null)
                {
                    if (endOfStream)
                    {
                        if (channel.Finish())
                        {
                            buf = NextReadableBuf(channel);
                        }
                        return(base.WriteDataAsync(ctx, streamId, buf ?? Unpooled.Empty, padding,
                                                   true, promise));
                    }
                    // END_STREAM is not set and the assumption is data is still forthcoming.
                    promise.Complete();
                    return(promise.Task);
                }

                var tasks = new List <Task>();
                while (true)
                {
                    var nextBuf = NextReadableBuf(channel);
                    var compressedEndOfStream = nextBuf is null && endOfStream;
                    if (compressedEndOfStream && channel.Finish())
                    {
                        nextBuf = NextReadableBuf(channel);
                        compressedEndOfStream = nextBuf is null;
                    }

                    var bufPromise = ctx.NewPromise();
                    tasks.Add(bufPromise.Task);
                    _ = base.WriteDataAsync(ctx, streamId, buf, padding, compressedEndOfStream, bufPromise);

                    if (nextBuf is null)
                    {
                        break;
                    }

                    padding = 0; // Padding is only communicated once on the first iteration
                    buf     = nextBuf;
                }
                Task.WhenAll(tasks).LinkOutcome(promise);
            }
            catch (Exception cause)
            {
                _ = promise.TrySetException(cause);
            }
            finally
            {
                if (endOfStream)
                {
                    Cleanup(stream, channel);
                }
            }

            return(promise.Task);
        }
 public override void Write(IChannelHandlerContext ctx, object msg, IPromise promise)
 {
     ReferenceCountUtil.Release(msg);
     promise.Complete();
 }