private async Task DoReceive() { Exception error = null; try { await ProcessReceives(); } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.ConnectionReset) { error = new ConnectionResetException(ex.Message, ex); _trace.ConnectionReset(ConnectionId); } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted || ex.SocketErrorCode == SocketError.ConnectionAborted || ex.SocketErrorCode == SocketError.Interrupted || ex.SocketErrorCode == SocketError.InvalidArgument) { if (!_aborted) { // Calling Dispose after ReceiveAsync can cause an "InvalidArgument" error on *nix. error = new ConnectionAbortedException(); _trace.ConnectionError(ConnectionId, error); } } catch (ObjectDisposedException) { if (!_aborted) { error = new ConnectionAbortedException(); _trace.ConnectionError(ConnectionId, error); } } catch (IOException ex) { error = ex; _trace.ConnectionError(ConnectionId, error); } catch (Exception ex) { error = new IOException(ex.Message, ex); _trace.ConnectionError(ConnectionId, error); } finally { if (_aborted) { error = error ?? new ConnectionAbortedException(); } Input.Complete(error); } }
private async Task DoReceive() { Exception error = null; try { await ProcessReceives(); } 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) { _trace.ConnectionReset(ConnectionId); } } 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. _trace.ConnectionError(ConnectionId, error); } } catch (Exception ex) { // This is unexpected. error = ex; _trace.ConnectionError(ConnectionId, error); } finally { // If Shutdown() has already bee called, assume that was the reason ProcessReceives() exited. Input.Complete(_shutdownReason ?? error); FireConnectionClosed(); await _waitForConnectionClosedTcs.Task; } }
private async Task RunAcceptLoopAsync() { try { while (true) { for (var schedulerIndex = 0; schedulerIndex < _numSchedulers; schedulerIndex++) { try { var acceptSocket = await _listenSocket.AcceptAsync(); acceptSocket.NoDelay = _endPointInformation.NoDelay; var connection = new SocketConnection(acceptSocket, _memoryPool, _schedulers[schedulerIndex], _trace); _dispatcher.OnConnection(connection); _ = connection.StartAsync(); } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.ConnectionReset) { // REVIEW: Should there be a separate log message for a connection reset this early? _trace.ConnectionReset(connectionId: "(null)"); } catch (SocketException ex) when(!_unbinding) { _trace.ConnectionError(connectionId: "(null)", ex); } } } } catch (Exception ex) { if (_unbinding) { // Means we must be unbinding. Eat the exception. } else { _trace.LogCritical(ex, $"Unexpected exeption in {nameof(SocketTransport)}.{nameof(RunAcceptLoopAsync)}."); _listenException = ex; // Request shutdown so we can rethrow this exception // in Stop which should be observable. _appLifetime.StopApplication(); } } }
private async Task DoReceive() { Exception error = null; try { await ProcessReceives(); } catch (SocketException ex) when(IsConnectionResetError(ex.SocketErrorCode)) { // A connection reset can be reported as SocketError.ConnectionAborted on Windows if (!_aborted) { error = new ConnectionResetException(ex.Message, ex); _trace.ConnectionReset(ConnectionId); } } catch (SocketException ex) when(IsConnectionAbortError(ex.SocketErrorCode)) { if (!_aborted) { // Calling Dispose after ReceiveAsync can cause an "InvalidArgument" error on *nix. _trace.ConnectionError(ConnectionId, error); } } catch (ObjectDisposedException) { if (!_aborted) { _trace.ConnectionError(ConnectionId, error); } } catch (IOException ex) { error = ex; _trace.ConnectionError(ConnectionId, error); } catch (Exception ex) { error = new IOException(ex.Message, ex); _trace.ConnectionError(ConnectionId, error); } finally { if (_aborted) { error = error ?? _abortReason ?? new ConnectionAbortedException(); } Input.Complete(error); } }
private async Task DoReceive() { Exception error = null; try { while (true) { // Ensure we have some reasonable amount of buffer space var buffer = Input.GetMemory(MinAllocBufferSize); var bytesReceived = await _receiver.ReceiveAsync(buffer); if (bytesReceived == 0) { // FIN _trace.ConnectionReadFin(ConnectionId); break; } Input.Advance(bytesReceived); var flushTask = Input.FlushAsync(); if (!flushTask.IsCompleted) { _trace.ConnectionPause(ConnectionId); await flushTask; _trace.ConnectionResume(ConnectionId); } var result = flushTask.GetAwaiter().GetResult(); 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); _trace.ConnectionReset(ConnectionId); } catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted || ex.SocketErrorCode == SocketError.ConnectionAborted || ex.SocketErrorCode == SocketError.Interrupted || ex.SocketErrorCode == SocketError.InvalidArgument) { if (!_aborted) { // Calling Dispose after ReceiveAsync can cause an "InvalidArgument" error on *nix. error = new ConnectionAbortedException(); _trace.ConnectionError(ConnectionId, error); } } catch (ObjectDisposedException) { if (!_aborted) { error = new ConnectionAbortedException(); _trace.ConnectionError(ConnectionId, error); } } catch (IOException ex) { error = ex; _trace.ConnectionError(ConnectionId, error); } catch (Exception ex) { error = new IOException(ex.Message, ex); _trace.ConnectionError(ConnectionId, error); } finally { if (_aborted) { error = error ?? new ConnectionAbortedException(); } Input.Complete(error); } }
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 _trace.ConnectionReadFin(this); break; } Input.Advance(bytesReceived); var flushTask = Input.FlushAsync(); var paused = !flushTask.IsCompleted; if (paused) { _trace.ConnectionPause(this); } var result = await flushTask; if (paused) { _trace.ConnectionResume(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) { _trace.ConnectionReset(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. _trace.ConnectionError(this, error); } } catch (Exception ex) { // This is unexpected. error = ex; _trace.ConnectionError(this, error); } finally { // If Shutdown() has already bee called, assume that was the reason ProcessReceives() exited. Input.Complete(_shutdownReason ?? error); FireConnectionClosed(); await _waitForConnectionClosedTcs.Task; } }