public QuicConnectionListener(QuicTransportOptions options, IQuicTrace log, EndPoint endpoint, SslServerAuthenticationOptions sslServerAuthenticationOptions) { if (options.Alpn == null) { throw new InvalidOperationException("QuicTransportOptions.Alpn must be configured with a value."); } _log = log; _context = new QuicTransportContext(_log, options); var quicListenerOptions = new QuicListenerOptions(); // TODO Should HTTP/3 specific ALPN still be global? Revisit whether it can be statically set once HTTP/3 is finalized. sslServerAuthenticationOptions.ApplicationProtocols = new List <SslApplicationProtocol>() { new SslApplicationProtocol(options.Alpn) }; quicListenerOptions.ServerAuthenticationOptions = sslServerAuthenticationOptions; quicListenerOptions.ListenEndPoint = endpoint as IPEndPoint; quicListenerOptions.IdleTimeout = options.IdleTimeout; _listener = new QuicListener(QuicImplementationProviders.MsQuic, quicListenerOptions); // Listener endpoint will resolve an ephemeral port, e.g. 127.0.0.1:0, into the actual port. EndPoint = _listener.ListenEndPoint; }
public QuicConnectionListener(QuicTransportOptions options, ILogger log, EndPoint endpoint, SslServerAuthenticationOptions sslServerAuthenticationOptions) { if (!QuicImplementationProviders.Default.IsSupported) { throw new NotSupportedException("QUIC is not supported or enabled on this platform. See https://aka.ms/aspnet/kestrel/http3reqs for details."); } _log = log; _context = new QuicTransportContext(_log, options); var quicListenerOptions = new QuicListenerOptions(); var listenEndPoint = endpoint as IPEndPoint; if (listenEndPoint == null) { throw new InvalidOperationException($"QUIC doesn't support listening on the configured endpoint type. Expected {nameof(IPEndPoint)} but got {endpoint.GetType().Name}."); } quicListenerOptions.ServerAuthenticationOptions = sslServerAuthenticationOptions; quicListenerOptions.ListenEndPoint = listenEndPoint; quicListenerOptions.IdleTimeout = options.IdleTimeout; quicListenerOptions.MaxBidirectionalStreams = options.MaxBidirectionalStreamCount; quicListenerOptions.MaxUnidirectionalStreams = options.MaxUnidirectionalStreamCount; quicListenerOptions.ListenBacklog = options.Backlog; _listener = new QuicListener(quicListenerOptions); // Listener endpoint will resolve an ephemeral port, e.g. 127.0.0.1:0, into the actual port. EndPoint = _listener.ListenEndPoint; }
public QuicConnectionListener(QuicTransportOptions options, IQuicTrace log, EndPoint endpoint) { if (options.Alpn == null) { throw new InvalidOperationException("QuicTransportOptions.Alpn must be configured with a value."); } _log = log; _context = new QuicTransportContext(_log, options); EndPoint = endpoint; var quicListenerOptions = new QuicListenerOptions(); var sslConfig = new SslServerAuthenticationOptions(); sslConfig.ServerCertificate = options.Certificate; sslConfig.ApplicationProtocols = new List <SslApplicationProtocol>() { new SslApplicationProtocol(options.Alpn) }; quicListenerOptions.ServerAuthenticationOptions = sslConfig; quicListenerOptions.CertificateFilePath = options.CertificateFilePath; quicListenerOptions.PrivateKeyFilePath = options.PrivateKeyFilePath; quicListenerOptions.ListenEndPoint = endpoint as IPEndPoint; quicListenerOptions.IdleTimeout = TimeSpan.FromMinutes(2); _listener = new QuicListener(QuicImplementationProviders.MsQuic, quicListenerOptions); _listener.Start(); }
public static QuicTransportFactory CreateTransportFactory(ILoggerFactory loggerFactory = null) { var quicTransportOptions = new QuicTransportOptions(); quicTransportOptions.Alpn = Alpn; quicTransportOptions.IdleTimeout = TimeSpan.FromMinutes(1); return(new QuicTransportFactory(loggerFactory ?? NullLoggerFactory.Instance, Options.Create(quicTransportOptions))); }
public async Task BindAsync_NoFeatures_Error() { // Arrange var quicTransportOptions = new QuicTransportOptions(); var quicTransportFactory = new QuicTransportFactory(NullLoggerFactory.Instance, Options.Create(quicTransportOptions)); // Act var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => quicTransportFactory.BindAsync(new IPEndPoint(0, 0), features : null, cancellationToken : CancellationToken.None).AsTask()).DefaultTimeout(); // Assert Assert.Equal("Couldn't find HTTPS configuration for QUIC transport.", ex.Message); }
public static QuicTransportFactory CreateTransportFactory(ILoggerFactory loggerFactory = null, ISystemClock systemClock = null) { var quicTransportOptions = new QuicTransportOptions(); quicTransportOptions.IdleTimeout = TimeSpan.FromMinutes(1); quicTransportOptions.MaxBidirectionalStreamCount = 200; quicTransportOptions.MaxUnidirectionalStreamCount = 200; if (systemClock != null) { quicTransportOptions.SystemClock = systemClock; } return(new QuicTransportFactory(loggerFactory ?? NullLoggerFactory.Instance, Options.Create(quicTransportOptions))); }
public async Task BindAsync_NoApplicationProtocols_Error() { // Arrange var quicTransportOptions = new QuicTransportOptions(); var quicTransportFactory = new QuicTransportFactory(NullLoggerFactory.Instance, Options.Create(quicTransportOptions)); var features = new FeatureCollection(); features.Set(new TlsConnectionCallbackOptions()); // Act var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => quicTransportFactory.BindAsync(new IPEndPoint(0, 0), features : features, cancellationToken : CancellationToken.None).AsTask()).DefaultTimeout(); // Assert Assert.Equal("No application protocols specified for QUIC transport.", ex.Message); }
public async Task BindAsync_NoServerCertificate_Error() { // Arrange var quicTransportOptions = new QuicTransportOptions(); var quicTransportFactory = new QuicTransportFactory(NullLoggerFactory.Instance, Options.Create(quicTransportOptions)); var features = new FeatureCollection(); features.Set(new SslServerAuthenticationOptions()); // Act var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => quicTransportFactory.BindAsync(new IPEndPoint(0, 0), features : features, cancellationToken : CancellationToken.None).AsTask()).DefaultTimeout(); // Assert Assert.Equal("SslServerAuthenticationOptions must provide a server certificate using ServerCertificate, ServerCertificateContext, or ServerCertificateSelectionCallback.", ex.Message); }
public QuicConnectionListener(QuicTransportOptions options, IQuicTrace log, EndPoint endpoint) { _log = log; _context = new QuicTransportContext(_log, options); EndPoint = endpoint; var sslConfig = new SslServerAuthenticationOptions(); sslConfig.ServerCertificate = options.Certificate; sslConfig.ApplicationProtocols = new List <SslApplicationProtocol>() { new SslApplicationProtocol(options.Alpn) }; _listener = new QuicListener(QuicImplementationProviders.MsQuic, endpoint as IPEndPoint, sslConfig); _listener.Start(); }
public QuicTransportFactory(ILoggerFactory loggerFactory, IOptions <QuicTransportOptions> options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (loggerFactory == null) { throw new ArgumentNullException(nameof(loggerFactory)); } var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Quic"); _log = logger; _options = options.Value; }
public static QuicTransportFactory CreateTransportFactory( ILoggerFactory loggerFactory = null, ISystemClock systemClock = null, long defaultCloseErrorCode = 0) { var quicTransportOptions = new QuicTransportOptions(); quicTransportOptions.MaxBidirectionalStreamCount = 200; quicTransportOptions.MaxUnidirectionalStreamCount = 200; quicTransportOptions.DefaultCloseErrorCode = defaultCloseErrorCode; if (systemClock != null) { quicTransportOptions.SystemClock = systemClock; } return(new QuicTransportFactory(loggerFactory ?? NullLoggerFactory.Instance, Options.Create(quicTransportOptions))); }
public async Task BindAsync_SslServerAuthenticationOptions_Success() { // Arrange var quicTransportOptions = new QuicTransportOptions(); var quicTransportFactory = new QuicTransportFactory(NullLoggerFactory.Instance, Options.Create(quicTransportOptions)); var features = new FeatureCollection(); features.Set(new TlsConnectionCallbackOptions { ApplicationProtocols = new List <SslApplicationProtocol> { SslApplicationProtocol.Http3 } }); // Act & Assert await quicTransportFactory.BindAsync(new IPEndPoint(0, 0), features : features, cancellationToken : CancellationToken.None).AsTask().DefaultTimeout(); }
public QuicConnectionListener(QuicTransportOptions options, IQuicTrace log, EndPoint endpoint, SslServerAuthenticationOptions sslServerAuthenticationOptions) { if (!QuicImplementationProviders.Default.IsSupported) { throw new NotSupportedException("QUIC is not supported or enabled on this platform. See https://aka.ms/aspnet/kestrel/http3reqs for details."); } _log = log; _context = new QuicTransportContext(_log, options); var quicListenerOptions = new QuicListenerOptions(); quicListenerOptions.ServerAuthenticationOptions = sslServerAuthenticationOptions; quicListenerOptions.ListenEndPoint = endpoint as IPEndPoint; quicListenerOptions.IdleTimeout = options.IdleTimeout; quicListenerOptions.MaxBidirectionalStreams = options.MaxBidirectionalStreamCount; quicListenerOptions.MaxUnidirectionalStreams = options.MaxUnidirectionalStreamCount; _listener = new QuicListener(quicListenerOptions); // Listener endpoint will resolve an ephemeral port, e.g. 127.0.0.1:0, into the actual port. EndPoint = _listener.ListenEndPoint; }
public QuicTransportContext(IQuicTrace log, QuicTransportOptions options) { Log = log; Options = options; }
public QuicConnectionListener( QuicTransportOptions options, ILogger log, EndPoint endpoint, TlsConnectionCallbackOptions tlsConnectionCallbackOptions) { if (!QuicListener.IsSupported) { throw new NotSupportedException("QUIC is not supported or enabled on this platform. See https://aka.ms/aspnet/kestrel/http3reqs for details."); } if (endpoint is not IPEndPoint listenEndPoint) { throw new InvalidOperationException($"QUIC doesn't support listening on the configured endpoint type. Expected {nameof(IPEndPoint)} but got {endpoint.GetType().Name}."); } if (tlsConnectionCallbackOptions.ApplicationProtocols.Count == 0) { throw new InvalidOperationException("No application protocols specified."); } _pendingConnections = new ConditionalWeakTable <QuicConnection, QuicConnectionContext>(); _log = log; _tlsConnectionCallbackOptions = tlsConnectionCallbackOptions; _context = new QuicTransportContext(_log, options); _quicListenerOptions = new QuicListenerOptions { ApplicationProtocols = _tlsConnectionCallbackOptions.ApplicationProtocols, ListenEndPoint = listenEndPoint, ListenBacklog = options.Backlog, ConnectionOptionsCallback = async(connection, helloInfo, cancellationToken) => { // Create the connection context inside the callback because it's passed // to the connection callback. The field is then read once AcceptConnectionAsync // finishes awaiting. var currentAcceptingConnection = new QuicConnectionContext(connection, _context); _pendingConnections.Add(connection, currentAcceptingConnection); var context = new TlsConnectionCallbackContext { ClientHelloInfo = helloInfo, State = _tlsConnectionCallbackOptions.OnConnectionState, Connection = currentAcceptingConnection, }; var serverAuthenticationOptions = await _tlsConnectionCallbackOptions.OnConnection(context, cancellationToken); // If the callback didn't set protocols then use the listener's list of protocols. if (serverAuthenticationOptions.ApplicationProtocols == null) { serverAuthenticationOptions.ApplicationProtocols = _tlsConnectionCallbackOptions.ApplicationProtocols; } // If the SslServerAuthenticationOptions doesn't have a cert or protocols then the // QUIC connection will fail and the client receives an unhelpful message. // Validate the options on the server and log issues to improve debugging. ValidateServerAuthenticationOptions(serverAuthenticationOptions); var connectionOptions = new QuicServerConnectionOptions { ServerAuthenticationOptions = serverAuthenticationOptions, IdleTimeout = Timeout.InfiniteTimeSpan, // Kestrel manages connection lifetimes itself so it can send GoAway's. MaxInboundBidirectionalStreams = options.MaxBidirectionalStreamCount, MaxInboundUnidirectionalStreams = options.MaxUnidirectionalStreamCount, DefaultCloseErrorCode = options.DefaultCloseErrorCode, DefaultStreamErrorCode = options.DefaultStreamErrorCode, }; return(connectionOptions); } }; // Setting to listenEndPoint to prevent the property from being null. // This will be initialized when CreateListenerAsync() is invoked. EndPoint = listenEndPoint; }