|
|
@@ -49,8 +49,18 @@ namespace Renci.SshNet.Abstractions
|
|
|
|
|
|
public static Socket Connect(IPEndPoint remoteEndpoint, TimeSpan connectTimeout)
|
|
|
{
|
|
|
- var socket = new Socket(remoteEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) {NoDelay = true};
|
|
|
+ var socket = new Socket(remoteEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
|
|
|
+ ConnectCore(socket, remoteEndpoint, connectTimeout, true);
|
|
|
+ return socket;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void Connect(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout)
|
|
|
+ {
|
|
|
+ ConnectCore(socket, remoteEndpoint, connectTimeout, false);
|
|
|
+ }
|
|
|
|
|
|
+ private static void ConnectCore(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout, bool ownsSocket)
|
|
|
+ {
|
|
|
#if FEATURE_SOCKET_EAP
|
|
|
var connectCompleted = new ManualResetEvent(false);
|
|
|
var args = new SocketAsyncEventArgs
|
|
|
@@ -66,8 +76,11 @@ namespace Renci.SshNet.Abstractions
|
|
|
{
|
|
|
// avoid ObjectDisposedException in ConnectCompleted
|
|
|
args.Completed -= ConnectCompleted;
|
|
|
- // dispose Socket
|
|
|
- socket.Dispose();
|
|
|
+ if (ownsSocket)
|
|
|
+ {
|
|
|
+ // dispose Socket
|
|
|
+ socket.Dispose();
|
|
|
+ }
|
|
|
// dispose ManualResetEvent
|
|
|
connectCompleted.Dispose();
|
|
|
// dispose SocketAsyncEventArgs
|
|
|
@@ -86,8 +99,12 @@ namespace Renci.SshNet.Abstractions
|
|
|
{
|
|
|
var socketError = (int) args.SocketError;
|
|
|
|
|
|
- // dispose Socket
|
|
|
- socket.Dispose();
|
|
|
+ if (ownsSocket)
|
|
|
+ {
|
|
|
+ // dispose Socket
|
|
|
+ socket.Dispose();
|
|
|
+ }
|
|
|
+
|
|
|
// dispose SocketAsyncEventArgs
|
|
|
args.Dispose();
|
|
|
|
|
|
@@ -96,20 +113,16 @@ namespace Renci.SshNet.Abstractions
|
|
|
|
|
|
// dispose SocketAsyncEventArgs
|
|
|
args.Dispose();
|
|
|
-
|
|
|
- return socket;
|
|
|
#elif FEATURE_SOCKET_APM
|
|
|
var connectResult = socket.BeginConnect(remoteEndpoint, null, null);
|
|
|
if (!connectResult.AsyncWaitHandle.WaitOne(connectTimeout, false))
|
|
|
throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
|
|
|
"Connection failed to establish within {0:F0} milliseconds.", connectTimeout.TotalMilliseconds));
|
|
|
socket.EndConnect(connectResult);
|
|
|
- return socket;
|
|
|
#elif FEATURE_SOCKET_TAP
|
|
|
if (!socket.ConnectAsync(remoteEndpoint).Wait(connectTimeout))
|
|
|
throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
|
|
|
"Connection failed to establish within {0:F0} milliseconds.", connectTimeout.TotalMilliseconds));
|
|
|
- return socket;
|
|
|
#else
|
|
|
#error Connecting to a remote endpoint is not implemented.
|
|
|
#endif
|
|
|
@@ -311,24 +324,28 @@ namespace Renci.SshNet.Abstractions
|
|
|
/// <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>
|
|
|
+ /// <param name="readTimeout">The maximum time to wait until <paramref name="size"/> bytes have been received.</param>
|
|
|
/// <returns>
|
|
|
/// The number of bytes received.
|
|
|
/// </returns>
|
|
|
/// <remarks>
|
|
|
+ /// <para>
|
|
|
/// 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 is exceeded. If the time-out value is 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
|
|
|
+ /// </para>
|
|
|
+ /// <para>
|
|
|
+ /// 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"/>.
|
|
|
+ /// </para>
|
|
|
/// </remarks>
|
|
|
- public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeSpan timeout)
|
|
|
+ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeSpan readTimeout)
|
|
|
{
|
|
|
#if FEATURE_SOCKET_SYNC
|
|
|
var totalBytesRead = 0;
|
|
|
var totalBytesToRead = size;
|
|
|
|
|
|
- socket.ReceiveTimeout = (int) timeout.TotalMilliseconds;
|
|
|
+ socket.ReceiveTimeout = (int)readTimeout.TotalMilliseconds;
|
|
|
|
|
|
do
|
|
|
{
|
|
|
@@ -350,7 +367,7 @@ namespace Renci.SshNet.Abstractions
|
|
|
|
|
|
if (ex.SocketErrorCode == SocketError.TimedOut)
|
|
|
throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture,
|
|
|
- "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds));
|
|
|
+ "Socket read operation has timed out after {0:F0} milliseconds.", readTimeout.TotalMilliseconds));
|
|
|
|
|
|
throw;
|
|
|
}
|