private async Task ProcessReceives() { while (true) { // Ensure we have some reasonable amount of buffer space var buffer = _application.Output.GetMemory(); var bytesReceived = await _receiver.ReceiveAsync(buffer); if (bytesReceived == 0) { // FIN break; } _application.Output.Advance(bytesReceived); var flushTask = _application.Output.FlushAsync(); if (!flushTask.IsCompleted) { await flushTask; } var result = flushTask.GetAwaiter().GetResult(); if (result.IsCompleted) { // Pipe consumer is shut down, do we stop writing break; } } }
private async Task ProcessReceives() { while (true) { var buffer = _application.Output.GetMemory(); var bytesReceived = await _receiver.ReceiveAsync(buffer); if (bytesReceived == 0) { break; } _application.Output.Advance(bytesReceived); var flushTask = _application.Output.FlushAsync(); if (!flushTask.IsCompleted) { await flushTask.ConfigureAwait(false); } var result = flushTask.Result; if (result.IsCompleted) { break; } } }
private async ValueTask <bool> WaitForDisconnect(Socket socket, CancellationToken cancellationToken) { var receiveBufferBytes = m_arrayPool.Rent(1); try { var socketReceiver = new SocketReceiver(socket); var receiveCount = await socketReceiver.ReceiveAsync(receiveBufferBytes, cancellationToken).ConfigureAwait(false); return(receiveCount <= 0); } catch (SocketException socketException) when(socketException.SocketErrorCode == SocketError.ConnectionReset) { return(true); } catch (SocketException) { return(false); } finally { m_arrayPool.Return(receiveBufferBytes); } }
private async Task DoReceive() { Exception?error = null; try { while (true) { if (_waitForData) { // Wait for data before allocating a buffer. await _receiver.WaitForDataAsync(_socket); } // Ensure we have some reasonable amount of buffer space var buffer = Input.GetMemory(MinAllocBufferSize); var bytesReceived = await _receiver.ReceiveAsync(_socket, buffer); if (bytesReceived == 0) { // FIN SocketsLog.ConnectionReadFin(_logger, this); break; } Input.Advance(bytesReceived); var flushTask = Input.FlushAsync(); var paused = !flushTask.IsCompleted; if (paused) { SocketsLog.ConnectionPause(_logger, this); } var result = await flushTask; if (paused) { SocketsLog.ConnectionResume(_logger, this); } if (result.IsCompleted || result.IsCanceled) { // Pipe consumer is shut down, do we stop writing break; } } } catch (SocketException ex) when(IsConnectionResetError(ex.SocketErrorCode)) { // This could be ignored if _shutdownReason is already set. error = new ConnectionResetException(ex.Message, ex); // There's still a small chance that both DoReceive() and DoSend() can log the same connection reset. // Both logs will have the same ConnectionId. I don't think it's worthwhile to lock just to avoid this. if (!_socketDisposed) { SocketsLog.ConnectionReset(_logger, this); } } catch (Exception ex) when((ex is SocketException socketEx && IsConnectionAbortError(socketEx.SocketErrorCode)) || ex is ObjectDisposedException) { // This exception should always be ignored because _shutdownReason should be set. error = ex; if (!_socketDisposed) { // This is unexpected if the socket hasn't been disposed yet. SocketsLog.ConnectionError(_logger, this, error); } } catch (Exception ex) { // This is unexpected. error = ex; SocketsLog.ConnectionError(_logger, this, error); } finally { // If Shutdown() has already bee called, assume that was the reason ProcessReceives() exited. Input.Complete(_shutdownReason ?? error); FireConnectionClosed(); await _waitForConnectionClosedTcs.Task; } }