|  | @@ -7,6 +7,7 @@ using Renci.SshNet.Common;
 | 
	
		
			
				|  |  |  using Renci.SshNet.Messages.Transport;
 | 
	
		
			
				|  |  |  using System.Diagnostics;
 | 
	
		
			
				|  |  |  using System.Collections.Generic;
 | 
	
		
			
				|  |  | +using System.Threading;
 | 
	
		
			
				|  |  |  using Renci.SshNet.Abstractions;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace Renci.SshNet
 | 
	
	
		
			
				|  | @@ -114,17 +115,39 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |              Log(string.Format("Initiating connect to '{0}:{1}'.", ConnectionInfo.Host, ConnectionInfo.Port));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #if FEATURE_SOCKET_EAP
 | 
	
		
			
				|  |  | -            if (!_socket.ConnectAsync(ep).Wait(timeout))
 | 
	
		
			
				|  |  | -                throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | -                    "Connection failed to establish within {0:F0} milliseconds.", timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | +            var connectCompleted = new ManualResetEvent(false);
 | 
	
		
			
				|  |  | +            var connectAsyncEventArgs = new SocketAsyncEventArgs
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    RemoteEndPoint = ep,
 | 
	
		
			
				|  |  | +                };
 | 
	
		
			
				|  |  | +            connectAsyncEventArgs.Completed += (sender, args) => { connectCompleted.Set(); };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (_socket.ConnectAsync(connectAsyncEventArgs))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (!connectCompleted.WaitOne(timeout, false))
 | 
	
		
			
				|  |  | +                    throw new SshOperationTimeoutException(
 | 
	
		
			
				|  |  | +                        string.Format(
 | 
	
		
			
				|  |  | +                            CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                            "Connection failed to establish within {0:F0} milliseconds.",
 | 
	
		
			
				|  |  | +                            timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (connectAsyncEventArgs.SocketError != SocketError.Success)
 | 
	
		
			
				|  |  | +                throw new SocketException((int) connectAsyncEventArgs.SocketError);
 | 
	
		
			
				|  |  | +#elif FEATURE_SOCKET_APM
 | 
	
		
			
				|  |  |              var connectResult = _socket.BeginConnect(ep, null, null);
 | 
	
		
			
				|  |  |              if (!connectResult.AsyncWaitHandle.WaitOne(timeout, false))
 | 
	
		
			
				|  |  |                  throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  |                      "Connection failed to establish within {0:F0} milliseconds.", timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              _socket.EndConnect(connectResult);
 | 
	
		
			
				|  |  | -#endif // FEATURE_SOCKET_ASYNC_TPL
 | 
	
		
			
				|  |  | +#elif FEATURE_SOCKET_TAP
 | 
	
		
			
				|  |  | +            if (!_socket.ConnectAsync(ep).Wait(timeout))
 | 
	
		
			
				|  |  | +                throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                    "Connection failed to establish within {0:F0} milliseconds.", timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +            #error Connecting socket is not implemented.
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
	
		
			
				|  | @@ -133,6 +156,7 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |          /// <exception cref="SocketException">An error occurred when trying to access the socket.</exception>
 | 
	
		
			
				|  |  |          partial void SocketDisconnect()
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | +            // TODO should disconnect instead ?!!
 | 
	
		
			
				|  |  |              _socket.Dispose();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -148,47 +172,79 @@ namespace Renci.SshNet
 | 
	
		
			
				|  |  |              var buffer = new List<byte>();
 | 
	
		
			
				|  |  |              var data = new byte[1];
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            // read data one byte at a time to find end of line and leave any unhandled information in the buffer
 | 
	
		
			
				|  |  | -            // to be processed by subsequent invocations
 | 
	
		
			
				|  |  | -            do
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -#if FEATURE_SOCKET_TAP
 | 
	
		
			
				|  |  | -                var receiveTask = _socket.ReceiveAsync(new ArraySegment<byte>(data, 0, data.Length), SocketFlags.None);
 | 
	
		
			
				|  |  | -                if (!receiveTask.Wait(timeout))
 | 
	
		
			
				|  |  | -                    throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | -                        "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                var received = receiveTask.Result;
 | 
	
		
			
				|  |  | -#else
 | 
	
		
			
				|  |  | -                var asyncResult = _socket.BeginReceive(data, 0, data.Length, SocketFlags.None, null, null);
 | 
	
		
			
				|  |  | -                if (!asyncResult.AsyncWaitHandle.WaitOne(timeout))
 | 
	
		
			
				|  |  | -                    throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | -                        "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | +#if FEATURE_SOCKET_EAP
 | 
	
		
			
				|  |  | +            var receiveCompleted = new AutoResetEvent(false);
 | 
	
		
			
				|  |  | +            var receiveAsyncEventArgs = new SocketAsyncEventArgs { SocketFlags = SocketFlags.None };
 | 
	
		
			
				|  |  | +            receiveAsyncEventArgs.Completed += (sender, args) => receiveCompleted.Set();
 | 
	
		
			
				|  |  | +            receiveAsyncEventArgs.SetBuffer(data, 0, data.Length);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                var received = _socket.EndReceive(asyncResult);
 | 
	
		
			
				|  |  | -#endif // FEATURE_SOCKET_TAP
 | 
	
		
			
				|  |  | +#endif // FEATURE_SOCKET_EAP
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                if (received == 0)
 | 
	
		
			
				|  |  | -                    // the remote server shut down the socket
 | 
	
		
			
				|  |  | -                    break;
 | 
	
		
			
				|  |  | +            try
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                // read data one byte at a time to find end of line and leave any unhandled information in the buffer
 | 
	
		
			
				|  |  | +                // to be processed by subsequent invocations
 | 
	
		
			
				|  |  | +                do
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +#if FEATURE_SOCKET_EAP
 | 
	
		
			
				|  |  | +                    if (_socket.ReceiveAsync(receiveAsyncEventArgs))
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        if (!receiveCompleted.WaitOne(timeout))
 | 
	
		
			
				|  |  | +                            throw new SshOperationTimeoutException(
 | 
	
		
			
				|  |  | +                                string.Format(
 | 
	
		
			
				|  |  | +                                    CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                                    "Socket read operation has timed out after {0:F0} milliseconds.",
 | 
	
		
			
				|  |  | +                                    timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                buffer.Add(data[0]);
 | 
	
		
			
				|  |  | +                    var received = receiveAsyncEventArgs.BytesTransferred;
 | 
	
		
			
				|  |  | +#elif FEATURE_SOCKET_TAP
 | 
	
		
			
				|  |  | +                    var receiveTask = _socket.ReceiveAsync(new ArraySegment<byte>(data, 0, data.Length), SocketFlags.None);
 | 
	
		
			
				|  |  | +                    if (!receiveTask.Wait(timeout))
 | 
	
		
			
				|  |  | +                        throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                            "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    var received = receiveTask.Result;
 | 
	
		
			
				|  |  | +    #elif FEATURE_SOCKET_APM
 | 
	
		
			
				|  |  | +                    var asyncResult = _socket.BeginReceive(data, 0, data.Length, SocketFlags.None, null, null);
 | 
	
		
			
				|  |  | +                    if (!asyncResult.AsyncWaitHandle.WaitOne(timeout))
 | 
	
		
			
				|  |  | +                        throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
 | 
	
		
			
				|  |  | +                            "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    var received = _socket.EndReceive(asyncResult);
 | 
	
		
			
				|  |  | +    #else
 | 
	
		
			
				|  |  | +                    #error Receiving from socket is not implemented.
 | 
	
		
			
				|  |  | +    #endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    if (received == 0)
 | 
	
		
			
				|  |  | +                        // the remote server shut down the socket
 | 
	
		
			
				|  |  | +                        break;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    buffer.Add(data[0]);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                while (!(buffer.Count > 0 && (buffer[buffer.Count - 1] == LineFeed || buffer[buffer.Count - 1] == Null)));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (buffer.Count == 0)
 | 
	
		
			
				|  |  | +                    response = null;
 | 
	
		
			
				|  |  | +                else if (buffer.Count == 1 && buffer[buffer.Count - 1] == 0x00)
 | 
	
		
			
				|  |  | +                    // return an empty version string if the buffer consists of only a 0x00 character
 | 
	
		
			
				|  |  | +                    response = string.Empty;
 | 
	
		
			
				|  |  | +                else if (buffer.Count > 1 && buffer[buffer.Count - 2] == CarriageReturn)
 | 
	
		
			
				|  |  | +                    // strip trailing CRLF
 | 
	
		
			
				|  |  | +                    response = SshData.Ascii.GetString(buffer.Take(buffer.Count - 2).ToArray());
 | 
	
		
			
				|  |  | +                else if (buffer.Count > 1 && buffer[buffer.Count - 1] == LineFeed)
 | 
	
		
			
				|  |  | +                    // strip trailing LF
 | 
	
		
			
				|  |  | +                    response = SshData.Ascii.GetString(buffer.Take(buffer.Count - 1).ToArray());
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                    response = SshData.Ascii.GetString(buffer.ToArray());
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            finally
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +#if FEATURE_SOCKET_EAP
 | 
	
		
			
				|  |  | +                receiveAsyncEventArgs.Dispose();
 | 
	
		
			
				|  |  | +                receiveCompleted.Dispose();
 | 
	
		
			
				|  |  | +#endif // FEATURE_SOCKET_EAP
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            while (!(buffer.Count > 0 && (buffer[buffer.Count - 1] == LineFeed || buffer[buffer.Count - 1] == Null)));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            if (buffer.Count == 0)
 | 
	
		
			
				|  |  | -                response = null;
 | 
	
		
			
				|  |  | -            else if (buffer.Count == 1 && buffer[buffer.Count - 1] == 0x00)
 | 
	
		
			
				|  |  | -                // return an empty version string if the buffer consists of only a 0x00 character
 | 
	
		
			
				|  |  | -                response = string.Empty;
 | 
	
		
			
				|  |  | -            else if (buffer.Count > 1 && buffer[buffer.Count - 2] == CarriageReturn)
 | 
	
		
			
				|  |  | -                // strip trailing CRLF
 | 
	
		
			
				|  |  | -                response = SshData.Ascii.GetString(buffer.Take(buffer.Count - 2).ToArray());
 | 
	
		
			
				|  |  | -            else if (buffer.Count > 1 && buffer[buffer.Count - 1] == LineFeed)
 | 
	
		
			
				|  |  | -                // strip trailing LF
 | 
	
		
			
				|  |  | -                response = SshData.Ascii.GetString(buffer.Take(buffer.Count - 1).ToArray());
 | 
	
		
			
				|  |  | -            else
 | 
	
		
			
				|  |  | -                response = SshData.Ascii.GetString(buffer.ToArray());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 |