public static async Task <QuicConnectionListener> CreateConnectionListenerFactory( TlsConnectionCallbackOptions tlsConnectionOptions, ILoggerFactory loggerFactory = null, ISystemClock systemClock = null, int port = 0) { var transportFactory = CreateTransportFactory(loggerFactory, systemClock); var endpoint = new IPEndPoint(IPAddress.Loopback, port); var features = new FeatureCollection(); features.Set(tlsConnectionOptions); return((QuicConnectionListener)await transportFactory.BindAsync(endpoint, features, cancellationToken : CancellationToken.None)); }
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; }