private async Task ProcessSends()
        {
            // Resolve `output` PipeReader via the IDuplexPipe interface prior to loop start for performance.
            var output = Output;

            while (true)
            {
                var result = await output.ReadAsync();

                if (result.IsCanceled)
                {
                    break;
                }

                var buffer = result.Buffer;

                var end         = buffer.End;
                var isCompleted = result.IsCompleted;
                if (!buffer.IsEmpty)
                {
                    _sender = _socketSenderPool.Rent();
                    await _sender.SendAsync(_socket, buffer);

                    // We don't return to the pool if there was an exception, and
                    // we keep the _sender assigned so that we can dispose it in StartAsync.
                    _socketSenderPool.Return(_sender);
                    _sender = null;
                }

                output.AdvanceTo(end);

                if (isCompleted)
                {
                    break;
                }
            }
        }
Example #2
0
        private async Task DoSend()
        {
            Exception?shutdownReason  = null;
            Exception?unexpectedError = null;

            try
            {
                while (true)
                {
                    var result = await Output.ReadAsync();

                    if (result.IsCanceled)
                    {
                        break;
                    }
                    var buffer = result.Buffer;

                    if (!buffer.IsEmpty)
                    {
                        _sender = _socketSenderPool.Rent();
                        await _sender.SendAsync(_socket, buffer);

                        // We don't return to the pool if there was an exception, and
                        // we keep the _sender assigned so that we can dispose it in StartAsync.
                        _socketSenderPool.Return(_sender);
                        _sender = null;
                    }

                    Output.AdvanceTo(buffer.End);

                    if (result.IsCompleted)
                    {
                        break;
                    }
                }
            }
            catch (SocketException ex) when(IsConnectionResetError(ex.SocketErrorCode))
            {
                shutdownReason = new ConnectionResetException(ex.Message, ex);
                _trace.ConnectionReset(this);
            }
            catch (Exception ex)
                when((ex is SocketException socketEx && IsConnectionAbortError(socketEx.SocketErrorCode)) ||
                     ex is ObjectDisposedException)
                {
                    // This should always be ignored since Shutdown() must have already been called by Abort().
                    shutdownReason = ex;
                }
            catch (Exception ex)
            {
                shutdownReason  = ex;
                unexpectedError = ex;
                _trace.ConnectionError(this, unexpectedError);
            }
            finally
            {
                Shutdown(shutdownReason);

                // Complete the output after disposing the socket
                Output.Complete(unexpectedError);

                // Cancel any pending flushes so that the input loop is un-paused
                Input.CancelPendingFlush();
            }
        }