Beispiel #1
0
        private static async Task ServerConnectionTask(QuicConnection connection, CancellationToken cancellationToken)
        {
            try
            {
                while (true)
                {
                    var stream = await connection.AcceptStreamAsync(cancellationToken).ConfigureAwait(false);

                    if (!stream.CanRead || !stream.CanWrite)
                    {
                        await connection.CloseAsync(1, cancellationToken).ConfigureAwait(false);

                        return;
                    }

                    _ = Helpers.Dispatch(() => ServerQuicStreamTask(connection, stream));
                }
            }
            catch (QuicConnectionAbortedException e) when(e.ErrorCode == 0)
            {
                // ignore successful closing
            }
            catch (OperationCanceledException)
            {
            }
            finally
            {
                await connection.CloseAsync(1).ConfigureAwait(false);

                connection.Dispose();
            }
        }
        public override async ValueTask DisposeAsync()
        {
            try
            {
                _closeTask ??= _connection.CloseAsync(errorCode: 0).AsTask();
                await _closeTask;
            }
            catch (Exception ex)
            {
                _log.LogWarning(ex, "Failed to gracefully shutdown connection.");
            }

            _connection.Dispose();
        }
Beispiel #3
0
        private async Task TestConnection(CipherSuitesPolicy serverPolicy, CipherSuitesPolicy clientPolicy)
        {
            var listenerOptions = new QuicListenerOptions()
            {
                ListenEndPoint       = new IPEndPoint(IPAddress.Loopback, 0),
                ApplicationProtocols = new List <SslApplicationProtocol>()
                {
                    ApplicationProtocol
                },
                ConnectionOptionsCallback = (_, _, _) =>
                {
                    var serverOptions = CreateQuicServerOptions();
                    serverOptions.ServerAuthenticationOptions.CipherSuitesPolicy = serverPolicy;
                    return(ValueTask.FromResult(serverOptions));
                }
            };

            await using QuicListener listener = await CreateQuicListener(listenerOptions);

            var clientOptions = CreateQuicClientOptions(listener.LocalEndPoint);

            clientOptions.ClientAuthenticationOptions.CipherSuitesPolicy = clientPolicy;
            await using QuicConnection clientConnection = await CreateQuicConnection(clientOptions);

            await clientConnection.CloseAsync(0);
        }
Beispiel #4
0
    public async Task AcceptAsync_ClientClosesConnection_ServerNotified()
    {
        // Arrange
        var connectionClosedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        // Act
        var acceptTask = connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await clientConnection.ConnectAsync().DefaultTimeout();

        await using var serverConnection = await acceptTask.DefaultTimeout();

        serverConnection.ConnectionClosed.Register(() => connectionClosedTcs.SetResult());

        var acceptStreamTask = serverConnection.AcceptAsync();

        await clientConnection.CloseAsync(256);

        // Assert
        var ex = await Assert.ThrowsAsync <ConnectionResetException>(() => acceptStreamTask.AsTask()).DefaultTimeout();

        var innerEx = Assert.IsType <QuicConnectionAbortedException>(ex.InnerException);

        Assert.Equal(256, innerEx.ErrorCode);

        await connectionClosedTcs.Task.DefaultTimeout();
    }
Beispiel #5
0
        public async Task TestStreams()
        {
            using QuicListener listener = CreateQuicListener();
            IPEndPoint listenEndPoint = listener.ListenEndPoint;

            using QuicConnection clientConnection = CreateQuicConnection(listenEndPoint);

            Assert.False(clientConnection.Connected);
            Assert.Equal(listenEndPoint, clientConnection.RemoteEndPoint);

            ValueTask      connectTask      = clientConnection.ConnectAsync();
            QuicConnection serverConnection = await listener.AcceptConnectionAsync();

            await connectTask;

            Assert.True(clientConnection.Connected);
            Assert.True(serverConnection.Connected);
            Assert.Equal(listenEndPoint, serverConnection.LocalEndPoint);
            Assert.Equal(listenEndPoint, clientConnection.RemoteEndPoint);
            Assert.Equal(clientConnection.LocalEndPoint, serverConnection.RemoteEndPoint);

            await CreateAndTestBidirectionalStream(clientConnection, serverConnection);
            await CreateAndTestBidirectionalStream(serverConnection, clientConnection);
            await CreateAndTestUnidirectionalStream(serverConnection, clientConnection);
            await CreateAndTestUnidirectionalStream(clientConnection, serverConnection);

            await clientConnection.CloseAsync(errorCode : 0);
        }
