Example #1
0
    public async Task BidirectionalStream_ClientAbortedAfterDisposeCalled_NotPooled()
    {
        // Arrange
        using var httpEventSource = new HttpEventSourceListener(LoggerFactory);

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

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

        await using var clientConnection = await QuicConnection.ConnectAsync(options);

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

        // Act
        Logger.LogInformation("Client starting stream.");
        var clientStream = await clientConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);

        await clientStream.WriteAsync(TestData).DefaultTimeout();

        var readTask = clientStream.ReadUntilEndAsync();

        Logger.LogInformation("Server accepted stream.");
        var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

        var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

        // Server sends a large response that will make it wait to complete sends.
        Logger.LogInformation("Server writing a large response.");
        await serverStream.Transport.Output.WriteAsync(new byte[1024 * 1024 * 32]).DefaultTimeout();

        // Complete reading and writing.
        Logger.LogInformation("Server complete reading and writing.");
        await serverStream.Transport.Input.CompleteAsync();

        await serverStream.Transport.Output.CompleteAsync();

        Logger.LogInformation("Client wait to finish reading.");
        await readTask.DefaultTimeout();

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        // Server starts disposing
        Logger.LogInformation("Server starts disposing.");
        var disposeTask = quicStreamContext.DisposeAsync();

        // Client aborts while server is draining
        clientStream.Abort(QuicAbortDirection.Read, (long)Http3ErrorCode.RequestCancelled);
        clientStream.Abort(QuicAbortDirection.Write, (long)Http3ErrorCode.RequestCancelled);

        // Server finishes disposing
        Logger.LogInformation("Wait for server finish disposing.");
        await disposeTask.DefaultTimeout();

        quicStreamContext.Dispose();

        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        // Assert
        Assert.Equal(0, quicConnectionContext.StreamPool.Count);
    }
Example #2
0
 /// <summary>
 /// Fired when Client is connected
 /// </summary>
 /// <param name="connection">The new connection</param>
 static void ClientConnected(QuicConnection connection)
 {
     Console.WriteLine("Client Connected");
     connection.OnStreamOpened += StreamOpened;
 }
Example #3
0
        public static async Task <QuicStreamContext> CreateAndCompleteBidirectionalStreamGracefully(QuicConnection clientConnection, MultiplexedConnectionContext serverConnection)
        {
            var clientStream = clientConnection.OpenBidirectionalStream();
            await clientStream.WriteAsync(TestData, endStream : true).DefaultTimeout();

            var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

            var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

            serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

            // Input should be completed.
            readResult = await serverStream.Transport.Input.ReadAsync();

            Assert.True(readResult.IsCompleted);

            // Complete reading and writing.
            await serverStream.Transport.Input.CompleteAsync();

            await serverStream.Transport.Output.CompleteAsync();

            var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

            // Both send and receive loops have exited.
            await quicStreamContext._processingTask.DefaultTimeout();

            Assert.True(quicStreamContext.CanWrite);
            Assert.True(quicStreamContext.CanRead);

            await quicStreamContext.DisposeAsync();

            quicStreamContext.Dispose();

            return(quicStreamContext);
        }
Example #4
0
 private static ulong ProjectBytesReceived(QuicConnection connection)
 {
     return(connection.BytesReceived);
 }
Example #5
0
 private static TimestampDelta ProjectDuration(QuicConnection connection)
 {
     return(connection.FinalTimeStamp - connection.InitialTimeStamp);
 }
Example #6
0
 private static ulong ProjectCorrelationId(QuicConnection connection)
 {
     return(connection.CorrelationId);
 }
Example #7
0
 private static string ProjectState(QuicConnection connection)
 {
     return(connection.State.ToString());
 }
Example #8
0
 protected abstract Task QuicStreamServer(QuicConnection connection);
