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}"); } }
private async Task DoSend() { Exception error = null; try { while (true) { // Wait for data to write from the pipe producer var result = await _output.ReadAsync(); var buffer = result.Buffer; if (result.IsCancelled) { break; } try { if (!buffer.IsEmpty) { if (buffer.IsSingleSpan) { await _socket.SendAsync(GetArraySegment(buffer.First), SocketFlags.None); } else { SetupSendBuffers(buffer); try { await _socket.SendAsync(_sendBufferList, SocketFlags.None); } finally { _sendBufferList.Clear(); } } } else if (result.IsCompleted) { break; } } finally { _output.Advance(buffer.End); } } _socket.Shutdown(SocketShutdown.Send); } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted) { error = null; } catch (ObjectDisposedException) { error = null; } catch (IOException ex) { error = ex; } catch (Exception ex) { error = new IOException(ex.Message, ex); } finally { _connectionContext.OnConnectionClosed(error); _output.Complete(error); } }