private void CloseInternal(Exception exception) { if (!this.IsValid) { return; } lock (this.lockObj) { try { if (!this.IsValid) { return; } this.IsValid = false; NetworkingStatisticsGroup.OnClosedSocket(this.ConnectionDirection); this.closeRegistration.Dispose(); this.closeRegistration = default; if (this.Log.IsEnabled(LogLevel.Information)) { this.Log.LogInformation( "Closing connection with remote endpoint {EndPoint}", this.RemoteEndPoint, Environment.StackTrace); } // Try to gracefully stop the reader/writer loops. this.Context.Transport.Input.CancelPendingRead(); this.Context.Transport.Output.CancelPendingFlush(); this.outgoingMessageWriter.TryComplete(); if (exception is null) { this.Context.Abort(); } else { var abortedException = exception as ConnectionAbortedException ?? new ConnectionAbortedException( $"Connection closed. See {nameof(Exception.InnerException)}", exception); this.Context.Abort(abortedException); } } catch (Exception innerException) { // Swallow any exceptions here. this.Log.LogWarning(innerException, "Exception closing connection with remote endpoint {EndPoint}: {Exception}", this.RemoteEndPoint, innerException); } } }
/// <summary> /// Close the connection. This method should only be called by <see cref="StartClosing(Exception)"/>. /// </summary> private async Task CloseAsync() { NetworkingStatisticsGroup.OnClosedSocket(this.ConnectionDirection); // Signal the outgoing message processor to exit gracefully. this.outgoingMessageWriter.TryComplete(); var transportFeature = Context.Features.Get <IUnderlyingTransportFeature>(); var transport = transportFeature?.Transport ?? _transport; transport.Input.CancelPendingRead(); transport.Output.CancelPendingFlush(); // Try to gracefully stop the reader/writer loops, if they are running. if (_processIncomingTask is { IsCompleted : false } incoming) { try { await incoming; } catch (Exception processIncomingException) { // Swallow any exceptions here. this.Log.LogWarning(processIncomingException, "Exception processing incoming messages on connection {Connection}", this); } } if (_processOutgoingTask is { IsCompleted : false } outgoing) { try { await outgoing; } catch (Exception processOutgoingException) { // Swallow any exceptions here. this.Log.LogWarning(processOutgoingException, "Exception processing outgoing messages on connection {Connection}", this); } } // Only wait for the transport to close if the connection actually started being processed. if (_processIncomingTask is not null && _processOutgoingTask is not null) { // Wait for the transport to signal that it's closed before disposing it. await _transportConnectionClosed.Task; } try { await this.Context.DisposeAsync(); } catch (Exception abortException) { // Swallow any exceptions here. this.Log.LogWarning(abortException, "Exception terminating connection {Connection}", this); } // Reject in-flight messages. foreach (var message in this.inflight) { this.OnSendMessageFailure(message, "Connection terminated"); } this.inflight.Clear(); // Reroute enqueued messages. var i = 0; while (this.outgoingMessages.Reader.TryRead(out var message)) { if (i == 0 && Log.IsEnabled(LogLevel.Information)) { this.Log.LogInformation( "Rerouting messages for remote endpoint {EndPoint}", this.RemoteEndPoint?.ToString() ?? "(never connected)"); } ++i; this.RetryMessage(message); } if (i > 0 && this.Log.IsEnabled(LogLevel.Information)) { this.Log.LogInformation( "Rerouted {Count} messages for remote endpoint {EndPoint}", i, this.RemoteEndPoint?.ToString() ?? "(never connected)"); } }
private void CloseInternal(Exception exception) { if (!this.IsValid) { return; } lock (this.lockObj) { try { if (!this.IsValid) { return; } this.IsValid = false; NetworkingStatisticsGroup.OnClosedSocket(this.ConnectionDirection); if (this.Log.IsEnabled(LogLevel.Information)) { if (exception is null) { this.Log.LogInformation( "Closing connection with remote endpoint {EndPoint}", this.RemoteEndPoint); } else { this.Log.LogInformation( exception, "Closing connection with remote endpoint {EndPoint}. Exception: {Exception}", this.RemoteEndPoint, exception); } } // Try to gracefully stop the reader/writer loops, if they are running. try { if (_processIncomingTask is Task task && !task.IsCompleted) { this.Context.Transport.Input.CancelPendingRead(); } } catch (Exception cancelException) { // Swallow any exceptions here. this.Log.LogWarning(cancelException, "Exception canceling pending read with remote endpoint {EndPoint}: {Exception}", this.RemoteEndPoint, cancelException); } try { if (_processOutgoingTask is Task task && !task.IsCompleted) { this.Context.Transport.Output.CancelPendingFlush(); } } catch (Exception cancelException) { // Swallow any exceptions here. this.Log.LogWarning(cancelException, "Exception canceling pending flush with remote endpoint {EndPoint}: {Exception}", this.RemoteEndPoint, cancelException); } this.outgoingMessageWriter.TryComplete(); if (exception is null) { this.Context.Abort(); } else { var abortedException = exception as ConnectionAbortedException ?? new ConnectionAbortedException( $"Connection closed. See {nameof(Exception.InnerException)}", exception); this.Context.Abort(abortedException); } } catch (Exception innerException) { // Swallow any exceptions here. this.Log.LogWarning(innerException, "Exception closing connection with remote endpoint {EndPoint}: {Exception}", this.RemoteEndPoint, innerException); } } }