public Http3LoopbackServer(Http3Options options = null) { options ??= new Http3Options(); _cert = Configuration.Certificates.GetServerCertificate(); var listenerOptions = new QuicListenerOptions() { ListenEndPoint = new IPEndPoint(options.Address, 0), ServerAuthenticationOptions = new SslServerAuthenticationOptions { EnabledSslProtocols = options.SslProtocols, ApplicationProtocols = new List <SslApplicationProtocol> { new SslApplicationProtocol(options.Alpn) }, ServerCertificate = _cert, ClientCertificateRequired = false }, MaxUnidirectionalStreams = options.MaxUnidirectionalStreams, MaxBidirectionalStreams = options.MaxBidirectionalStreams, }; ValueTask <QuicListener> valueTask = QuicListener.ListenAsync(listenerOptions); Debug.Assert(valueTask.IsCompleted); _listener = valueTask.Result; }
protected override async Task <StreamPair> CreateConnectedStreamsAsync() { var listener = await QuicListener.ListenAsync(new QuicListenerOptions() { ListenEndPoint = new IPEndPoint(IPAddress.Loopback, 0), ServerAuthenticationOptions = 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() => { try { connection2 = await QuicConnection.ConnectAsync(new QuicClientConnectionOptions() { RemoteEndPoint = listener.ListenEndPoint, ClientAuthenticationOptions = GetSslClientAuthenticationOptions() }); await connection2.ConnectAsync(); stream2 = await connection2.OpenBidirectionalStreamAsync(); // 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 listener.Dispose(); var result = new StreamPairWithOtherDisposables(stream1, stream2); result.Disposables.Add(connection1); result.Disposables.Add(connection2); return(result); }
public async ValueTask CreateListenerAsync() { QuicLog.ConnectionListenerStarting(_log, _quicListenerOptions.ListenEndPoint); try { _listener = await QuicListener.ListenAsync(_quicListenerOptions); } catch (QuicException ex) when(ex.QuicError == QuicError.AddressInUse) { throw new AddressInUseException(ex.Message, ex); } // EndPoint could be configured with an ephemeral port of 0. // Listener endpoint will resolve an ephemeral port, e.g. 127.0.0.1:0, into the actual port // so we need to update the public listener endpoint property. EndPoint = _listener.LocalEndPoint; }
public Http3LoopbackServer(Http3Options options = null) { options ??= new Http3Options(); _cert = options.Certificate ?? Configuration.Certificates.GetServerCertificate(); var listenerOptions = new QuicListenerOptions() { ListenEndPoint = new IPEndPoint(options.Address, 0), ApplicationProtocols = new List <SslApplicationProtocol> { new SslApplicationProtocol(options.Alpn) }, ConnectionOptionsCallback = (_, _, _) => { var serverOptions = new QuicServerConnectionOptions() { DefaultStreamErrorCode = Http3LoopbackConnection.H3_REQUEST_CANCELLED, DefaultCloseErrorCode = Http3LoopbackConnection.H3_NO_ERROR, MaxInboundBidirectionalStreams = options.MaxInboundBidirectionalStreams, MaxInboundUnidirectionalStreams = options.MaxInboundUnidirectionalStreams, ServerAuthenticationOptions = new SslServerAuthenticationOptions { EnabledSslProtocols = options.SslProtocols, ApplicationProtocols = new List <SslApplicationProtocol> { new SslApplicationProtocol(options.Alpn) }, ServerCertificate = _cert, ClientCertificateRequired = false } }; return(ValueTask.FromResult(serverOptions)); } }; ValueTask <QuicListener> valueTask = QuicListener.ListenAsync(listenerOptions); Debug.Assert(valueTask.IsCompleted); _listener = valueTask.Result; }
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; } }