Example #9
0
        public async Task ConnectWithCertificateCallback()
        {
            X509Certificate2 c1 = System.Net.Test.Common.Configuration.Certificates.GetServerCertificate();
            X509Certificate2 c2 = System.Net.Test.Common.Configuration.Certificates.GetClientCertificate(); // This 'wrong' certificate but should be sufficient
            X509Certificate2 expectedCertificate = c1;

            using CancellationTokenSource cts = new CancellationTokenSource();
            cts.CancelAfter(PassingTestTimeout);
            string?         receivedHostName    = null;
            X509Certificate?receivedCertificate = null;

            var listenerOptions = new QuicListenerOptions();

            listenerOptions.ListenEndPoint = new IPEndPoint(Socket.OSSupportsIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback, 0);
            listenerOptions.ServerAuthenticationOptions = GetSslServerAuthenticationOptions();
            listenerOptions.ServerAuthenticationOptions.ServerCertificate = null;
            listenerOptions.ServerAuthenticationOptions.ServerCertificateSelectionCallback = (sender, hostName) =>
            {
                receivedHostName = hostName;
                if (hostName == "foobar1")
                {
                    return(c1);
                }
                else if (hostName == "foobar2")
                {
                    return(c2);
                }

                return(null);
            };

            using QuicListener listener = new QuicListener(QuicImplementationProviders.MsQuic, listenerOptions);
            QuicClientConnectionOptions clientOptions = CreateQuicClientOptions();

            clientOptions.ClientAuthenticationOptions.TargetHost = "foobar1";
            clientOptions.ClientAuthenticationOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) =>
            {
                receivedCertificate = cert;
                return(true);
            };

            (QuicConnection clientConnection, QuicConnection serverConnection) = await CreateConnectedQuicConnection(clientOptions, listener);

            Assert.Equal(clientOptions.ClientAuthenticationOptions.TargetHost, receivedHostName);
            Assert.Equal(c1, receivedCertificate);
            clientConnection.Dispose();
            serverConnection.Dispose();

            // This should fail when callback return null.
            clientOptions.ClientAuthenticationOptions.TargetHost = "foobar3";
            clientConnection = new QuicConnection(QuicImplementationProviders.MsQuic, clientOptions);
            Task clientTask = clientConnection.ConnectAsync(cts.Token).AsTask();

            await Assert.ThrowsAsync <QuicException>(() => clientTask);

            Assert.Equal(clientOptions.ClientAuthenticationOptions.TargetHost, receivedHostName);
            clientConnection.Dispose();

            // Do this last to make sure Listener is still functional.
            clientOptions.ClientAuthenticationOptions.TargetHost = "foobar2";
            expectedCertificate = c2;

            (clientConnection, serverConnection) = await CreateConnectedQuicConnection(clientOptions, listener);

            Assert.Equal(clientOptions.ClientAuthenticationOptions.TargetHost, receivedHostName);
            Assert.Equal(c2, receivedCertificate);
            clientConnection.Dispose();
            serverConnection.Dispose();
        }
 internal Data(QuicConnection connection, QuicFlowBlockedData blockedData, QuicStream?stream = null)
 {
     Connection  = connection;
     Stream      = stream;
     BlockedData = blockedData;
 }
Example #11
0
        public async Task AcceptAsync_ClientStartsAndStopsBidirectionStream_ServerAccepts()
        {
            // 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.AcceptAsync().DefaultTimeout();

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

            await using var clientStream = quicConnection.OpenBidirectionalStream();
            await clientStream.WriteAsync(TestData);

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

            await serverStream.Transport.Output.WriteAsync(TestData);

            // Assert
            Assert.NotNull(serverStream);
            Assert.False(serverStream.ConnectionClosed.IsCancellationRequested);

            var closedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

            serverStream.ConnectionClosed.Register(() => closedTcs.SetResult());

            // Read data from client.
            var read = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

            Assert.Equal(TestData, read.Buffer.ToArray());
            serverStream.Transport.Input.AdvanceTo(read.Buffer.End);

            // Read data from server.
            var data      = new List <byte>();
            var buffer    = new byte[1024];
            var readCount = 0;

            while ((readCount = await clientStream.ReadAsync(buffer).DefaultTimeout()) != -1)
            {
                data.AddRange(buffer.AsMemory(0, readCount).ToArray());
                if (data.Count == TestData.Length)
                {
                    break;
                }
            }
            Assert.Equal(TestData, data);

            // Shutdown from client.
            clientStream.Shutdown();

            // Get shutdown from client.
            read = await serverStream.Transport.Input.ReadAsync().DefaultTimeout();

            Assert.True(read.IsCompleted);

            await closedTcs.Task.DefaultTimeout();
        }
