private Exception LogAndWrapReadError(UvException uvError) { if (uvError.StatusCode == LibuvConstants.ECANCELED) { // The operation was canceled by the server not the client. No need for additional logs. return(new ConnectionAbortedException(uvError.Message, uvError)); } else if (LibuvConstants.IsConnectionReset(uvError.StatusCode)) { // Log connection resets at a lower (Debug) level. LibuvTrace.ConnectionReset(Log, ConnectionId); return(new ConnectionResetException(uvError.Message, uvError)); } else { // This is unexpected. LibuvTrace.ConnectionError(Log, ConnectionId, uvError); return(new IOException(uvError.Message, uvError)); } }
private void LogWriteInfo(int status, Exception error) { if (error == null) { LibuvTrace.ConnectionWriteCallback(_log, _connectionId, status); } else { // Log connection resets at a lower (Debug) level. if (status == LibuvConstants.ECANCELED) { // Connection was aborted. } else if (LibuvConstants.IsConnectionReset(status)) { LibuvTrace.ConnectionReset(_log, _connectionId); } else { LibuvTrace.ConnectionError(_log, _connectionId, error); } } }
private async Task StartCore() { try { OutputConsumer = new LibuvOutputConsumer(Output, Thread, _socket, ConnectionId, Log); StartReading(); Exception inputError = null; Exception outputError = null; try { // This *must* happen after socket.ReadStart // The socket output consumer is the only thing that can close the connection. If the // output pipe is already closed by the time we start then it's fine since, it'll close gracefully afterwards. await OutputConsumer.WriteOutputAsync(); } catch (UvException ex) { // The connection reset/error has already been logged by LibuvOutputConsumer if (ex.StatusCode == LibuvConstants.ECANCELED) { // Connection was aborted. } else if (LibuvConstants.IsConnectionReset(ex.StatusCode)) { // Don't cause writes to throw for connection resets. inputError = new ConnectionResetException(ex.Message, ex); } else { // This is unexpected. LibuvTrace.ConnectionError(Log, ConnectionId, ex); inputError = ex; outputError = ex; } } finally { inputError ??= _abortReason ?? new ConnectionAbortedException("The libuv transport's send loop completed gracefully."); // Now, complete the input so that no more reads can happen Input.Complete(inputError); Output.Complete(outputError); // Make sure it isn't possible for a paused read to resume reading after calling uv_close // on the stream handle Input.CancelPendingFlush(); // Send a FIN LibuvTrace.ConnectionWriteFin(Log, ConnectionId, inputError.Message); // We're done with the socket now _socket.Dispose(); // Ensure this always fires FireConnectionClosed(); await _waitForConnectionClosedTcs.Task; } } catch (Exception e) { Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}"); } }