Ejemplo n.º 1
0
        public async Task ReadWrite_Random_Success(int readSize, int writeSize)
        {
            byte[] testBuffer = new byte[8192];
            Random.Shared.NextBytes(testBuffer);

            await RunClientServer(
                async clientConnection =>
            {
                await using QuicStream clientStream = clientConnection.OpenUnidirectionalStream();

                ReadOnlyMemory <byte> sendBuffer = testBuffer;
                while (sendBuffer.Length != 0)
                {
                    ReadOnlyMemory <byte> chunk = sendBuffer.Slice(0, Math.Min(sendBuffer.Length, writeSize));
                    await clientStream.WriteAsync(chunk);
                    sendBuffer = sendBuffer.Slice(chunk.Length);
                }

                clientStream.Shutdown();
                await clientStream.ShutdownWriteCompleted();
            },
                async serverConnection =>
            {
                await using QuicStream serverStream = await serverConnection.AcceptStreamAsync();

                byte[] receiveBuffer = new byte[testBuffer.Length];
                int totalBytesRead   = 0;

                while (totalBytesRead != receiveBuffer.Length)
                {
                    int bytesRead = await serverStream.ReadAsync(receiveBuffer.AsMemory(totalBytesRead, Math.Min(receiveBuffer.Length - totalBytesRead, readSize)));
                    if (bytesRead == 0)
                    {
                        break;
                    }

                    totalBytesRead += bytesRead;
                }

                Assert.Equal(testBuffer.Length, receiveBuffer.Length);
                Assert.Equal(testBuffer, receiveBuffer);
            });
        }
Ejemplo n.º 2
0
        public async Task BasicTest()
        {
            for (int i = 0; i < 100; i++)
            {
                Task listenTask = Task.Run(async() =>
                {
                    using QuicConnection connection = await DefaultListener.AcceptConnectionAsync();
                    await using QuicStream stream   = await connection.AcceptStreamAsync();

                    byte[] buffer = new byte[s_data.Length];
                    int bytesRead = await stream.ReadAsync(buffer);

                    Assert.Equal(s_data.Length, bytesRead);
                    Assert.True(s_data.Span.SequenceEqual(buffer));

                    await stream.WriteAsync(s_data, endStream: true);
                    await stream.ShutdownWriteCompleted();

                    await connection.CloseAsync(errorCode: 0);
                });

                Task clientTask = Task.Run(async() =>
                {
                    using QuicConnection connection = CreateQuicConnection(DefaultListener.ListenEndPoint);
                    await connection.ConnectAsync();
                    await using QuicStream stream = connection.OpenBidirectionalStream();

                    await stream.WriteAsync(s_data, endStream: true);

                    byte[] memory = new byte[12];
                    int bytesRead = await stream.ReadAsync(memory);

                    Assert.Equal(s_data.Length, bytesRead);
                    // TODO this failed once...
                    Assert.True(s_data.Span.SequenceEqual(memory));
                    await stream.ShutdownWriteCompleted();

                    await connection.CloseAsync(errorCode: 0);
                });

                await(new[] { listenTask, clientTask }).WhenAllOrAnyFailed(millisecondsTimeout: 10000);
            }
        }
Ejemplo n.º 3
0
        private Task EnsureControlStreamAcceptedAsync()
        {
            if (_inboundControlStream != null)
            {
                return(Task.CompletedTask);
            }

            return(EnsureControlStreamAcceptedInternalAsync());

            async Task EnsureControlStreamAcceptedInternalAsync()
            {
                Http3LoopbackStream controlStream;

                while (true)
                {
                    QuicStream quicStream = await _connection.AcceptStreamAsync().ConfigureAwait(false);

                    if (!quicStream.CanWrite)
                    {
                        // control stream accepted
                        controlStream = new Http3LoopbackStream(quicStream);
                        break;
                    }

                    // control streams are unidirectional, so this must be a request stream
                    // keep it for later and wait for another stream
                    _delayedStreams.Enqueue(quicStream);
                }

                long?streamType = await controlStream.ReadIntegerAsync();

                Assert.Equal(Http3LoopbackStream.ControlStream, streamType);

                List <(long settingId, long settingValue)> settings = await controlStream.ReadSettingsAsync();

                (long settingId, long settingValue) = Assert.Single(settings);

                Assert.Equal(Http3LoopbackStream.MaxHeaderListSize, settingId);
                MaxHeaderListSize = settingValue;

                _inboundControlStream = controlStream;
            }
        }