Example #12
0
        public Http3Connection(HttpConnectionPool pool, HttpAuthority?origin, HttpAuthority authority, QuicConnection connection)
        {
            _pool       = pool;
            _origin     = origin;
            _authority  = authority;
            _connection = connection;

            bool   altUsedDefaultPort = pool.Kind == HttpConnectionKind.Http && authority.Port == HttpConnectionPool.DefaultHttpPort || pool.Kind == HttpConnectionKind.Https && authority.Port == HttpConnectionPool.DefaultHttpsPort;
            string altUsedValue       = altUsedDefaultPort ? authority.IdnHost : string.Create(CultureInfo.InvariantCulture, $"{authority.IdnHost}:{authority.Port}");

            _altUsedEncodedHeader = QPack.QPackEncoder.EncodeLiteralHeaderFieldWithoutNameReferenceToArray(KnownHeaders.AltUsed.Name, altUsedValue);

            // Errors are observed via Abort().
            _ = SendSettingsAsync();

            // This process is cleaned up when _connection is disposed, and errors are observed via Abort().
            _ = AcceptStreamsAsync();
        }
        protected override async Task <StreamPair> CreateConnectedStreamsAsync()
        {
            var listener = await QuicListener.ListenAsync(new QuicListenerOptions()
            {
                ListenEndPoint       = new IPEndPoint(IPAddress.Loopback, 0),
                ApplicationProtocols = new List <SslApplicationProtocol>()
                {
                    new SslApplicationProtocol("quictest")
                },
                ConnectionOptionsCallback = (_, _, _) => ValueTask.FromResult(new QuicServerConnectionOptions()
                {
                    DefaultStreamErrorCode      = QuicTestBase.DefaultStreamErrorCodeServer,
                    DefaultCloseErrorCode       = QuicTestBase.DefaultCloseErrorCodeServer,
                    ServerAuthenticationOptions = GetSslServerAuthenticationOptions()
                })
            });

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

            try
            {
                await WhenAllOrAnyFailed(
                    Task.Run(async() =>
                {
                    connection1 = await listener.AcceptConnectionAsync();
                    stream1     = await connection1.AcceptInboundStreamAsync();
                    Assert.Equal(1, await stream1.ReadAsync(buffer));
                }),
                    Task.Run(async() =>
                {
                    try
                    {
                        connection2 = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions()
                        {
                            DefaultStreamErrorCode      = QuicTestBase.DefaultStreamErrorCodeClient,
                            DefaultCloseErrorCode       = QuicTestBase.DefaultCloseErrorCodeClient,
                            RemoteEndPoint              = listener.LocalEndPoint,
                            ClientAuthenticationOptions = GetSslClientAuthenticationOptions()
                        });
                        stream2 = await connection2.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);
                        // OpenBidirectionalStream only allocates ID. We will force stream opening
                        // by Writing there and receiving data on the other side.
                        await stream2.WriteAsync(buffer);
                    }
                    catch (Exception ex)
                    {
                        _output?.WriteLine($"Failed to {ex.Message}");
                        throw;
                    }
                }));

                // No need to keep the listener once we have connected connection and streams
                await listener.DisposeAsync();

                var result = new StreamPairWithOtherDisposables(stream1, stream2);
                result.Disposables.Add(connection1);
                result.Disposables.Add(connection2);

                return(result);
            }
            catch
            {
                if (stream1 is not null)
                {
                    await stream1.DisposeAsync();
                }
                if (stream2 is not null)
                {
                    await stream2.DisposeAsync();
                }
                if (connection1 is not null)
                {
                    await connection1.DisposeAsync();
                }
                if (connection2 is not null)
                {
                    await connection2.DisposeAsync();
                }
                throw;
            }
        }
