protected async Task HandleConnectionAsync(UvStreamHandle socket) { try { IPEndPoint remoteEndPoint = null; IPEndPoint localEndPoint = null; if (socket is UvTcpHandle tcpHandle) { try { remoteEndPoint = tcpHandle.GetPeerIPEndPoint(); localEndPoint = tcpHandle.GetSockIPEndPoint(); } catch (UvException ex) when(UvConstants.IsConnectionReset(ex.StatusCode)) { Log.ConnectionReset("(null)"); socket.Dispose(); return; } } var connection = new UvConnection(socket, _thread, remoteEndPoint, localEndPoint, log: Log); await connection.Start(); await Dispatcher.OnConnection(connection); connection.Dispose(); } catch (Exception ex) { Log.LogCritical(ex, $"Unexpected exception in {nameof(UvListener)}.{nameof(HandleConnectionAsync)}."); } }
private void ConnectionCallback(UvStreamHandle listenSocket, int status, UvException error, object state) { var listener = (UvListener)state; if (error != null) { listener.Log.LogError(0, error, "Listener.ConnectionCallback"); } else if (!listener._closed) { UvStreamHandle acceptSocket = null; try { acceptSocket = CreateAcceptSocket(); listenSocket.Accept(acceptSocket); DispatchConnection(acceptSocket); } catch (UvException ex) when(UvConstants.IsConnectionReset(ex.StatusCode)) { Log.ConnectionReset("(null)"); acceptSocket?.Dispose(); } catch (UvException ex) { Log.LogError(0, ex, "Listener.OnConnection"); acceptSocket?.Dispose(); } } }
public async Task Start() { try { 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 WriteOutputAsync(); } catch (UvException ex) { // The connection reset/error has already been logged by LibuvOutputConsumer if (ex.StatusCode == UvConstants.ECANCELED) { // Connection was aborted. } else if (UvConstants.IsConnectionReset(ex.StatusCode)) { // Don't cause writes to throw for connection resets. outputError = new ConnectionResetException(ex.Message, ex); } else { inputError = ex; outputError = ex; } } finally { // Now, complete the input so that no more reads can happen _receiveFromUV.Writer.Complete(inputError ?? _abortReason ?? new ConnectionAbortedException()); _sendToUV.Reader.Complete(outputError); // Make sure it isn't possible for a paused read to resume reading after calling uv_close // on the stream handle _receiveFromUV.Writer.CancelPendingFlush(); // Send a FIN Log.ConnectionWriteFin(ConnectionId); // We're done with the socket now _socket.Dispose(); ThreadPool.QueueUserWorkItem(state => ((UvConnection)state).CancelConnectionClosedToken(), this); } } catch (Exception e) { Log.LogCritical(0, e, $"{nameof(UvConnection)}.{nameof(Start)}() {ConnectionId}"); } }
private Exception LogAndWrapReadError(UvException uvError) { if (uvError.StatusCode == UvConstants.ECANCELED) { // The operation was canceled by the server not the client. No need for additional logs. return(new ConnectionAbortedException(uvError.Message, uvError)); } else if (UvConstants.IsConnectionReset(uvError.StatusCode)) { // Log connection resets at a lower (Debug) level. Log.ConnectionReset(ConnectionId); return(new ConnectionResetException(uvError.Message, uvError)); } else { Log.ConnectionError(ConnectionId, uvError); return(new IOException(uvError.Message, uvError)); } }
private void ReadStartCallback(UvStreamHandle handle, int status) { if (status < 0) { if (status != UvConstants.EOF) { _thread.Loop.Libuv.Check(status, out var ex); Log.LogError(0, ex, "DispatchPipe.ReadStart"); } DispatchPipe.Dispose(); return; } if (_closed || DispatchPipe.PendingCount() == 0) { return; } var acceptSocket = CreateAcceptSocket(); try { DispatchPipe.Accept(acceptSocket); // REVIEW: This task should be tracked by the server for graceful shutdown // Today it's handled specifically for http but not for aribitrary middleware _ = HandleConnectionAsync(acceptSocket); } catch (UvException ex) when(UvConstants.IsConnectionReset(ex.StatusCode)) { Log.ConnectionReset("(null)"); acceptSocket.Dispose(); } catch (UvException ex) { Log.LogError(0, ex, "DispatchPipe.Accept"); acceptSocket.Dispose(); } }
private void LogWriteInfo(int status, Exception error) { if (error == null) { Log.ConnectionWriteCallback(ConnectionId, status); } else { // Log connection resets at a lower (Debug) level. if (status == UvConstants.ECANCELED) { // Connection was aborted. } else if (UvConstants.IsConnectionReset(status)) { Log.ConnectionReset(ConnectionId); } else { Log.ConnectionError(ConnectionId, error); } } }