Beispiel #6
0
        public async Task Read_ConnectionAborted_Throws()
        {
            const int ExpectedErrorCode = 1234;

            await Task.Run(async() =>
            {
                using QuicListener listener = CreateQuicListener();
                ValueTask <QuicConnection> serverConnectionTask = listener.AcceptConnectionAsync();

                using QuicConnection clientConnection = CreateQuicConnection(listener.ListenEndPoint);
                await clientConnection.ConnectAsync();

                using QuicConnection serverConnection = await serverConnectionTask;

                await using QuicStream clientStream = clientConnection.OpenBidirectionalStream();
                await clientStream.WriteAsync(new byte[1]);

                await using QuicStream serverStream = await serverConnection.AcceptStreamAsync();
                await serverStream.ReadAsync(new byte[1]);

                await clientConnection.CloseAsync(ExpectedErrorCode);

                byte[] buffer = new byte[100];
                QuicConnectionAbortedException ex = await Assert.ThrowsAsync <QuicConnectionAbortedException>(() => serverStream.ReadAsync(buffer).AsTask());
                Assert.Equal(ExpectedErrorCode, ex.ErrorCode);
            }).TimeoutAfter(millisecondsTimeout: 5_000);
        }
Beispiel #7
0
    public async Task AcceptAsync_ClientClosesConnection_ExceptionThrown()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

        var options = QuicTestHelpers.CreateClientConnectionOptions(connectionListener.EndPoint);

        using var quicConnection = new QuicConnection(QuicImplementationProviders.MsQuic, options);
        await quicConnection.ConnectAsync().DefaultTimeout();

        var serverConnection = await connectionListener.AcceptAndAddFeatureAsync().DefaultTimeout();

        // Act
        var acceptTask = serverConnection.AcceptAsync().AsTask();

        await quicConnection.CloseAsync((long)Http3ErrorCode.NoError).DefaultTimeout();

        // Assert
        var ex = await Assert.ThrowsAsync <ConnectionResetException>(() => acceptTask).DefaultTimeout();

        var innerEx = Assert.IsType <QuicConnectionAbortedException>(ex.InnerException);

        Assert.Equal((long)Http3ErrorCode.NoError, innerEx.ErrorCode);

        Assert.Equal((long)Http3ErrorCode.NoError, serverConnection.Features.Get <IProtocolErrorCodeFeature>().Error);
    }
Beispiel #8
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)
            {
                // Close the QuicConnection in the background.

                if (_connectionClosedTask == null)
                {
                    _connectionClosedTask = _connection.CloseAsync((long)Http3ErrorCode.NoError).AsTask();
                }

                QuicConnection connection = _connection;
                _connection = null;

                _ = _connectionClosedTask.ContinueWith(closeTask =>
                {
                    if (closeTask.IsFaulted && NetEventSource.IsEnabled)
                    {
                        Trace($"{nameof(QuicConnection)} failed to close: {closeTask.Exception.InnerException}");
                    }

                    try
                    {
                        connection.Dispose();
                    }
                    catch (Exception ex)
                    {
                        Trace($"{nameof(QuicConnection)} failed to dispose: {ex}");
                    }
                }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
            }
        }
Beispiel #9
0
    public override async ValueTask DisposeAsync()
    {
        try
        {
            lock (_shutdownLock)
            {
                _closeTask ??= _connection.CloseAsync(errorCode: _context.Options.DefaultCloseErrorCode).AsTask();
            }

            await _closeTask;
        }
        catch (Exception ex)
        {
            _log.LogWarning(ex, "Failed to gracefully shutdown connection.");
        }

        await _connection.DisposeAsync();
    }
Beispiel #10
0
        public static async Task <int> RunClient(IPEndPoint serverEp, CancellationToken token)
        {
            using var client = new QuicConnection(new QuicClientConnectionOptions
            {
                RemoteEndPoint = serverEp,
                ClientAuthenticationOptions = new SslClientAuthenticationOptions
                {
                    ApplicationProtocols = new List <SslApplicationProtocol>
                    {
                        new SslApplicationProtocol("echo") // same as used for server
                    }
                }
            });

            await client.ConnectAsync(token);

            try
            {
                await using QuicStream stream = client.OpenBidirectionalStream();

                // spawn a reader task to not let server be flow-control blocked
                _ = Task.Run(async() =>
                {
                    byte[] arr = new byte[4 * 1024];
                    int read;
                    while ((read = await stream.ReadAsync(arr, token)) > 0)
                    {
                        string s = Encoding.ASCII.GetString(arr, 0, read);
                        Console.WriteLine($"Received: {s}");
                    }
                });

                string line;
                while ((line = Console.ReadLine()) != null)
                {
                    // convert into ASCII byte array before sending
                    byte[] bytes = Encoding.ASCII.GetBytes(line);
                    await stream.WriteAsync(bytes, token);

                    // flush the stream to send the data immediately
                    await stream.FlushAsync(token);
                }

                // once all stdin is written, close the stream
                stream.Shutdown();

                // wait until the server receives all data
                await stream.ShutdownWriteCompleted(token);
            }
            finally
            {
                await client.CloseAsync(0, token);
            }

            return(0);
        }
