public Task WriteAndFlushAsync(object message, IPromise promise) { try { _channel.WriteInbound(message); _channel.RunPendingTasks(); promise.Complete(); } catch (Exception exc) { promise.TrySetException(exc); } return(promise.Task); }
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); }
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); }
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); }
/// <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; } }
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(); }