public void ReadCallback(UvStreamHandle dispatchPipe, int status) { if (status == LibuvConstants.EOF && _bytesRead == 0) { // This is an unexpected immediate termination of the dispatch pipe most likely caused by an // external process scanning the pipe, so don't we don't log it too severely. // https://github.com/aspnet/AspNetCore/issues/4741 dispatchPipe.Dispose(); _bufHandle.Free(); _listener.Log.LogDebug("An internal pipe was opened unexpectedly."); return; } try { dispatchPipe.Libuv.ThrowIfErrored(status); _bytesRead += status; if (_bytesRead == _bufferLength) { var correctMessage = true; for (var i = 0; i < _bufferLength; i++) { if (_buf[i] != _listener._pipeMessage[i]) { correctMessage = false; } } if (correctMessage) { _listener._dispatchPipes.Add((UvPipeHandle)dispatchPipe); dispatchPipe.ReadStop(); _bufHandle.Free(); } else { throw new IOException("Bad data sent over an internal pipe."); } } } catch (Exception ex) { dispatchPipe.Dispose(); _bufHandle.Free(); _listener.Log.LogError(0, ex, "ListenerPrimary.ReadCallback"); } }
protected void 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(LibuvConstants.IsConnectionReset(ex.StatusCode)) { TransportContext.Log.ConnectionReset("(null)"); socket.Dispose(); return; } } var connection = new LibuvConnection(socket, TransportContext.Log, Thread, remoteEndPoint, localEndPoint); TransportContext.ConnectionDispatcher.OnConnection(connection); _ = connection.Start(); } catch (Exception ex) { TransportContext.Log.LogCritical(ex, $"Unexpected exception in {nameof(ListenerContext)}.{nameof(HandleConnectionAsync)}."); } }
protected internal void HandleConnection(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(LibuvConstants.IsConnectionReset(ex.StatusCode)) { TransportContext.Log.ConnectionReset("(null)"); socket.Dispose(); return; } } var options = TransportContext.Options; var connection = new LibuvConnection(socket, TransportContext.Log, Thread, remoteEndPoint, localEndPoint, InputOptions, OutputOptions, options.MaxReadBufferSize, options.MaxWriteBufferSize); connection.Start(); bool accepted = _acceptQueue.Writer.TryWrite(connection); Debug.Assert(accepted, "The connection was not written to the channel!"); } catch (Exception ex) { TransportContext.Log.LogCritical(ex, $"Unexpected exception in {nameof(ListenerContext)}.{nameof(HandleConnection)}."); } }
public async Task Start() { 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 { inputError = ex; outputError = ex; } } finally { // Now, complete the input so that no more reads can happen Input.Complete(inputError ?? _abortReason ?? new ConnectionAbortedException()); 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 Log.ConnectionWriteFin(ConnectionId); // We're done with the socket now _socket.Dispose(); ThreadPool.QueueUserWorkItem(state => ((LibuvConnection)state).CancelConnectionClosedToken(), this); } } catch (Exception e) { Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}"); } }
/// <summary> /// Handles an incoming connection /// </summary> /// <param name="listenSocket">Socket being used to listen on</param> /// <param name="status">Connection status</param> private void OnConnection(UvStreamHandle listenSocket, int status) { UvStreamHandle acceptSocket = null; try { acceptSocket = CreateAcceptSocket(); listenSocket.Accept(acceptSocket); DispatchConnection(acceptSocket); } catch (UvException ex) when(LibuvConstants.IsConnectionReset(ex.StatusCode)) { Log.ConnectionReset("(null)"); acceptSocket?.Dispose(); } catch (UvException ex) { Log.LogError(0, ex, "Listener.OnConnection"); acceptSocket?.Dispose(); } }
public async Task Start() { try { _connectionContext = ConnectionHandler.OnConnection(this); ConnectionId = _connectionContext.ConnectionId; Input = _connectionContext.Input; Output = new LibuvOutputConsumer(_connectionContext.Output, Thread, _socket, ConnectionId, Log); StartReading(); Exception error = 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 Output.WriteOutputAsync(); } catch (UvException ex) { error = new IOException(ex.Message, ex); } finally { // Now, complete the input so that no more reads can happen Input.Complete(error ?? new ConnectionAbortedException()); _connectionContext.Output.Complete(error); _connectionContext.OnConnectionClosed(error); // 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 Log.ConnectionWriteFin(ConnectionId); // We're done with the socket now _socket.Dispose(); } } catch (Exception e) { Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}"); } }
/// <summary> /// Handles an incoming connection /// </summary> /// <param name="listenSocket">Socket being used to listen on</param> /// <param name="status">Connection status</param> private void OnConnection(UvStreamHandle listenSocket, int status) { UvStreamHandle acceptSocket = null; try { acceptSocket = CreateAcceptSocket(); listenSocket.Accept(acceptSocket); DispatchConnection(acceptSocket); } catch (UvException ex) { Log.LogError(0, ex, "Listener.OnConnection"); acceptSocket?.Dispose(); } }
public void ReadCallback(UvStreamHandle dispatchPipe, int status) { try { dispatchPipe.Libuv.ThrowIfErrored(status); _bytesRead += status; if (_bytesRead == _bufferLength) { var correctMessage = true; for (var i = 0; i < _bufferLength; i++) { if (_buf[i] != _listener._pipeMessage[i]) { correctMessage = false; } } if (correctMessage) { _listener._dispatchPipes.Add((UvPipeHandle)dispatchPipe); dispatchPipe.ReadStop(); _bufHandle.Free(); } else { throw new IOException("Bad data sent over Kestrel pipe."); } } } catch (Exception ex) { dispatchPipe.Dispose(); _bufHandle.Free(); _listener.Log.LogError(0, ex, "ListenerPrimary.ReadCallback"); } }
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. Log.ConnectionError(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 Log.ConnectionWriteFin(ConnectionId, inputError.Message); // We're done with the socket now _socket.Dispose(); // Fire the connection closed token and wait for it to complete var waitForConnectionClosedTcs = new TaskCompletionSource <object>(TaskCreationOptions.RunContinuationsAsynchronously); ThreadPool.UnsafeQueueUserWorkItem(state => { (var connection, var tcs) = state; connection.CancelConnectionClosedToken(); tcs.TrySetResult(null); }, (this, waitForConnectionClosedTcs), preferLocal: false); await waitForConnectionClosedTcs.Task; } } catch (Exception e) { Log.LogCritical(0, e, $"{nameof(LibuvConnection)}.{nameof(Start)}() {ConnectionId}"); } }
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}"); } }