public override async ValueTask <ConnectionContext> ConnectAsync(IFeatureCollection?features = null, CancellationToken cancellationToken = default)
    {
        QuicStream quicStream;

        var streamDirectionFeature = features?.Get <IStreamDirectionFeature>();

        if (streamDirectionFeature != null)
        {
            if (streamDirectionFeature.CanRead)
            {
                quicStream = await _connection.OpenBidirectionalStreamAsync(cancellationToken);
            }
            else
            {
                quicStream = await _connection.OpenUnidirectionalStreamAsync(cancellationToken);
            }
        }
        else
        {
            quicStream = await _connection.OpenBidirectionalStreamAsync(cancellationToken);
        }

        // Only a handful of control streams are created by the server and they last for the
        // lifetime of the connection. No value in pooling them.
        QuicStreamContext?context = new QuicStreamContext(this, _context);

        context.Initialize(quicStream);
        context.Start();

        QuicLog.ConnectedStream(_log, context);

        return(context);
    }
    public async Task ClientToServerUnidirectionalStream_CompleteWrites_PipeProvidesDataAndCompleteTogether()
    {
        // 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();

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

        // Act
        await using var clientStream = await quicConnection.OpenUnidirectionalStreamAsync();

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

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

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

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

        var readResultTask = serverStream.Transport.Input.ReadAsync();

        await clientStream.WriteAsync(TestData, endStream : true).DefaultTimeout();

        // Assert
        var completeReadResult = await readResultTask.DefaultTimeout();

        Assert.Equal(TestData, completeReadResult.Buffer.ToArray());
        Assert.True(completeReadResult.IsCompleted);
    }
Пример #3
0
    public async Task AcceptAsync_ClientStartsAndStopsUnidirectionStream_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();

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

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

        await using var clientStream = await quicConnection.OpenUnidirectionalStreamAsync();

        await clientStream.WriteAsync(TestData);

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

        // 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);

        // Shutdown client.
        clientStream.Shutdown();

        // Receive shutdown on server.
        read = await serverStream.Transport.Input.ReadAsync().DefaultTimeout();

        Assert.True(read.IsCompleted);

        await closedTcs.Task.DefaultTimeout();
    }
    public async Task ClientToServerUnidirectionalStream_ClientAbort_ServerReceivesAbort()
    {
        // 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();

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

        // Act
        await using var clientStream = await quicConnection.OpenUnidirectionalStreamAsync();

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

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

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

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

        var closedTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);

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

        clientStream.AbortWrite((long)Http3ErrorCode.InternalError);

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

        // Assert
        Assert.Equal((long)Http3ErrorCode.InternalError, ((QuicStreamAbortedException)ex.InnerException).ErrorCode);

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

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

        await closedTcs.Task.DefaultTimeout();
    }
    public async Task ClientToServerUnidirectionalStream_ServerReadsData_GracefullyClosed()
    {
        // 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();

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

        // Act
        await using var clientStream = await quicConnection.OpenUnidirectionalStreamAsync();

        await clientStream.WriteAsync(TestData, endStream : true).DefaultTimeout();

        await using 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().DefaultTimeout();

        // Assert
        Assert.True(readResult.IsCompleted);

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

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

        // Both send and receive loops have exited.
        await quicStreamContext._processingTask.DefaultTimeout();
    }
Пример #6
0
 public async ValueTask <Http3LoopbackStream> OpenUnidirectionalStreamAsync()
 {
     return(new Http3LoopbackStream(await _connection.OpenUnidirectionalStreamAsync()));
 }