Example #14
0
    public async Task StreamPool_StreamAbortedOnClientAndServer_NotPooled()
    {
        // Arrange
        await using var connectionListener = await QuicTestHelpers.CreateConnectionListenerFactory(LoggerFactory);

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

        await using var clientConnection = await QuicConnection.ConnectAsync(options);

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

        var testHeartbeatFeature = new TestHeartbeatFeature();

        serverConnection.Features.Set <IConnectionHeartbeatFeature>(testHeartbeatFeature);

        // Act & Assert
        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(0, quicConnectionContext.StreamPool.Count);

        var clientStream = await clientConnection.OpenOutboundStreamAsync(QuicStreamType.Bidirectional);

        await clientStream.WriteAsync(TestData).DefaultTimeout();

        var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

        var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

        serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

        clientStream.Abort(QuicAbortDirection.Write, (long)Http3ErrorCode.InternalError);

        // Receive abort form client.
        var serverEx = await Assert.ThrowsAsync <ConnectionResetException>(() => serverStream.Transport.Input.ReadAsync().AsTask()).DefaultTimeout();

        Assert.Equal("Stream aborted by peer (258).", serverEx.Message);
        Assert.Equal((long)Http3ErrorCode.InternalError, ((QuicException)serverEx.InnerException).ApplicationErrorCode.Value);

        serverStream.Features.Get <IProtocolErrorCodeFeature>().Error = (long)Http3ErrorCode.RequestRejected;
        serverStream.Abort(new ConnectionAbortedException("Test message."));

        // Complete server.
        await serverStream.Transport.Input.CompleteAsync();

        await serverStream.Transport.Output.CompleteAsync();

        var buffer   = new byte[1024];
        var clientEx = await Assert.ThrowsAsync <QuicException>(() => clientStream.ReadAsync(buffer).AsTask()).DefaultTimeout();

        Assert.Equal(QuicError.StreamAborted, clientEx.QuicError);
        Assert.Equal((long)Http3ErrorCode.RequestRejected, clientEx.ApplicationErrorCode.Value);

        var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

        // Both send and receive loops have exited.
        await quicStreamContext._processingTask.DefaultTimeout();

        await quicStreamContext.DisposeAsync();

        Assert.Equal(0, quicConnectionContext.StreamPool.Count);
    }
Example #15
0
 private static uint ProjectProcessId(QuicConnection connection)
 {
     return(connection.ProcessId);
 }
        public async Task BidirectionalStream_ServerWritesDataAndDisposes_ClientReadsData(int dataLength)
        {
            // Arrange
            var testData = new byte[dataLength];

            for (int i = 0; i < dataLength; i++)
            {
                testData[i] = (byte)i;
            }

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

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

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

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

            // Act
            Logger.LogInformation("Client starting stream.");
            var clientStream = clientConnection.OpenBidirectionalStream();
            await clientStream.WriteAsync(TestData, endStream : true).DefaultTimeout();

            var serverStream = await serverConnection.AcceptAsync().DefaultTimeout();

            Logger.LogInformation("Server accepted stream.");
            var readResult = await serverStream.Transport.Input.ReadAtLeastAsync(TestData.Length).DefaultTimeout();

            serverStream.Transport.Input.AdvanceTo(readResult.Buffer.End);

            // Input should be completed.
            readResult = await serverStream.Transport.Input.ReadAsync().DefaultTimeout();

            Assert.True(readResult.IsCompleted);

            Logger.LogInformation("Server sending data.");
            await serverStream.Transport.Output.WriteAsync(testData).DefaultTimeout();

            Logger.LogInformation("Server completing pipes.");
            await serverStream.Transport.Input.CompleteAsync().DefaultTimeout();

            await serverStream.Transport.Output.CompleteAsync().DefaultTimeout();

            Logger.LogInformation("Client reading until end of stream.");
            var data = await clientStream.ReadUntilEndAsync().DefaultTimeout();

            Assert.Equal(testData.Length, data.Length);
            Assert.Equal(testData, data);

            var quicStreamContext = Assert.IsType <QuicStreamContext>(serverStream);

            Logger.LogInformation("Server waiting for send and receiving loops to complete.");
            await quicStreamContext._processingTask.DefaultTimeout();

            Assert.True(quicStreamContext.CanWrite);
            Assert.True(quicStreamContext.CanRead);

            Logger.LogInformation("Server disposing stream.");
            await quicStreamContext.DisposeAsync().DefaultTimeout();

            quicStreamContext.Dispose();

            var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

            Assert.Equal(1, quicConnectionContext.StreamPool.Count);
        }
