private void OnRead(UvStreamHandle handle, int status) { if (status == 0) { // EAGAIN/EWOULDBLOCK so just return the buffer. // http://docs.libuv.org/en/v1.x/stream.html#c.uv_read_cb Debug.Assert(_currentWritableBuffer != null); _currentWritableBuffer.Value.Commit(); } else if (status > 0) { Log.ConnectionRead(ConnectionId, status); Debug.Assert(_currentWritableBuffer != null); var currentWritableBuffer = _currentWritableBuffer.Value; currentWritableBuffer.Advance(status); var flushTask = currentWritableBuffer.FlushAsync(); if (!flushTask.IsCompleted) { // We wrote too many bytes to the reader, so pause reading and resume when // we hit the low water mark. _ = ApplyBackpressureAsync(flushTask); } } else { // Given a negative status, it's possible that OnAlloc wasn't called. _currentWritableBuffer?.Commit(); _socket.ReadStop(); IOException error = null; if (status == LibuvConstants.EOF) { Log.ConnectionReadFin(ConnectionId); } else { handle.Libuv.Check(status, out var uvError); // Log connection resets at a lower (Debug) level. if (status == LibuvConstants.ECONNRESET) { Log.ConnectionReset(ConnectionId); error = new ConnectionResetException(uvError.Message, uvError); } else { Log.ConnectionError(ConnectionId, uvError); error = new IOException(uvError.Message, uvError); } } _connectionContext.Abort(error); // Complete after aborting the connection Input.Complete(error); } // Cleanup state from last OnAlloc. This is safe even if OnAlloc wasn't called. _currentWritableBuffer = null; _bufferHandle.Free(); }
private async Task DoReceive() { Exception error = null; try { while (true) { // Ensure we have some reasonable amount of buffer space var buffer = _input.Alloc(MinAllocBufferSize); try { var bytesReceived = await _socket.ReceiveAsync(GetArraySegment(buffer.Buffer), SocketFlags.None); if (bytesReceived == 0) { // FIN break; } buffer.Advance(bytesReceived); } finally { buffer.Commit(); } var result = await buffer.FlushAsync(); if (result.IsCompleted) { // Pipe consumer is shut down, do we stop writing break; } } } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.ConnectionReset) { error = new ConnectionResetException(ex.Message, ex); } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted) { error = new ConnectionAbortedException(); } catch (ObjectDisposedException) { error = new ConnectionAbortedException(); } catch (IOException ex) { error = ex; } catch (Exception ex) { error = new IOException(ex.Message, ex); } finally { _connectionContext.Abort(error); _input.Complete(error); } }