private static void DoSend(Socket socket, SocketAwaitableEventArgs args, ReadOnlyMemory <byte> memory, string name)
        {
            // The BufferList getter is much less expensive then the setter.
            if (args.BufferList != null)
            {
                args.BufferList = null;
            }

#if SOCKET_STREAM_BUFFERS
            args.SetBuffer(MemoryMarshal.AsMemory(memory));
#else
            var segment = memory.GetArray();

            args.SetBuffer(segment.Array, segment.Offset, segment.Count);
#endif
            Helpers.DebugLog(name, $"## {nameof(socket.SendAsync)} {memory.Length}");
            if (socket.SendAsync(args))
            {
                Helpers.Incr(Counter.SocketSendAsyncSingleAsync);
            }
            else
            {
                Helpers.Incr(Counter.SocketSendAsyncSingleSync);
                args.Complete();
            }
        }
        private static void DoSend(Socket socket, SocketAwaitableEventArgs args, ReadOnlySequence <byte> buffer, string name)
        {
            if (buffer.IsSingleSegment)
            {
                DoSend(socket, args, buffer.First, name);
                return;
            }

#if SOCKET_STREAM_BUFFERS
            if (!args.MemoryBuffer.IsEmpty)
#else
            if (args.Buffer != null)
#endif
            {
                args.SetBuffer(null, 0, 0);
            }

            args.BufferList = GetBufferList(args, buffer);

            Helpers.DebugLog(name, $"## {nameof(socket.SendAsync)} {buffer.Length}");
            if (socket.SendAsync(args))
            {
                Helpers.Incr(Counter.SocketSendAsyncMultiAsync);
            }
            else
            {
                Helpers.Incr(Counter.SocketSendAsyncMultiSync);
                args.Complete();
            }
        }
        /// <summary>
        /// Open a new or existing socket as a client
        /// </summary>
        public static async Task <SocketConnection> ConnectAsync(
            EndPoint endpoint,
            PipeOptions sendPipeOptions, PipeOptions receivePipeOptions,
            SocketConnectionOptions connectionOptions = SocketConnectionOptions.None,
            Func <SocketConnection, Task> onConnected = null,
            Socket socket = null, string name = null)
        {
            AssertDependencies();
            var addressFamily = endpoint.AddressFamily == AddressFamily.Unspecified ? AddressFamily.InterNetwork : endpoint.AddressFamily;
            var protocolType  = addressFamily == AddressFamily.Unix ? ProtocolType.Unspecified : ProtocolType.Tcp;

            if (socket == null)
            {
                socket = new Socket(addressFamily, SocketType.Stream, protocolType);
            }
            if (sendPipeOptions == null)
            {
                sendPipeOptions = PipeOptions.Default;
            }
            if (receivePipeOptions == null)
            {
                receivePipeOptions = PipeOptions.Default;
            }

            SetRecommendedClientOptions(socket);

            using (var args = new SocketAwaitableEventArgs((connectionOptions & SocketConnectionOptions.InlineConnect) == 0 ? PipeScheduler.ThreadPool : null))
            {
                args.RemoteEndPoint = endpoint;
                Helpers.DebugLog(name, $"connecting to {endpoint}...");

                if (!socket.ConnectAsync(args))
                {
                    args.Complete();
                }
                await args;
            }

            Helpers.DebugLog(name, "connected");

            var connection = Create(socket, sendPipeOptions, receivePipeOptions, connectionOptions, name);

            if (onConnected != null)
            {
                await onConnected(connection).ConfigureAwait(false);
            }

            return(connection);
        }
        private async Task DoReceiveAsync()
        {
            Exception error = null;

            DebugLog("starting receive loop");
            try
            {
                _readerArgs = new SocketAwaitableEventArgs(InlineReads ? null : _receiveOptions.WriterScheduler);
                while (true)
                {
                    if (ZeroLengthReads && Socket.Available == 0)
                    {
                        DebugLog($"awaiting zero-length receive...");

                        Helpers.Incr(Counter.OpenReceiveReadAsync);
                        DoReceive(Socket, _readerArgs, default, Name);
        private async Task DoSendAsync()
        {
            Exception error = null;

            DebugLog("starting send loop");
            try
            {
                while (true)
                {
                    DebugLog("awaiting data from pipe...");
                    if (_sendToSocket.Reader.TryRead(out var result))
                    {
                        Helpers.Incr(Counter.SocketPipeReadReadSync);
                    }
                    else
                    {
                        Helpers.Incr(Counter.OpenSendReadAsync);
                        var read = _sendToSocket.Reader.ReadAsync();
                        Helpers.Incr(read.IsCompleted ? Counter.SocketPipeReadReadSync : Counter.SocketPipeReadReadAsync);
                        result = await read;
                        Helpers.Decr(Counter.OpenSendReadAsync);
                    }
                    var buffer = result.Buffer;

                    if (result.IsCanceled || (result.IsCompleted && buffer.IsEmpty))
                    {
                        DebugLog(result.IsCanceled ? "cancelled" : "complete");
                        break;
                    }

                    try
                    {
                        if (!buffer.IsEmpty)
                        {
                            if (_writerArgs == null)
                            {
                                _writerArgs = new SocketAwaitableEventArgs(InlineWrites ? null : _sendOptions.ReaderScheduler);
                            }
                            DebugLog($"sending {buffer.Length} bytes over socket...");
                            Helpers.Incr(Counter.OpenSendWriteAsync);
                            DoSend(Socket, _writerArgs, buffer, Name);
                            Helpers.Incr(_writerArgs.IsCompleted ? Counter.SocketSendAsyncSync : Counter.SocketSendAsyncAsync);
                            BytesSent += await _writerArgs;
                            Helpers.Decr(Counter.OpenSendWriteAsync);
                        }
                        else if (result.IsCompleted)
                        {
                            DebugLog("completed");
                            break;
                        }
                    }
                    finally
                    {
                        DebugLog("advancing");
                        _sendToSocket.Reader.AdvanceTo(buffer.End);
                    }
                }
                TrySetShutdown(PipeShutdownKind.WriteEndOfStream);
            }
            catch (SocketException ex) when(ex.SocketErrorCode == SocketError.OperationAborted)
            {
                TrySetShutdown(PipeShutdownKind.WriteSocketError, ex.SocketErrorCode);
                DebugLog($"fail: {ex.SocketErrorCode}");
                error = null;
            }
            catch (SocketException ex)
            {
                TrySetShutdown(PipeShutdownKind.WriteSocketError, ex.SocketErrorCode);
                DebugLog($"fail: {ex.SocketErrorCode}");
                error = ex;
            }
            catch (ObjectDisposedException)
            {
                TrySetShutdown(PipeShutdownKind.WriteDisposed);
                DebugLog("fail: disposed");
                error = null;
            }
            catch (IOException ex)
            {
                TrySetShutdown(PipeShutdownKind.WriteIOException);
                DebugLog($"fail - io: {ex.Message}");
                error = ex;
            }
            catch (Exception ex)
            {
                TrySetShutdown(PipeShutdownKind.WriteException);
                DebugLog($"fail: {ex.Message}");
                error = new IOException(ex.Message, ex);
            }
            finally
            {
                // Make sure to close the connection only after the _aborted flag is set.
                // Without this, the RequestsCanBeAbortedMidRead test will sometimes fail when
                // a BadHttpRequestException is thrown instead of a TaskCanceledException.
                _sendAborted = true;
                try
                {
                    DebugLog($"shutting down socket-send");
                    Socket.Shutdown(SocketShutdown.Send);
                }
                catch { }

                // close *both halves* of the send pipe; we're not
                // listening *and* we don't want anyone trying to write
                DebugLog($"marking {nameof(Output)} as complete");
                try { _sendToSocket.Writer.Complete(error); } catch { }
                try { _sendToSocket.Reader.Complete(error); } catch { }

                var args = _writerArgs;
                _writerArgs = null;
                if (args != null)
                {
                    try { args.Dispose(); } catch { }
                }
            }
            DebugLog(error == null ? "exiting with success" : $"exiting with failure: {error.Message}");
            //return error;
        }
 private static void DoSend(Socket socket, SocketAwaitableEventArgs args, in ReadOnlySequence <byte> buffer, string name)