Example #17
0
 private static ulong ProjectPointer(QuicConnection connection)
 {
     return(connection.Pointer);
 }
Example #18
0
        public async Task MultipleStreamsOnSingleConnection()
        {
            using QuicListener listener = CreateQuicListener();

            Task listenTask = Task.Run(async() =>
            {
                {
                    using QuicConnection connection = await listener.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(errorCode: 0);
                }
            });

            Task clientTask = Task.Run(async() =>
            {
                using QuicConnection connection = CreateQuicConnection(listener.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(errorCode: 0);
            });

            await(new[] { listenTask, clientTask }).WhenAllOrAnyFailed(millisecondsTimeout: 60000);
        }
Example #19
0
 private static string ProjectIsServer(QuicConnection connection)
 {
     return(connection.IsServer is null ? "Unknown" : connection.IsServer.ToString());
 }
Example #20
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);
            }
        }
Example #21
0
 private static ulong ProjectBytesSent(QuicConnection connection)
 {
     return(connection.BytesSent);
 }
Example #22
0
        private static async Task CreateAndTestUnidirectionalStream(QuicConnection c1, QuicConnection c2)
        {
            using QuicStream s1 = c1.OpenUnidirectionalStream();

            Assert.False(s1.CanRead);
            Assert.True(s1.CanWrite);

            ValueTask writeTask = s1.WriteAsync(s_data);

            using QuicStream s2 = await c2.AcceptStreamAsync();
            await ReceiveDataAsync(s_data, s2);

            await writeTask;

            await TestUnidirectionalStream(s1, s2);
        }
Example #23
0
 private static Timestamp ProjectTime(QuicConnection connection)
 {
     return(connection.InitialTimeStamp);
 }
