/// <summary> /// Kicks off the handshake process. It doesn't propagate the result outside directly but rather stores it in a task available via <see cref="FinishHandshakeAsync"/>. /// </summary> /// <remarks> /// The method is <c>async void</c> on purpose so it starts an operation but doesn't wait for the result from the caller's perspective. /// It does await <see cref="QuicConnection.FinishHandshakeAsync"/> but that never gets propagated to the caller for which the method ends with the first asynchronously processed <c>await</c>. /// Once the asynchronous processing finishes, the result is stored in the task field that gets exposed via <see cref="FinishHandshakeAsync"/>. /// </remarks> /// <param name="connection">The new connection.</param> /// <param name="clientHello">The TLS ClientHello data.</param> /// <param name="connectionOptionsCallback">The connection options selection callback.</param> public async void StartHandshake(QuicConnection connection, SslClientHelloInfo clientHello, Func <QuicConnection, SslClientHelloInfo, CancellationToken, ValueTask <QuicServerConnectionOptions> > connectionOptionsCallback) { try { _cancellationTokenSource.CancelAfter(s_handshakeTimeout); QuicServerConnectionOptions options = await connectionOptionsCallback(connection, clientHello, _cancellationTokenSource.Token).ConfigureAwait(false); options.Validate(nameof(options)); // Validate and fill in defaults for the options. await connection.FinishHandshakeAsync(options, clientHello.ServerName, _cancellationTokenSource.Token).ConfigureAwait(false); _finishHandshakeTask.SetResult(connection); } catch (Exception ex) { // Handshake failed: // 1. Connection cannot be handed out since it's useless --> return null, listener will wait for another one. // 2. Shutdown the connection to send a transport error to the peer --> application error code doesn't matter here, use default. if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(connection, $"{connection} Connection handshake failed: {ex}"); } await connection.CloseAsync(default).ConfigureAwait(false);