Beispiel #11
0
        public override async ValueTask DisposeAsync()
        {
            try
            {
                if (_closeTask != default)
                {
                    _closeTask = _connection.CloseAsync(errorCode: 0);
                    await _closeTask;
                }
                else
                {
                    await _closeTask;
                }
            }
            catch (Exception ex)
            {
                _log.LogWarning(ex, "Failed to gracefully shutdown connection.");
            }

            _connection.Dispose();
        }
Beispiel #12
0
        private async Task TestConnection(CipherSuitesPolicy serverPolicy, CipherSuitesPolicy clientPolicy)
        {
            var listenerOptions = CreateQuicListenerOptions();

            listenerOptions.ServerAuthenticationOptions.CipherSuitesPolicy = serverPolicy;
            using QuicListener listener = await CreateQuicListener(listenerOptions);

            var clientOptions = CreateQuicClientOptions();

            clientOptions.ClientAuthenticationOptions.CipherSuitesPolicy = clientPolicy;
            clientOptions.RemoteEndPoint          = listener.ListenEndPoint;
            using QuicConnection clientConnection = await CreateQuicConnection(clientOptions);

            await clientConnection.ConnectAsync();

            await clientConnection.CloseAsync(0);
        }
Beispiel #13
0
        public async Task ConnectWithClientCertificate()
        {
            bool clientCertificateOK = false;

            var serverOptions = new QuicListenerOptions();

            serverOptions.ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0);
            serverOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions();
            serverOptions.ServerAuthenticationOptions.ClientCertificateRequired           = true;
            serverOptions.ServerAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) =>
            {
                _output.WriteLine("client certificate {0}", cert);
                Assert.NotNull(cert);
                Assert.Equal(ClientCertificate.Thumbprint, ((X509Certificate2)cert).Thumbprint);

                clientCertificateOK = true;
                return(true);
            };
            using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, serverOptions);

            QuicClientConnectionOptions clientOptions = new QuicClientConnectionOptions()
            {
                RemoteEndPoint = listener.ListenEndPoint,
                ClientAuthenticationOptions = GetSslClientAuthenticationOptions(),
            };

            clientOptions.ClientAuthenticationOptions.ClientCertificates = new X509CertificateCollection()
            {
                ClientCertificate
            };

            using QuicConnection clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, clientOptions);
            Task <QuicConnection> serverTask = listener.AcceptConnectionAsync().AsTask();
            await TaskTimeoutExtensions.WhenAllOrAnyFailed(clientConnection.ConnectAsync().AsTask(), serverTask, PassingTestTimeoutMilliseconds);

            using QuicConnection serverConnection = serverTask.Result;

            // Verify functionality of the connections.
            await PingPong(clientConnection, serverConnection);

            // check we completed the client certificate verification.
            Assert.True(clientCertificateOK);
            Assert.Equal(ClientCertificate, serverConnection.RemoteCertificate);

            await serverConnection.CloseAsync(0);
        }
