public void Process(SocketAsyncEventArgs args)
            {
                if (args.SocketError == SocketError.Success)
                {
                    if (args.BytesTransferred == 0)
                    {
                        // remote socket was closed
                        _completionWaitHandle.Set();
                        return;
                    }

                    _processReceivedBytesAction(args.Buffer, args.Offset, args.BytesTransferred);
                    ResumeOperation(args);
                    return;
                }

                if (IsErrorResumable(args.SocketError))
                {
                    ThreadAbstraction.Sleep(30);
                    ResumeOperation(args);
                    return;
                }

                if (args.SocketError != SocketError.OperationAborted)
                {
                    Exception = new SocketException((int)args.SocketError);
                }

                // we're dealing with a (fatal) error
                _completionWaitHandle.Set();
            }
            public void Process(SocketAsyncEventArgs args)
            {
                if (args.SocketError == SocketError.Success)
                {
                    _completionWaitHandle.Set();
                    return;
                }

                if (IsErrorResumable(args.SocketError))
                {
                    ThreadAbstraction.Sleep(30);
                    ResumeOperation(args);
                    return;
                }

                // we're dealing with a (fatal) error
                _completionWaitHandle.Set();
            }
            public void Process(SocketAsyncEventArgs args)
            {
                if (args.SocketError == SocketError.Success)
                {
                    TotalBytesTransferred += args.BytesTransferred;

                    if (TotalBytesTransferred == _bytesToTransfer)
                    {
                        // finished transferring specified bytes
                        _completionWaitHandle.Set();
                        return;
                    }

                    if (args.BytesTransferred == 0)
                    {
                        // remote server closed the connection
                        _completionWaitHandle.Set();
                        return;
                    }

                    _offset += args.BytesTransferred;
                    args.SetBuffer(_buffer, _offset, _bytesToTransfer - TotalBytesTransferred);
                    ResumeOperation(args);
                    return;
                }

                if (IsErrorResumable(args.SocketError))
                {
                    ThreadAbstraction.Sleep(30);
                    ResumeOperation(args);
                    return;
                }

                // we're dealing with a (fatal) error
                _completionWaitHandle.Set();
            }
        public static void Send(Socket socket, byte[] data, int offset, int size)
        {
#if FEATURE_SOCKET_SYNC
            var totalBytesSent   = 0; // how many bytes are already sent
            var totalBytesToSend = size;

            do
            {
                try
                {
                    var bytesSent = socket.Send(data, offset + totalBytesSent, totalBytesToSend - totalBytesSent,
                                                SocketFlags.None);
                    if (bytesSent == 0)
                    {
                        throw new SshConnectionException("An established connection was aborted by the server.",
                                                         DisconnectReason.ConnectionLost);
                    }

                    totalBytesSent += bytesSent;
                }
                catch (SocketException ex)
                {
                    if (IsErrorResumable(ex.SocketErrorCode))
                    {
                        // socket buffer is probably full, wait and try again
                        ThreadAbstraction.Sleep(30);
                    }
                    else
                    {
                        throw;  // any serious error occurr
                    }
                }
            } while (totalBytesSent < totalBytesToSend);
#elif FEATURE_SOCKET_EAP
            var sendCompleted       = new ManualResetEvent(false);
            var sendReceiveToken    = new BlockingSendReceiveToken(socket, data, offset, size, sendCompleted);
            var socketAsyncSendArgs = new SocketAsyncEventArgs
            {
                RemoteEndPoint = socket.RemoteEndPoint,
                UserToken      = sendReceiveToken
            };
            socketAsyncSendArgs.SetBuffer(data, offset, size);
            socketAsyncSendArgs.Completed += SendCompleted;

            try
            {
                if (socket.SendAsync(socketAsyncSendArgs))
                {
                    if (!sendCompleted.WaitOne())
                    {
                        throw new SocketException((int)SocketError.TimedOut);
                    }
                }

                if (socketAsyncSendArgs.SocketError != SocketError.Success)
                {
                    throw new SocketException((int)socketAsyncSendArgs.SocketError);
                }

                if (sendReceiveToken.TotalBytesTransferred == 0)
                {
                    throw new SshConnectionException("An established connection was aborted by the server.",
                                                     DisconnectReason.ConnectionLost);
                }
            }
            finally
            {
                // initialize token to avoid the completion waithandle getting used after it's disposed
                socketAsyncSendArgs.UserToken = null;
                socketAsyncSendArgs.Dispose();
                sendCompleted.Dispose();
            }
#else
#error Sending data to a Socket is not implemented.
#endif
        }
        /// <summary>
        /// Receives data from a bound <see cref="Socket"/>into a receive buffer.
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="buffer">An array of type <see cref="byte"/> that is the storage location for the received data. </param>
        /// <param name="offset">The position in <paramref name="buffer"/> parameter to store the received data.</param>
        /// <param name="size">The number of bytes to receive.</param>
        /// <param name="timeout">Specifies the amount of time after which the call will time out.</param>
        /// <returns>
        /// The number of bytes received.
        /// </returns>
        /// <remarks>
        /// If no data is available for reading, the <see cref="Read(Socket,byte[], int, int, TimeSpan)"/> method will
        /// block until data is available or the time-out value was exceeded. If the time-out value was exceeded, the
        /// <see cref="Read(Socket,byte[], int, int, TimeSpan)"/> call will throw a <see cref="SshOperationTimeoutException"/>.
        ///  If you are in non-blocking mode, and there is no data available in the in the protocol stack buffer, the
        /// <see cref="Read(Socket,byte[], int, int, TimeSpan)"/> method will complete immediately and throw a <see cref="SocketException"/>.
        /// </remarks>
        public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeSpan timeout)
        {
#if FEATURE_SOCKET_SYNC
            var totalBytesRead   = 0;
            var totalBytesToRead = size;

            socket.ReceiveTimeout = (int)timeout.TotalMilliseconds;

            do
            {
                try
                {
                    var bytesRead = socket.Receive(buffer, offset + totalBytesRead, totalBytesToRead - totalBytesRead, SocketFlags.None);
                    if (bytesRead == 0)
                    {
                        return(0);
                    }

                    totalBytesRead += bytesRead;
                }
                catch (SocketException ex)
                {
                    if (IsErrorResumable(ex.SocketErrorCode))
                    {
                        ThreadAbstraction.Sleep(30);
                        continue;
                    }

                    if (ex.SocketErrorCode == SocketError.TimedOut)
                    {
                        throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
                                                                             "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds));
                    }

                    throw;
                }
            }while (totalBytesRead < totalBytesToRead);

            return(totalBytesRead);
#elif FEATURE_SOCKET_EAP
            var receiveCompleted = new ManualResetEvent(false);
            var sendReceiveToken = new BlockingSendReceiveToken(socket, buffer, offset, size, receiveCompleted);

            var args = new SocketAsyncEventArgs
            {
                UserToken      = sendReceiveToken,
                RemoteEndPoint = socket.RemoteEndPoint
            };
            args.Completed += ReceiveCompleted;
            args.SetBuffer(buffer, offset, size);

            try
            {
                if (socket.ReceiveAsync(args))
                {
                    if (!receiveCompleted.WaitOne(timeout))
                    {
                        throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
                                                                             "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds));
                    }
                }

                if (args.SocketError != SocketError.Success)
                {
                    throw new SocketException((int)args.SocketError);
                }

                return(sendReceiveToken.TotalBytesTransferred);
            }
            finally
            {
                // initialize token to avoid the waithandle getting used after it's disposed
                args.UserToken = null;
                args.Dispose();
                receiveCompleted.Dispose();
            }
#else
#error Receiving data from a Socket is not implemented.
#endif
        }