Ejemplo n.º 1
0
        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);
                }
            }
        }
Ejemplo n.º 2
0
        /// <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)");
            }
        }
Ejemplo n.º 3
0
        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);
                }
            }
        }