Beispiel #14
0
        public async Task BasicTest()
        {
            using QuicListener listener = CreateQuicListener();

            for (int i = 0; i < 100; i++)
            {
                Task listenTask = Task.Run(async() =>
                {
                    using QuicConnection connection = await listener.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(listener.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);
            }
        }
Beispiel #15
0
        public async Task AbortiveConnectionFromClient()
        {
            using QuicConnection clientConnection = CreateQuicConnection(DefaultListener.ListenEndPoint);

            ValueTask clientTask = clientConnection.ConnectAsync();

            using QuicConnection serverConnection = await DefaultListener.AcceptConnectionAsync();

            await clientTask;
            // Close connection on client, verifying server connection is aborted.
            await clientConnection.CloseAsync();

            QuicStream stream = await serverConnection.AcceptStreamAsync();

            // Providers are alaways wrapped right now by a QuicStream. All fields are null here.
            // TODO make sure this returns null.
            Assert.Throws <NullReferenceException>(() => stream.CanRead);
        }
Beispiel #16
0
        public async Task TestStreams()
        {
            using (QuicListener listener = new QuicListener(
                       QuicImplementationProviders.MsQuic,
                       new IPEndPoint(IPAddress.Loopback, 0),
                       GetSslServerAuthenticationOptions()))
            {
                listener.Start();
                IPEndPoint listenEndPoint = listener.ListenEndPoint;

                using (QuicConnection clientConnection = new QuicConnection(
                           QuicImplementationProviders.MsQuic,
                           listenEndPoint,
                           sslClientAuthenticationOptions: new SslClientAuthenticationOptions {
                    ApplicationProtocols = new List <SslApplicationProtocol>()
                    {
                        new SslApplicationProtocol("quictest")
                    }
                }))
                {
                    Assert.False(clientConnection.Connected);
                    Assert.Equal(listenEndPoint, clientConnection.RemoteEndPoint);

                    ValueTask      connectTask      = clientConnection.ConnectAsync();
                    QuicConnection serverConnection = await listener.AcceptConnectionAsync();

                    await connectTask;

                    Assert.True(clientConnection.Connected);
                    Assert.True(serverConnection.Connected);
                    Assert.Equal(listenEndPoint, serverConnection.LocalEndPoint);
                    Assert.Equal(listenEndPoint, clientConnection.RemoteEndPoint);
                    Assert.Equal(clientConnection.LocalEndPoint, serverConnection.RemoteEndPoint);

                    await CreateAndTestBidirectionalStream(clientConnection, serverConnection);
                    await CreateAndTestBidirectionalStream(serverConnection, clientConnection);
                    await CreateAndTestUnidirectionalStream(serverConnection, clientConnection);
                    await CreateAndTestUnidirectionalStream(clientConnection, serverConnection);

                    await clientConnection.CloseAsync();
                }
            }
        }
Beispiel #17
0
        /// <summary>
        /// Aborts the connection with an error.
        /// </summary>
        /// <remarks>
        /// Used for e.g. I/O or connection-level frame parsing errors.
        /// </remarks>
        internal Exception Abort(Exception abortException)
        {
            // Only observe the first exception we get.
            Exception firstException = Interlocked.CompareExchange(ref _abortException, abortException, null);

            if (firstException != null)
            {
                if (NetEventSource.IsEnabled && !ReferenceEquals(firstException, abortException))
                {
                    // Lost the race to set the field to another exception, so just trace this one.
                    Trace($"{nameof(abortException)}=={abortException}");
                }

                return(firstException);
            }

            // Stop sending requests to this connection.
            _pool.InvalidateHttp3Connection(this);

            Http3ErrorCode connectionResetErrorCode = (abortException as Http3ProtocolException)?.ErrorCode ?? Http3ErrorCode.InternalError;

            lock (SyncObj)
            {
                // Set _lastProcessedStreamId != -1 to make ShuttingDown = true.
                // It's possible GOAWAY is already being processed, in which case this would already be != -1.
                if (_lastProcessedStreamId == -1)
                {
                    _lastProcessedStreamId = long.MaxValue;
                }

                // Abort the connection. This will cause all of our streams to abort on their next I/O.
                _connection?.CloseAsync((long)connectionResetErrorCode).GetAwaiter().GetResult(); // TODO: async...

                CancelWaiters();
                CheckForShutdown();
            }

            return(abortException);
        }
Beispiel #18
0
        public async Task TestStreams()
        {
            using QuicListener listener = new QuicListener(
                      QuicImplementationProviders.MsQuic,
                      new IPEndPoint(IPAddress.Loopback, 0),
                      GetSslServerAuthenticationOptions());

            listener.Start();
            IPEndPoint listenEndPoint = listener.ListenEndPoint;

            Assert.NotEqual(0, listenEndPoint.Port);

            using QuicConnection clientConnection = new QuicConnection(
                      QuicImplementationProviders.MsQuic,
                      listenEndPoint,
                      GetSslClientAuthenticationOptions());

            Assert.False(clientConnection.Connected);
            Assert.Equal(listenEndPoint, clientConnection.RemoteEndPoint);

            ValueTask      connectTask      = clientConnection.ConnectAsync();
            QuicConnection serverConnection = await listener.AcceptConnectionAsync();

            await connectTask;

            Assert.True(clientConnection.Connected);
            Assert.True(serverConnection.Connected);
            Assert.Equal(listenEndPoint, serverConnection.LocalEndPoint);
            Assert.Equal(listenEndPoint, clientConnection.RemoteEndPoint);
            Assert.Equal(clientConnection.LocalEndPoint, serverConnection.RemoteEndPoint);

            await CreateAndTestBidirectionalStream(clientConnection, serverConnection);
            await CreateAndTestBidirectionalStream(serverConnection, clientConnection);
            await CreateAndTestUnidirectionalStream(serverConnection, clientConnection);
            await CreateAndTestUnidirectionalStream(clientConnection, serverConnection);

            await clientConnection.CloseAsync(errorCode : 0);
        }
Beispiel #19
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;
            }
        }
Beispiel #20
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);
     }
 }
Beispiel #21
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);
            }
        }
Beispiel #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);
            }
        }
Beispiel #23
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);
        }
        public async Task CloseAsync(long errorCode)
        {
            await _connection.CloseAsync(errorCode).ConfigureAwait(false);

            _closed = true;
        }
Beispiel #25
0
 public Task CloseAsync(long errorCode) => _connection.CloseAsync(errorCode).AsTask();
Beispiel #26
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);
            }
        }