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 async ValueTask <MultiplexedConnectionContext?> AcceptAsync(IFeatureCollection?features = null, CancellationToken cancellationToken = default) { try { var quicConnection = await _listener.AcceptConnectionAsync(cancellationToken); var connectionContext = new QuicConnectionContext(quicConnection, _context); QuicLog.AcceptedConnection(_log, connectionContext); return(connectionContext); } catch (QuicOperationAbortedException ex) { _log.LogDebug($"Listener has aborted with exception: {ex.Message}"); } return(null); }
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; }