Example #24
0
        public async Task MultipleReadsAndWrites()
        {
            using QuicListener listener = CreateQuicListener();

            for (int j = 0; j < 100; j++)
            {
                Task listenTask = Task.Run(async() =>
                {
                    // Connection isn't being accepted, interesting.
                    using QuicConnection connection = await listener.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(errorCode: 0);
                });

                Task clientTask = Task.Run(async() =>
                {
                    using QuicConnection connection = CreateQuicConnection(listener.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(errorCode: 0);
                });

                await(new[] { listenTask, clientTask }).WhenAllOrAnyFailed(millisecondsTimeout: 1000000);
            }
        }
Example #25
0
        private Http3LoopbackStream _outboundControlStream;     // Our outbound control stream

        public Http3LoopbackConnection(QuicConnection connection)
        {
            _connection = connection;
        }
Example #26
0
    public async Task StreamPool_Heartbeat_ExpiredStreamRemoved()
    {
        // Arrange
        var now             = new DateTimeOffset(2021, 7, 6, 12, 0, 0, TimeSpan.Zero);
        var testSystemClock = new TestSystemClock {
            UtcNow = now
        };

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

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

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

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

        var testHeartbeatFeature = new TestHeartbeatFeature();

        serverConnection.Features.Set <IConnectionHeartbeatFeature>(testHeartbeatFeature);

        // Act & Assert
        var quicConnectionContext = Assert.IsType <QuicConnectionContext>(serverConnection);

        Assert.Equal(0, quicConnectionContext.StreamPool.Count);

        var stream1 = await QuicTestHelpers.CreateAndCompleteBidirectionalStreamGracefully(clientConnection, serverConnection);

        Assert.Equal(1, quicConnectionContext.StreamPool.Count);
        QuicStreamContext pooledStream = quicConnectionContext.StreamPool._array[0];

        Assert.Same(stream1, pooledStream);
        Assert.Equal(now.Ticks + QuicConnectionContext.StreamPoolExpiryTicks, pooledStream.PoolExpirationTicks);

        now = now.AddMilliseconds(100);
        testSystemClock.UtcNow = now;
        testHeartbeatFeature.RaiseHeartbeat();
        // Not removed.
        Assert.Equal(1, quicConnectionContext.StreamPool.Count);

        var stream2 = await QuicTestHelpers.CreateAndCompleteBidirectionalStreamGracefully(clientConnection, serverConnection);

        Assert.Equal(1, quicConnectionContext.StreamPool.Count);
        pooledStream = quicConnectionContext.StreamPool._array[0];
        Assert.Same(stream1, pooledStream);
        Assert.Equal(now.Ticks + QuicConnectionContext.StreamPoolExpiryTicks, pooledStream.PoolExpirationTicks);

        Assert.Same(stream1, stream2);

        now = now.AddTicks(QuicConnectionContext.StreamPoolExpiryTicks);
        testSystemClock.UtcNow = now;
        testHeartbeatFeature.RaiseHeartbeat();
        // Not removed.
        Assert.Equal(1, quicConnectionContext.StreamPool.Count);

        now = now.AddTicks(1);
        testSystemClock.UtcNow = now;
        testHeartbeatFeature.RaiseHeartbeat();
        // Removed.
        Assert.Equal(0, quicConnectionContext.StreamPool.Count);
    }
Example #27
0
        public override async Task <GenericLoopbackConnection> EstablishGenericConnectionAsync()
        {
            QuicConnection con = await _listener.AcceptConnectionAsync().ConfigureAwait(false);

            return(new Http3LoopbackConnection(con));
        }
Example #28
0
 private static ulong ProjectId(QuicConnection connection)
 {
     return(connection.Id);
 }
Example #29
0
        public Http3Connection(HttpConnectionPool pool, HttpAuthority?origin, HttpAuthority authority, QuicConnection connection)
        {
            _pool       = pool;
            _origin     = origin;
            _authority  = authority;
            _connection = connection;

            bool   altUsedDefaultPort = pool.Kind == HttpConnectionKind.Http && authority.Port == HttpConnectionPool.DefaultHttpPort || pool.Kind == HttpConnectionKind.Https && authority.Port == HttpConnectionPool.DefaultHttpsPort;
            string altUsedValue       = altUsedDefaultPort ? authority.IdnHost : authority.IdnHost + ":" + authority.Port.ToString(Globalization.CultureInfo.InvariantCulture);

            _altUsedEncodedHeader = QPack.QPackEncoder.EncodeLiteralHeaderFieldWithoutNameReferenceToArray(KnownHeaders.AltUsed.Name, altUsedValue);

            _maximumRequestStreams = _requestStreamsRemaining = connection.GetRemoteAvailableBidirectionalStreamCount();

            // Errors are observed via Abort().
            _ = SendSettingsAsync();

            // This process is cleaned up when _connection is disposed, and errors are observed via Abort().
            _ = AcceptStreamsAsync();
        }
 protected sealed override Task QuicStreamServer(QuicConnection connection)
 {
     return(Task.CompletedTask);
 }