Ejemplo n.º 4
0
        public Req send_on_quic_protocol(string content,int port)
        {
            Req request = new Req();
            int ms = 0;
            int byteNumber = -1;
            request.Content = content;
            //Console.WriteLine("Starting client.");
            QuicClient client = new QuicClient();
            request.timeSended = DateTime.Now.ToLocalTime();
            QuicConnection connection = client.Connect("127.0.0.1", port);   // Connect to peer (Server)

            QuicStream stream_quic = connection.CreateStream(QuickNet.Utilities.StreamType.ClientBidirectional); // Create a data stream

            byte[] messageBytes = null;

            string aaa = JsonConvert.SerializeObject(request);
            messageBytes = System.Text.Encoding.UTF8.GetBytes(aaa);
            //Console.WriteLine("Send 'Hello From Client!'");
            stream_quic.Send(messageBytes);        // Send Data
            //Console.WriteLine("Waiting for message from the server");
            try
            {
                byte[] data = stream_quic.Receive();
                byteNumber = data.Length;
                DateTime timeRecieved = DateTime.Now.ToLocalTime();
                string message = cleanMessage(data);
                // Receive from server
                Req request_back = JsonConvert.DeserializeObject<Req>(message); // Deserialize
                request.timeRecieved = timeRecieved;
                TimeSpan span = request_back.timeRecieved - request_back.timeSended;
                request.number_of_bytes = data.Length;
                //request_back.timeRecieved.mili
                ms = (int)span.TotalMilliseconds;
                request.totalTime = ms;

            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            return request;
        }
Ejemplo n.º 5
0
        static void Main(string[] args)
        {
            Console.WriteLine("Starting client.");
            QuicClient client = new QuicClient();

            Console.WriteLine("Connecting to server.");
            QuicConnection connection = client.Connect("127.0.0.1", 11000);   // Connect to peer (Server)

            Console.WriteLine("Connected");

            QuicStream stream = connection.CreateStream(QuickNet.Utilities.StreamType.ClientBidirectional); // Create a data stream

            Console.WriteLine("Create stream with id: " + stream.StreamId.IntegerValue.ToString());

            Console.WriteLine("Send 'Hello From Client!'");
            stream.Send(Encoding.UTF8.GetBytes("Hello from Client!"));                           // Send Data

            stream = connection.CreateStream(QuickNet.Utilities.StreamType.ClientBidirectional); // Create a data stream
            stream.Send(Encoding.UTF8.GetBytes("Hello from Client2!"));

            Console.WriteLine("Waiting for message from the server");
            try
            {
                byte[] data = stream.Receive();                                   // Receive from server
                Console.WriteLine("Received: " + Encoding.UTF8.GetString(data));
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            try
            {
                byte[] data = stream.Receive();                                   // Receive from server
                Console.WriteLine("Received: " + Encoding.UTF8.GetString(data));
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            Console.ReadKey();
        }
Ejemplo n.º 6
0
        protected override async Task <StreamPair> CreateConnectedStreamsAsync()
        {
            QuicImplementationProvider provider = Provider;
            var listener = new QuicListener(
                provider,
                new IPEndPoint(IPAddress.Loopback, 0),
                GetSslServerAuthenticationOptions());

            byte[] buffer = new byte[1] {
                42
            };
            QuicConnection connection1 = null, connection2 = null;
            QuicStream     stream1 = null, stream2 = null;

            await WhenAllOrAnyFailed(
                Task.Run(async() =>
            {
                connection1 = await listener.AcceptConnectionAsync();
                stream1     = await connection1.AcceptStreamAsync();
                Assert.Equal(1, await stream1.ReadAsync(buffer));
            }),
                Task.Run(async() =>
            {
                connection2 = new QuicConnection(
                    provider,
                    listener.ListenEndPoint,
                    GetSslClientAuthenticationOptions());
                await connection2.ConnectAsync();
                stream2 = connection2.OpenBidirectionalStream();
                // OpenBidirectionalStream only allocates ID. We will force stream opening
                // by Writing there and receiving data on the other side.
                await stream2.WriteAsync(buffer);
            }));

            var result = new StreamPairWithOtherDisposables(stream1, stream2);

            result.Disposables.Add(connection1);
            result.Disposables.Add(connection2);
            result.Disposables.Add(listener);

            return(result);
        }
Ejemplo n.º 7
0
        // RunAsync starts the QuicListener and continually waits for new clients
        public override async Task RunAsync(CancellationToken Token)
        {
            // Start the QuicListener
            QuicListener listener = new QuicListener(this.ExternalPort);

            //QuicListener Listener = new QuicListener(IPAddress.Any, this.ExternalPort);;
            listener.Start();

            // Continually wait for new client
            while (!Token.IsCancellationRequested)
            {
                // Handle the client asynchronously in a new thread
                QuicConnection client = listener.AcceptQuicClient();
                _ = Task.Run(() =>
                {
                    //client.ReceiveTimeout = client.SendTimeout = 0;
                    QuicStream stream = client.CreateStream(QuickNet.Utilities.StreamType.ClientBidirectional);
                    //stream.
                    //stream.ReadTimeout = stream.WriteTimeout = Timeout.Infinite;
                    while (!Token.IsCancellationRequested)
                    {
                        // byte[] data;
                        // Read from the implant
                        string read            = "";
                        client.OnDataReceived += (c) =>
                        {
                            read += Encoding.UTF8.GetString(c.Data);
                        };
                        //string read = Encoding.UTF8.GetString(data);
                        //string read = await Utilities.ReadStreamAsync(stream);
                        // Write to the Covenant server
                        string guid = this.WriteToConnector(read);
                        if (guid != null)
                        {
                            // Track this GUID -> client mapping, for use within the OnReadBridge function

                            Clients.TryAdd(guid, stream);
                        }
                    }
                });
            }
        }
Ejemplo n.º 8
0
        public QuicStream ProcessFrames(List <Frame> frames)
        {
            QuicStream stream = null;

            foreach (Frame frame in frames)
            {
                if (frame.Type == 0x01)
                {
                    OnRstStreamFrame(frame);
                }
                if (frame.Type == 0x04)
                {
                    OnRstStreamFrame(frame);
                }
                if (frame.Type >= 0x08 && frame.Type <= 0x0f)
                {
                    stream = OnStreamFrame(frame);
                }
                if (frame.Type == 0x10)
                {
                    OnMaxDataFrame(frame);
                }
                if (frame.Type == 0x11)
                {
                    OnMaxStreamDataFrame(frame);
                }
                if (frame.Type >= 0x12 && frame.Type <= 0x13)
                {
                    OnMaxStreamFrame(frame);
                }
                if (frame.Type == 0x14)
                {
                    OnDataBlockedFrame(frame);
                }
                if (frame.Type >= 0x1c && frame.Type <= 0x1d)
                {
                    OnConnectionCloseFrame(frame);
                }
            }

            return(stream);
        }
Ejemplo n.º 9
0
        public async Task Dispose_WithOpenLocalStream_LocalStreamFailsWithQuicOperationAbortedException(int writesBeforeClose)
        {
            if (IsMockProvider)
            {
                return;
            }

            // Set a short idle timeout so that after we dispose the connection, the peer will discover the connection is dead before too long.
            QuicListenerOptions listenerOptions = CreateQuicListenerOptions();

            listenerOptions.IdleTimeout = TimeSpan.FromSeconds(1);

            using var sync = new SemaphoreSlim(0);

            await RunClientServer(
                async clientConnection =>
            {
                using QuicStream clientStream = await clientConnection.OpenBidirectionalStreamAsync();
                await DoWrites(clientStream, writesBeforeClose);

                // Wait for peer to receive data
                await sync.WaitAsync();

                clientConnection.Dispose();

                await Assert.ThrowsAsync <QuicOperationAbortedException>(async() => await clientStream.ReadAsync(new byte[1]));
                await Assert.ThrowsAsync <QuicOperationAbortedException>(async() => await clientStream.WriteAsync(new byte[1]));
            },
                async serverConnection =>
            {
                using QuicStream serverStream = await serverConnection.AcceptStreamAsync();
                await DoReads(serverStream, writesBeforeClose);

                sync.Release();

                // The client has done an abortive shutdown of the connection, which means we are not notified that the connection has closed.
                // But the connection idle timeout should kick in and eventually we will get exceptions.
                await Assert.ThrowsAsync <QuicConnectionAbortedException>(async() => await serverStream.ReadAsync(new byte[1]));
                await Assert.ThrowsAsync <QuicConnectionAbortedException>(async() => await serverStream.WriteAsync(new byte[1]));
            }, listenerOptions : listenerOptions);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Accepts unidirectional streams (control, QPack, ...) from the server.
        /// </summary>
        private async Task AcceptStreamsAsync()
        {
            try
            {
                while (true)
                {
                    ValueTask <QuicStream> streamTask;

                    lock (SyncObj)
                    {
                        if (ShuttingDown)
                        {
                            return;
                        }

                        // No cancellation token is needed here; we expect the operation to cancel itself when _connection is disposed.
                        streamTask = _connection !.AcceptInboundStreamAsync(CancellationToken.None);
                    }

                    QuicStream stream = await streamTask.ConfigureAwait(false);

                    // This process is cleaned up when _connection is disposed, and errors are observed via Abort().
                    _ = ProcessServerStreamAsync(stream);
                }
            }
            catch (QuicException ex) when(ex.QuicError == QuicError.OperationAborted)
            {
                // Shutdown initiated by us, no need to abort.
            }
            catch (QuicException ex) when(ex.QuicError == QuicError.ConnectionAborted)
            {
                Debug.Assert(ex.ApplicationErrorCode.HasValue);
                Http3ErrorCode code = (Http3ErrorCode)ex.ApplicationErrorCode.Value;

                Abort(HttpProtocolException.CreateHttp3ConnectionException(code, SR.net_http_http3_connection_close));
            }
            catch (Exception ex)
            {
                Abort(ex);
            }
        }
Ejemplo n.º 11
0
        public void Start(bool isBlocking, IPEndPoint requiredLocalEP)
        {
            ValidateListenerDisposed();

            QuicConnection serverConnection = AsyncUtil.RunSync <QuicConnection>(()
                                                                                 => this.listener.AcceptConnectionAsync().AsTask());

            QuicStream serverStream = AsyncUtil.RunSync <QuicStream>(()
                                                                     => serverConnection.AcceptStreamAsync().AsTask());

            if (this.lspHooked)
            {
                IPEndPoint actualListenedLocalEP = this.listener.ListenEndPoint as IPEndPoint;

                LspConsole.Instance.InterceptTraffic(this.server.SocketConfig.Type, isBlocking, requiredLocalEP, actualListenedLocalEP);
            }

            this.lspHookedLocalEP = requiredLocalEP;

            this.thread.Start();
        }
Ejemplo n.º 12
0
    public void Initialize(QuicStream stream)
    {
        Debug.Assert(_stream == null);

        _stream = stream;

        _streamClosedTokenSource = null;
        _onClosedRegistrations?.Clear();

        InitializeFeatures();

        CanRead             = _stream.CanRead;
        CanWrite            = _stream.CanWrite;
        _error              = null;
        StreamId            = _stream.Id;
        PoolExpirationTicks = 0;

        Transport   = _originalTransport;
        Application = _originalApplication;

        _transportPipeReader.Reset();
        _transportPipeWriter.Reset();

        _connectionId        = null;
        _shutdownReason      = null;
        _writeAbortException = null;
        _streamClosed        = false;
        _serverAborted       = false;
        _clientAbort         = false;

        // Only reset pipes if the stream has been reused.
        if (CanReuse)
        {
            _inputPipe.Reset();
            _outputPipe.Reset();
        }

        CanReuse = false;
    }
Ejemplo n.º 13
0
        private Task <HttpResponseMessage> SendWithoutWaitingAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            QuicStream         quicStream = null;
            Http3RequestStream stream;

            try
            {
                // TODO: do less work in this lock, try to get rid of goto.
                lock (SyncObj)
                {
                    if (_connection == null)
                    {
                        goto retryRequest;
                    }

                    quicStream = _connection.OpenBidirectionalStream();
                    if (_lastProcessedStreamId != -1 && quicStream.StreamId > _lastProcessedStreamId)
                    {
                        goto retryRequest;
                    }

                    stream = new Http3RequestStream(request, this, quicStream);
                    _activeRequests.Add(quicStream.StreamId, stream);
                }

                return(stream.SendAsync(cancellationToken));
            }
            catch (QuicConnectionAbortedException ex)
            {
                // This will happen if we aborted _connection somewhere.
                Abort(ex);
            }

retryRequest:
            // We lost a race between GOAWAY/abort and our pool sending the request to this connection.
            quicStream?.Dispose();
            return(Task.FromException <HttpResponseMessage>(new HttpRequestException(SR.net_http_request_aborted, null, RequestRetryType.RetryOnSameOrNextProxy)));
        }
Ejemplo n.º 14
0
        public async Task CloseAsync_WithOpenStream_LocalAndPeerStreamsFailWithQuicOperationAbortedException(int writesBeforeClose)
        {
            if (IsMockProvider)
            {
                return;
            }

            using var sync = new SemaphoreSlim(0);

            await RunClientServer(
                async clientConnection =>
            {
                using QuicStream clientStream = await clientConnection.OpenBidirectionalStreamAsync();
                await DoWrites(clientStream, writesBeforeClose);

                // Wait for peer to receive data
                await sync.WaitAsync();

                await clientConnection.CloseAsync(ExpectedErrorCode);

                await Assert.ThrowsAsync <QuicOperationAbortedException>(async() => await clientStream.ReadAsync(new byte[1]));
                await Assert.ThrowsAsync <QuicOperationAbortedException>(async() => await clientStream.WriteAsync(new byte[1]));
            },
                async serverConnection =>
            {
                using QuicStream serverStream = await serverConnection.AcceptStreamAsync();
                await DoReads(serverStream, writesBeforeClose);

                sync.Release();

                // Since the peer did the abort, we should receive the abort error code in the exception.
                QuicConnectionAbortedException ex;
                ex = await Assert.ThrowsAsync <QuicConnectionAbortedException>(async() => await serverStream.ReadAsync(new byte[1]));
                Assert.Equal(ExpectedErrorCode, ex.ErrorCode);
                ex = await Assert.ThrowsAsync <QuicConnectionAbortedException>(async() => await serverStream.WriteAsync(new byte[1]));
                Assert.Equal(ExpectedErrorCode, ex.ErrorCode);
            });
        }
Ejemplo n.º 15
0
        public static async Task HandleServerConnection(QuicConnection connection, CancellationToken token)
        {
            try
            {
                QuicStream stream = await connection.AcceptStreamAsync(token);

                byte[] buffer = new byte[4 * 1024];

                int read;
                while ((read = await stream.ReadAsync(buffer, token)) > 0)
                {
                    // echo the read data back
                    await stream.WriteAsync(buffer, 0, read, token);

                    await stream.FlushAsync(token);
                }
            }
            finally
            {
                // gracefully close the connection with 0 error code
                await connection.CloseAsync(0);
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Called when shutting down, this checks for when shutdown is complete (no more active requests) and does actual disposal.
        /// </summary>
        /// <remarks>Requires <see cref="SyncObj"/> to be locked.</remarks>
        private void CheckForShutdown()
        {
            Debug.Assert(Monitor.IsEntered(SyncObj));
            Debug.Assert(ShuttingDown);

            if (_activeRequests.Count != 0)
            {
                return;
            }

            if (_clientControl != null)
            {
                _clientControl.Dispose();
                _clientControl = null;
            }

            if (_connection != null)
            {
                _connection.CloseAsync((long)Http3ErrorCode.NoError).GetAwaiter().GetResult(); // TODO: async...
                _connection.Dispose();
                _connection = null;
            }
        }
Ejemplo n.º 17
0
 private static async Task ServerQuicStreamTask(QuicConnection connection, QuicStream stream)
 {
     try
     {
         if (!await ServerStreamTask(stream).ConfigureAwait(false))
         {
             await connection.CloseAsync(1).ConfigureAwait(false);
         }
     }
     catch (QuicStreamAbortedException e) when(e.ErrorCode == 0)
     {
     }
     catch (QuicConnectionAbortedException)
     {
     }
     catch (OperationCanceledException)
     {
     }
     finally
     {
         await stream.DisposeAsync().ConfigureAwait(false);
     }
 }
Ejemplo n.º 18
0
        private void OnStreamFrame(Frame frame)
        {
            StreamFrame sf = (StreamFrame)frame;

            if (_streams.ContainsKey(sf.StreamId.Value) == false)
            {
                QuicStream stream = new QuicStream(this, sf.ConvertedStreamId);
                stream.ProcessData(sf);

                if ((UInt64)_streams.Count < MaxStreams)
                {
                    _streams.Add(sf.StreamId.Value, stream);
                }
                else
                {
                    SendMaximumStreamReachedError();
                }
            }
            else
            {
                QuicStream stream = _streams[sf.StreamId];
                stream.ProcessData(sf);
            }
        }
Ejemplo n.º 19
0
        public async Task BasicTest()
        {
            using (QuicListener listener = new QuicListener(QuicImplementationProviders.Mock, new IPEndPoint(IPAddress.Loopback, 0), sslServerAuthenticationOptions: null))
            {
                listener.Start();
                IPEndPoint listenEndPoint = listener.ListenEndPoint;

                await Task.WhenAll(
                    Task.Run(async() =>
                {
                    // Client code
                    using (QuicConnection connection = new QuicConnection(QuicImplementationProviders.Mock, listenEndPoint, sslClientAuthenticationOptions: null))
                    {
                        await connection.ConnectAsync();
                        using (QuicStream stream = connection.OpenBidirectionalStream())
                        {
                            await stream.WriteAsync(s_data);
                        }
                    }
                }),
                    Task.Run(async() =>
                {
                    // Server code
                    using (QuicConnection connection = await listener.AcceptConnectionAsync())
                    {
                        using (QuicStream stream = await connection.AcceptStreamAsync())
                        {
                            byte[] buffer = new byte[s_data.Length];
                            int bytesRead = await stream.ReadAsync(buffer);
                            Assert.Equal(s_data.Length, bytesRead);
                            Assert.True(s_data.Span.SequenceEqual(buffer));
                        }
                    }
                }));
            }
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Reads the server's control stream.
        /// </summary>
        private async Task ProcessServerControlStreamAsync(QuicStream stream, ArrayBuffer buffer)
        {
            (Http3FrameType? frameType, long payloadLength) = await ReadFrameEnvelopeAsync().ConfigureAwait(false);

            if (frameType == null)
            {
                // Connection closed prematurely, expected SETTINGS frame.
                throw new Http3ConnectionException(Http3ErrorCode.ClosedCriticalStream);
            }

            if (frameType != Http3FrameType.Settings)
            {
                // Expected SETTINGS as first frame of control stream.
                throw new Http3ConnectionException(Http3ErrorCode.MissingSettings);
            }

            await ProcessSettingsFrameAsync(payloadLength).ConfigureAwait(false);

            while (true)
            {
                (frameType, payloadLength) = await ReadFrameEnvelopeAsync().ConfigureAwait(false);

                switch (frameType)
                {
                case Http3FrameType.GoAway:
                    await ProcessGoAwayFameAsync(payloadLength).ConfigureAwait(false);

                    break;

                case Http3FrameType.Settings:
                    // Only a single SETTINGS frame is supported.
                    throw new Http3ConnectionException(Http3ErrorCode.UnexpectedFrame);

                case Http3FrameType.Headers:
                case Http3FrameType.Data:
                case Http3FrameType.MaxPushId:
                case Http3FrameType.DuplicatePush:
                    // Servers should not send these frames to a control stream.
                    throw new Http3ConnectionException(Http3ErrorCode.UnexpectedFrame);

                case Http3FrameType.PushPromise:
                case Http3FrameType.CancelPush:
                    // Because we haven't sent any MAX_PUSH_ID frame, it is invalid to receive any push-related frames as they will all reference a too-large ID.
                    throw new Http3ConnectionException(Http3ErrorCode.IdError);

                case null:
                    // End of stream reached. If we're shutting down, stop looping. Otherwise, this is an error (this stream should not be closed for life of connection).
                    bool shuttingDown;
                    lock (SyncObj)
                    {
                        shuttingDown = ShuttingDown;
                    }
                    if (!shuttingDown)
                    {
                        throw new Http3ConnectionException(Http3ErrorCode.ClosedCriticalStream);
                    }
                    return;

                default:
                    await SkipUnknownPayloadAsync(frameType.GetValueOrDefault(), payloadLength).ConfigureAwait(false);

                    break;
                }
            }

            async ValueTask <(Http3FrameType?frameType, long payloadLength)> ReadFrameEnvelopeAsync()
            {
                long frameType, payloadLength;
                int  bytesRead;

                while (!Http3Frame.TryReadIntegerPair(buffer.ActiveSpan, out frameType, out payloadLength, out bytesRead))
                {
                    buffer.EnsureAvailableSpace(VariableLengthIntegerHelper.MaximumEncodedLength * 2);
                    bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                    if (bytesRead != 0)
                    {
                        buffer.Commit(bytesRead);
                    }
                    else if (buffer.ActiveLength == 0)
                    {
                        // End of stream.
                        return(null, 0);
                    }
                    else
                    {
                        // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                        throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                    }
                }

                buffer.Discard(bytesRead);

                return((Http3FrameType)frameType, payloadLength);
            }

            async ValueTask ProcessSettingsFrameAsync(long settingsPayloadLength)
            {
                if (settingsPayloadLength > MaximumSettingsPayloadLength)
                {
                    if (NetEventSource.Log.IsEnabled())
                    {
                        Trace($"Received SETTINGS frame with {settingsPayloadLength} byte payload exceeding the {MaximumSettingsPayloadLength} byte maximum.");
                    }
                    throw new Http3ConnectionException(Http3ErrorCode.ExcessiveLoad);
                }

                while (settingsPayloadLength != 0)
                {
                    long settingId, settingValue;
                    int  bytesRead;

                    while (!Http3Frame.TryReadIntegerPair(buffer.ActiveSpan, out settingId, out settingValue, out bytesRead))
                    {
                        buffer.EnsureAvailableSpace(VariableLengthIntegerHelper.MaximumEncodedLength * 2);
                        bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                        if (bytesRead != 0)
                        {
                            buffer.Commit(bytesRead);
                        }
                        else
                        {
                            // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                            throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                        }
                    }

                    settingsPayloadLength -= bytesRead;

                    // Only support this single setting. Skip others.
                    if (settingId == (long)Http3SettingType.MaxHeaderListSize)
                    {
                        _maximumHeadersLength = (int)Math.Min(settingValue, int.MaxValue);
                    }
                }
            }

            async ValueTask ProcessGoAwayFameAsync(long goawayPayloadLength)
            {
                long lastStreamId;
                int  bytesRead;

                while (!VariableLengthIntegerHelper.TryRead(buffer.AvailableSpan, out lastStreamId, out bytesRead))
                {
                    buffer.EnsureAvailableSpace(VariableLengthIntegerHelper.MaximumEncodedLength);
                    bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                    if (bytesRead != 0)
                    {
                        buffer.Commit(bytesRead);
                    }
                    else
                    {
                        // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                        throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                    }
                }

                buffer.Discard(bytesRead);
                if (bytesRead != goawayPayloadLength)
                {
                    // Frame contains unknown extra data after the integer.
                    throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                }

                OnServerGoAway(lastStreamId);
            }

            async ValueTask SkipUnknownPayloadAsync(Http3FrameType frameType, long payloadLength)
            {
                if (payloadLength > MaximumUnknownFramePayloadLength)
                {
                    Trace($"Received unknown frame type 0x{(long)frameType:x} with {payloadLength} byte payload exceeding the {MaximumUnknownFramePayloadLength} byte maximum.");
                    throw new Http3ConnectionException(Http3ErrorCode.ExcessiveLoad);
                }

                while (payloadLength != 0)
                {
                    if (buffer.ActiveLength == 0)
                    {
                        int bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                        if (bytesRead != 0)
                        {
                            buffer.Commit(bytesRead);
                        }
                        else
                        {
                            // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                            throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                        }
                    }

                    long readLength = Math.Min(payloadLength, buffer.ActiveLength);
                    buffer.Discard((int)readLength);
                    payloadLength -= readLength;
                }
            }
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Routes a stream to an appropriate stream-type-specific processor
        /// </summary>
        private async Task ProcessServerStreamAsync(QuicStream stream)
        {
            try
            {
                await using (stream.ConfigureAwait(false))
                    using (var buffer = new ArrayBuffer(initialSize: 32, usePool: true))
                    {
                        if (stream.CanWrite)
                        {
                            // Server initiated bidirectional streams are either push streams or extensions, and we support neither.
                            throw new Http3ConnectionException(Http3ErrorCode.StreamCreationError);
                        }

                        int bytesRead;

                        try
                        {
                            bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);
                        }
                        catch (QuicStreamAbortedException)
                        {
                            // Treat identical to receiving 0. See below comment.
                            bytesRead = 0;
                        }

                        if (bytesRead == 0)
                        {
                            // https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-unidirectional-streams
                            // A sender can close or reset a unidirectional stream unless otherwise specified. A receiver MUST
                            // tolerate unidirectional streams being closed or reset prior to the reception of the unidirectional
                            // stream header.
                            return;
                        }

                        buffer.Commit(bytesRead);

                        // Stream type is a variable-length integer, but we only check the first byte. There is no known type requiring more than 1 byte.
                        switch (buffer.ActiveSpan[0])
                        {
                        case (byte)Http3StreamType.Control:
                            if (Interlocked.Exchange(ref _haveServerControlStream, 1) != 0)
                            {
                                // A second control stream has been received.
                                throw new Http3ConnectionException(Http3ErrorCode.StreamCreationError);
                            }

                            // Discard the stream type header.
                            buffer.Discard(1);

                            await ProcessServerControlStreamAsync(stream, buffer).ConfigureAwait(false);

                            return;

                        case (byte)Http3StreamType.QPackDecoder:
                            if (Interlocked.Exchange(ref _haveServerQpackDecodeStream, 1) != 0)
                            {
                                // A second QPack decode stream has been received.
                                throw new Http3ConnectionException(Http3ErrorCode.StreamCreationError);
                            }

                            // The stream must not be closed, but we aren't using QPACK right now -- ignore.
                            buffer.Dispose();
                            await stream.CopyToAsync(Stream.Null).ConfigureAwait(false);

                            return;

                        case (byte)Http3StreamType.QPackEncoder:
                            if (Interlocked.Exchange(ref _haveServerQpackEncodeStream, 1) != 0)
                            {
                                // A second QPack encode stream has been received.
                                throw new Http3ConnectionException(Http3ErrorCode.StreamCreationError);
                            }

                            // The stream must not be closed, but we aren't using QPACK right now -- ignore.
                            buffer.Dispose();
                            await stream.CopyToAsync(Stream.Null).ConfigureAwait(false);

                            return;

                        case (byte)Http3StreamType.Push:
                            // We don't support push streams.
                            // Because no maximum push stream ID was negotiated via a MAX_PUSH_ID frame, server should not have sent this. Abort the connection with H3_ID_ERROR.
                            throw new Http3ConnectionException(Http3ErrorCode.IdError);

                        default:
                            // Unknown stream type. Per spec, these must be ignored and aborted but not be considered a connection-level error.

                            if (NetEventSource.Log.IsEnabled())
                            {
                                // Read the rest of the integer, which might be more than 1 byte, so we can log it.

                                long unknownStreamType;
                                while (!VariableLengthIntegerHelper.TryRead(buffer.ActiveSpan, out unknownStreamType, out _))
                                {
                                    buffer.EnsureAvailableSpace(VariableLengthIntegerHelper.MaximumEncodedLength);
                                    bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                                    if (bytesRead == 0)
                                    {
                                        unknownStreamType = -1;
                                        break;
                                    }

                                    buffer.Commit(bytesRead);
                                }

                                NetEventSource.Info(this, $"Ignoring server-initiated stream of unknown type {unknownStreamType}.");
                            }

                            stream.AbortWrite((long)Http3ErrorCode.StreamCreationError);
                            return;
                        }
                    }
            }
            catch (Exception ex)
            {
                Abort(ex);
            }
        }
Ejemplo n.º 22
0
        public async Task MultipleReadsAndWrites()
        {
            for (int j = 0; j < 100; j++)
            {
                Task listenTask = Task.Run(async() =>
                {
                    // Connection isn't being accepted, interesting.
                    using QuicConnection connection = await DefaultListener.AcceptConnectionAsync();
                    await using QuicStream stream   = await connection.AcceptStreamAsync();
                    byte[] buffer = new byte[s_data.Length];

                    while (true)
                    {
                        int bytesRead = await stream.ReadAsync(buffer);
                        if (bytesRead == 0)
                        {
                            break;
                        }
                        Assert.Equal(s_data.Length, bytesRead);
                        Assert.True(s_data.Span.SequenceEqual(buffer));
                    }

                    for (int i = 0; i < 5; i++)
                    {
                        await stream.WriteAsync(s_data);
                    }
                    await stream.WriteAsync(Memory <byte> .Empty, endStream: true);
                    await stream.ShutdownWriteCompleted();
                    await connection.CloseAsync();
                });

                Task clientTask = Task.Run(async() =>
                {
                    using QuicConnection connection = CreateQuicConnection(DefaultListener.ListenEndPoint);
                    await connection.ConnectAsync();
                    await using QuicStream stream = connection.OpenBidirectionalStream();

                    for (int i = 0; i < 5; i++)
                    {
                        await stream.WriteAsync(s_data);
                    }

                    await stream.WriteAsync(Memory <byte> .Empty, endStream: true);

                    byte[] memory = new byte[12];
                    while (true)
                    {
                        int res = await stream.ReadAsync(memory);
                        if (res == 0)
                        {
                            break;
                        }
                        Assert.True(s_data.Span.SequenceEqual(memory));
                    }

                    await stream.ShutdownWriteCompleted();
                    await connection.CloseAsync();
                });

                await(new[] { listenTask, clientTask }).WhenAllOrAnyFailed(millisecondsTimeout: 1000000);
            }
        }
Ejemplo n.º 23
0
        private static async Task SendAndReceiveDataAsync(ReadOnlyMemory <byte> data, QuicStream s1, QuicStream s2)
        {
            await s1.WriteAsync(data);

            await ReceiveDataAsync(data, s2);
        }
Ejemplo n.º 24
0
        public async Task MultipleStreamsOnSingleConnection()
        {
            Task listenTask = Task.Run(async() =>
            {
                {
                    using QuicConnection connection = await DefaultListener.AcceptConnectionAsync();
                    await using QuicStream stream   = await connection.AcceptStreamAsync();
                    await using QuicStream stream2  = await connection.AcceptStreamAsync();

                    byte[] buffer = new byte[s_data.Length];

                    while (true)
                    {
                        int bytesRead = await stream.ReadAsync(buffer);
                        if (bytesRead == 0)
                        {
                            break;
                        }
                        Assert.Equal(s_data.Length, bytesRead);
                        Assert.True(s_data.Span.SequenceEqual(buffer));
                    }

                    while (true)
                    {
                        int bytesRead = await stream2.ReadAsync(buffer);
                        if (bytesRead == 0)
                        {
                            break;
                        }
                        Assert.True(s_data.Span.SequenceEqual(buffer));
                    }

                    await stream.WriteAsync(s_data, endStream: true);
                    await stream.ShutdownWriteCompleted();

                    await stream2.WriteAsync(s_data, endStream: true);
                    await stream2.ShutdownWriteCompleted();

                    await connection.CloseAsync();
                }
            });

            Task clientTask = Task.Run(async() =>
            {
                using QuicConnection connection = CreateQuicConnection(DefaultListener.ListenEndPoint);
                await connection.ConnectAsync();
                await using QuicStream stream  = connection.OpenBidirectionalStream();
                await using QuicStream stream2 = connection.OpenBidirectionalStream();

                await stream.WriteAsync(s_data, endStream: true);
                await stream.ShutdownWriteCompleted();
                await stream2.WriteAsync(s_data, endStream: true);
                await stream2.ShutdownWriteCompleted();

                byte[] memory = new byte[12];
                while (true)
                {
                    int res = await stream.ReadAsync(memory);
                    if (res == 0)
                    {
                        break;
                    }
                    Assert.True(s_data.Span.SequenceEqual(memory));
                }

                while (true)
                {
                    int res = await stream2.ReadAsync(memory);
                    if (res == 0)
                    {
                        break;
                    }
                    Assert.True(s_data.Span.SequenceEqual(memory));
                }

                await connection.CloseAsync();
            });

            await(new[] { listenTask, clientTask }).WhenAllOrAnyFailed(millisecondsTimeout: 60000);
        }
Ejemplo n.º 25
0
 public Http3LoopbackStream(QuicStream stream)
 {
     _stream = stream;
 }
Ejemplo n.º 26
0
        /// <summary>
        /// Reads the server's control stream.
        /// </summary>
        private async Task ProcessServerControlStreamAsync(QuicStream stream, ArrayBuffer buffer)
        {
            using (buffer)
            {
                // Read the first frame of the control stream. Per spec:
                // A SETTINGS frame MUST be sent as the first frame of each control stream.

                (Http3FrameType? frameType, long payloadLength) = await ReadFrameEnvelopeAsync().ConfigureAwait(false);

                if (frameType == null)
                {
                    // Connection closed prematurely, expected SETTINGS frame.
                    throw new Http3ConnectionException(Http3ErrorCode.ClosedCriticalStream);
                }

                if (frameType != Http3FrameType.Settings)
                {
                    throw new Http3ConnectionException(Http3ErrorCode.MissingSettings);
                }

                await ProcessSettingsFrameAsync(payloadLength).ConfigureAwait(false);

                // Read subsequent frames.

                while (true)
                {
                    (frameType, payloadLength) = await ReadFrameEnvelopeAsync().ConfigureAwait(false);

                    switch (frameType)
                    {
                    case Http3FrameType.GoAway:
                        await ProcessGoAwayFameAsync(payloadLength).ConfigureAwait(false);

                        break;

                    case Http3FrameType.Settings:
                        // If an endpoint receives a second SETTINGS frame on the control stream, the endpoint MUST respond with a connection error of type H3_FRAME_UNEXPECTED.
                        throw new Http3ConnectionException(Http3ErrorCode.UnexpectedFrame);

                    case Http3FrameType.Headers:
                    case Http3FrameType.Data:
                    case Http3FrameType.MaxPushId:
                    case Http3FrameType.DuplicatePush:
                        // Servers should not send these frames to a control stream.
                        throw new Http3ConnectionException(Http3ErrorCode.UnexpectedFrame);

                    case Http3FrameType.PushPromise:
                    case Http3FrameType.CancelPush:
                        // Because we haven't sent any MAX_PUSH_ID frame, it is invalid to receive any push-related frames as they will all reference a too-large ID.
                        throw new Http3ConnectionException(Http3ErrorCode.IdError);

                    case null:
                        // End of stream reached. If we're shutting down, stop looping. Otherwise, this is an error (this stream should not be closed for life of connection).
                        bool shuttingDown;
                        lock (SyncObj)
                        {
                            shuttingDown = ShuttingDown;
                        }
                        if (!shuttingDown)
                        {
                            throw new Http3ConnectionException(Http3ErrorCode.ClosedCriticalStream);
                        }
                        return;

                    default:
                        await SkipUnknownPayloadAsync(frameType.GetValueOrDefault(), payloadLength).ConfigureAwait(false);

                        break;
                    }
                }
            }

            async ValueTask <(Http3FrameType?frameType, long payloadLength)> ReadFrameEnvelopeAsync()
            {
                long frameType, payloadLength;
                int  bytesRead;

                while (!Http3Frame.TryReadIntegerPair(buffer.ActiveSpan, out frameType, out payloadLength, out bytesRead))
                {
                    buffer.EnsureAvailableSpace(VariableLengthIntegerHelper.MaximumEncodedLength * 2);
                    bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                    if (bytesRead != 0)
                    {
                        buffer.Commit(bytesRead);
                    }
                    else if (buffer.ActiveLength == 0)
                    {
                        // End of stream.
                        return(null, 0);
                    }
                    else
                    {
                        // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                        throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                    }
                }

                buffer.Discard(bytesRead);

                return((Http3FrameType)frameType, payloadLength);
            }

            async ValueTask ProcessSettingsFrameAsync(long settingsPayloadLength)
            {
                while (settingsPayloadLength != 0)
                {
                    long settingId, settingValue;
                    int  bytesRead;

                    while (!Http3Frame.TryReadIntegerPair(buffer.ActiveSpan, out settingId, out settingValue, out bytesRead))
                    {
                        buffer.EnsureAvailableSpace(VariableLengthIntegerHelper.MaximumEncodedLength * 2);
                        bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                        if (bytesRead != 0)
                        {
                            buffer.Commit(bytesRead);
                        }
                        else
                        {
                            // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                            throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                        }
                    }

                    settingsPayloadLength -= bytesRead;

                    if (settingsPayloadLength < 0)
                    {
                        // An integer was encoded past the payload length.
                        // A frame payload that contains additional bytes after the identified fields or a frame payload that terminates before the end of the identified fields MUST be treated as a connection error of type H3_FRAME_ERROR.
                        throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                    }

                    buffer.Discard(bytesRead);

                    // Only support this single setting. Skip others.
                    if (settingId == (long)Http3SettingType.MaxHeaderListSize)
                    {
                        _maximumHeadersLength = (int)Math.Min(settingValue, int.MaxValue);
                    }
                }
            }

            async ValueTask ProcessGoAwayFameAsync(long goawayPayloadLength)
            {
                long lastStreamId;
                int  bytesRead;

                while (!VariableLengthIntegerHelper.TryRead(buffer.AvailableSpan, out lastStreamId, out bytesRead))
                {
                    buffer.EnsureAvailableSpace(VariableLengthIntegerHelper.MaximumEncodedLength);
                    bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                    if (bytesRead != 0)
                    {
                        buffer.Commit(bytesRead);
                    }
                    else
                    {
                        // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                        throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                    }
                }

                buffer.Discard(bytesRead);
                if (bytesRead != goawayPayloadLength)
                {
                    // Frame contains unknown extra data after the integer.
                    throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                }

                OnServerGoAway(lastStreamId);
            }

            async ValueTask SkipUnknownPayloadAsync(Http3FrameType frameType, long payloadLength)
            {
                while (payloadLength != 0)
                {
                    if (buffer.ActiveLength == 0)
                    {
                        int bytesRead = await stream.ReadAsync(buffer.AvailableMemory, CancellationToken.None).ConfigureAwait(false);

                        if (bytesRead != 0)
                        {
                            buffer.Commit(bytesRead);
                        }
                        else
                        {
                            // Our buffer has partial frame data in it but not enough to complete the read: bail out.
                            throw new Http3ConnectionException(Http3ErrorCode.FrameError);
                        }
                    }

                    long readLength = Math.Min(payloadLength, buffer.ActiveLength);
                    buffer.Discard((int)readLength);
                    payloadLength -= readLength;
                }
            }
        }
Ejemplo n.º 27
0
        public async Task LargeDataSentAndReceived()
        {
            byte[]    data           = Enumerable.Range(0, 64 * 1024).Select(x => (byte)x).ToArray();
            const int NumberOfWrites = 256;       // total sent = 16M

            using QuicListener listener = CreateQuicListener();

            for (int j = 0; j < 100; j++)
            {
                Task listenTask = Task.Run(async() =>
                {
                    using QuicConnection connection = await listener.AcceptConnectionAsync();
                    await using QuicStream stream   = await connection.AcceptStreamAsync();
                    byte[] buffer = new byte[data.Length];

                    for (int i = 0; i < NumberOfWrites; i++)
                    {
                        int totalBytesRead = 0;
                        while (totalBytesRead < data.Length)
                        {
                            int bytesRead = await stream.ReadAsync(buffer.AsMemory(totalBytesRead));
                            Assert.NotEqual(0, bytesRead);
                            totalBytesRead += bytesRead;
                        }

                        Assert.Equal(data.Length, totalBytesRead);
                        Assert.True(data.AsSpan().SequenceEqual(buffer));
                    }

                    for (int i = 0; i < NumberOfWrites; i++)
                    {
                        await stream.WriteAsync(data);
                    }

                    await stream.WriteAsync(Memory <byte> .Empty, endStream: true);

                    await stream.ShutdownWriteCompleted();
                    await connection.CloseAsync(errorCode: 0);
                });

                Task clientTask = Task.Run(async() =>
                {
                    using QuicConnection connection = CreateQuicConnection(listener.ListenEndPoint);
                    await connection.ConnectAsync();
                    await using QuicStream stream = connection.OpenBidirectionalStream();
                    byte[] buffer = new byte[data.Length];

                    for (int i = 0; i < NumberOfWrites; i++)
                    {
                        await stream.WriteAsync(data);
                    }

                    await stream.WriteAsync(Memory <byte> .Empty, endStream: true);

                    for (int i = 0; i < NumberOfWrites; i++)
                    {
                        int totalBytesRead = 0;
                        while (totalBytesRead < data.Length)
                        {
                            int bytesRead = await stream.ReadAsync(buffer.AsMemory(totalBytesRead));
                            Assert.NotEqual(0, bytesRead);
                            totalBytesRead += bytesRead;
                        }

                        Assert.Equal(data.Length, totalBytesRead);
                        Assert.True(data.AsSpan().SequenceEqual(buffer));
                    }

                    await stream.ShutdownWriteCompleted();
                    await connection.CloseAsync(errorCode: 0);
                });

                await(new[] { listenTask, clientTask }).WhenAllOrAnyFailed(millisecondsTimeout: 1000000);
            }
        }
Ejemplo n.º 28
0
        public async Task WriteTests(int[][] writes, WriteType writeType)
        {
            await RunClientServer(
                async clientConnection =>
            {
                await using QuicStream stream = clientConnection.OpenUnidirectionalStream();

                foreach (int[] bufferLengths in writes)
                {
                    switch (writeType)
                    {
                    case WriteType.SingleBuffer:
                        foreach (int bufferLength in bufferLengths)
                        {
                            await stream.WriteAsync(new byte[bufferLength]);
                        }
                        break;

                    case WriteType.GatheredBuffers:
                        var buffers = bufferLengths
                                      .Select(bufferLength => new ReadOnlyMemory <byte>(new byte[bufferLength]))
                                      .ToArray();
                        await stream.WriteAsync(buffers);
                        break;

                    case WriteType.GatheredSequence:
                        var firstSegment          = new BufferSegment(new byte[bufferLengths[0]]);
                        BufferSegment lastSegment = firstSegment;

                        foreach (int bufferLength in bufferLengths.Skip(1))
                        {
                            lastSegment = lastSegment.Append(new byte[bufferLength]);
                        }

                        var buffer = new ReadOnlySequence <byte>(firstSegment, 0, lastSegment, lastSegment.Memory.Length);
                        await stream.WriteAsync(buffer);
                        break;

                    default:
                        Debug.Fail("Unknown write type.");
                        break;
                    }
                }

                stream.Shutdown();
                await stream.ShutdownCompleted();
            },
                async serverConnection =>
            {
                await using QuicStream stream = await serverConnection.AcceptStreamAsync();

                var buffer        = new byte[4096];
                int receivedBytes = 0, totalBytes = 0;

                while ((receivedBytes = await stream.ReadAsync(buffer)) != 0)
                {
                    totalBytes += receivedBytes;
                }

                int expectedTotalBytes = writes.SelectMany(x => x).Sum();
                Assert.Equal(expectedTotalBytes, totalBytes);

                stream.Shutdown();
                await stream.ShutdownCompleted();
            });
        }
Ejemplo n.º 29
0
 public StreamPair(QuicStream stream1, QuicStream stream2)
 {
     Stream1 = stream1;
     Stream2 = stream2;
 }
Ejemplo n.º 30
0
        protected static async Task <StreamPair> CreateConnectedStreamsAsync()
        {
            QuicImplementationProvider provider = ImplementationProvider;
            var protocol = new SslApplicationProtocol("quictest");

            QuicListener listener = new QuicListener(provider, new QuicListenerOptions()
            {
                ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0),
                ServerAuthenticationOptions = new SslServerAuthenticationOptions {
                    ApplicationProtocols = new List <SslApplicationProtocol> {
                        protocol
                    }
                },
                CertificateFilePath = "Certs/cert.crt",
                PrivateKeyFilePath  = "Certs/cert.key"
            });

            listener.Start();

            QuicConnection connection1 = null, connection2 = null;
            QuicStream     stream1 = null, stream2 = null;

            await Task.WhenAll(
                Task.Run(async() =>
            {
                connection1 = await listener.AcceptConnectionAsync();
                stream1     = await connection1.AcceptStreamAsync();

                // Hack to force stream creation
                byte[] buffer = new byte[1];
                await stream1.ReadAsync(buffer);
            }),
                Task.Run(async() =>
            {
                connection2 = new QuicConnection(
                    provider,
                    listener.ListenEndPoint,
                    new SslClientAuthenticationOptions()
                {
                    ApplicationProtocols = new List <SslApplicationProtocol>()
                    {
                        protocol
                    }
                });
                await connection2.ConnectAsync();
                stream2 = connection2.OpenBidirectionalStream();

                // Hack to force stream creation
                byte[] buffer = new byte[1];
                await stream2.WriteAsync(buffer);
                await stream2.FlushAsync();
            }));

            var result = new StreamPair(stream1, stream2);

            result.Disposables.Add(connection1);
            result.Disposables.Add(connection2);
            result.Disposables.Add(listener);

            return(result);
        }