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 QuicStreamContext(QuicConnectionContext connection, QuicTransportContext context) { _connection = connection; _context = context; _log = context.Log; MemoryPool = connection.MemoryPool; MultiplexedConnectionFeatures = connection.Features; RemoteEndPoint = connection.RemoteEndPoint; LocalEndPoint = connection.LocalEndPoint; var maxReadBufferSize = context.Options.MaxReadBufferSize ?? 0; var maxWriteBufferSize = context.Options.MaxWriteBufferSize ?? 0; // TODO should we allow these PipeScheduler to be configurable here? var inputOptions = new PipeOptions(MemoryPool, PipeScheduler.ThreadPool, PipeScheduler.Inline, maxReadBufferSize, maxReadBufferSize / 2, useSynchronizationContext: false); var outputOptions = new PipeOptions(MemoryPool, PipeScheduler.Inline, PipeScheduler.ThreadPool, maxWriteBufferSize, maxWriteBufferSize / 2, useSynchronizationContext: false); _inputPipe = new Pipe(inputOptions); _outputPipe = new Pipe(outputOptions); _transportPipeReader = new CompletionPipeReader(_inputPipe.Reader); _transportPipeWriter = new CompletionPipeWriter(_outputPipe.Writer); _originalApplication = new DuplexPipe(_outputPipe.Reader, _inputPipe.Writer); _originalTransport = new DuplexPipe(_transportPipeReader, _transportPipeWriter); }
public QuicConnectionFactory(IOptions <QuicTransportOptions> options, ILoggerFactory loggerFactory) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var logger = loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Quic.Client"); _transportContext = new QuicTransportContext(logger, options.Value); }
public QuicConnectionContext(QuicConnection connection, QuicTransportContext context) { _log = context.Log; _context = context; _connection = connection; ConnectionClosed = _connectionClosedTokenSource.Token; StreamPool = new PooledStreamStack <QuicStreamContext>(InitialStreamPoolSize); RemoteEndPoint = connection.RemoteEndPoint; LocalEndPoint = connection.LocalEndPoint; InitializeFeatures(); }
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; }