<PackageReference Include="SSH.NET" Version="2023.0.0" />

SocketAbstraction

static class SocketAbstraction
using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using System; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; namespace Renci.SshNet.Abstractions { internal static class SocketAbstraction { public static bool CanRead(Socket socket) { if (socket.Connected) { if (socket.Poll(-1, SelectMode.SelectRead)) return socket.Available > 0; return false; } return false; } public static bool CanWrite(Socket socket) { if (socket != null && socket.Connected) return socket.Poll(-1, SelectMode.SelectWrite); return false; } public static Socket Connect(IPEndPoint remoteEndpoint, TimeSpan connectTimeout) { Socket obj = new Socket(remoteEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; ConnectCore(obj, remoteEndpoint, connectTimeout, true); return obj; } public static void Connect(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout) { ConnectCore(socket, remoteEndpoint, connectTimeout, false); } [AsyncStateMachine(typeof(<ConnectAsync>d__4))] public static Task ConnectAsync(Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellationToken) { <ConnectAsync>d__4 stateMachine = default(<ConnectAsync>d__4); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.socket = socket; stateMachine.remoteEndpoint = remoteEndpoint; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } private static void ConnectCore(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout, bool ownsSocket) { ManualResetEvent manualResetEvent = new ManualResetEvent(false); SocketAsyncEventArgs socketAsyncEventArgs = new SocketAsyncEventArgs { UserToken = manualResetEvent, RemoteEndPoint = remoteEndpoint }; socketAsyncEventArgs.Completed += ConnectCompleted; if (socket.ConnectAsync(socketAsyncEventArgs) && !manualResetEvent.WaitOne(connectTimeout)) { socketAsyncEventArgs.Completed -= ConnectCompleted; if (ownsSocket) socket.Dispose(); manualResetEvent.Dispose(); socketAsyncEventArgs.Dispose(); throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0:F0} milliseconds.", connectTimeout.TotalMilliseconds)); } manualResetEvent.Dispose(); if (socketAsyncEventArgs.SocketError != 0) { SocketError socketError = socketAsyncEventArgs.SocketError; if (ownsSocket) socket.Dispose(); socketAsyncEventArgs.Dispose(); throw new SocketException((int)socketError); } socketAsyncEventArgs.Dispose(); } public static void ClearReadBuffer(Socket socket) { TimeSpan timeout = TimeSpan.FromMilliseconds(500); byte[] array = new byte[256]; int num; do { num = ReadPartial(socket, array, 0, array.Length, timeout); } while (num > 0); } public static int ReadPartial(Socket socket, byte[] buffer, int offset, int size, TimeSpan timeout) { socket.ReceiveTimeout = (int)timeout.TotalMilliseconds; try { return socket.Receive(buffer, offset, size, SocketFlags.None); } catch (SocketException ex) { 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; } } public static void ReadContinuous(Socket socket, byte[] buffer, int offset, int size, Action<byte[], int, int> processReceivedBytesAction) { socket.ReceiveTimeout = 0; while (socket.Connected) { try { int num = socket.Receive(buffer, offset, size, SocketFlags.None); if (num == 0) return; processReceivedBytesAction(buffer, offset, num); } catch (SocketException ex) { if (!IsErrorResumable(ex.SocketErrorCode)) { SocketError socketErrorCode = ex.SocketErrorCode; if (socketErrorCode != SocketError.Interrupted && (uint)(socketErrorCode - 10053) > 1) throw; return; } } } } public static int ReadByte(Socket socket, TimeSpan timeout) { byte[] array = new byte[1]; if (Read(socket, array, 0, 1, timeout) == 0) return -1; return array[0]; } public static void SendByte(Socket socket, byte value) { byte[] data = new byte[1] { value }; Send(socket, data, 0, 1); } public static byte[] Read(Socket socket, int size, TimeSpan timeout) { byte[] array = new byte[size]; Read(socket, array, 0, size, timeout); return array; } public static Task<int> ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken) { return socket.ReceiveAsync(buffer, offset, length, cancellationToken); } public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeSpan readTimeout) { int num = 0; socket.ReceiveTimeout = (int)readTimeout.TotalMilliseconds; do { try { int num2 = socket.Receive(buffer, offset + num, size - num, SocketFlags.None); if (num2 == 0) return 0; num += num2; } catch (SocketException ex) { if (!IsErrorResumable(ex.SocketErrorCode)) { if (ex.SocketErrorCode == SocketError.TimedOut) throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", readTimeout.TotalMilliseconds)); throw; } ThreadAbstraction.Sleep(30); } } while (num < size); return num; } public static void Send(Socket socket, byte[] data) { Send(socket, data, 0, data.Length); } public static void Send(Socket socket, byte[] data, int offset, int size) { int num = 0; do { try { int num2 = socket.Send(data, offset + num, size - num, SocketFlags.None); if (num2 == 0) throw new SshConnectionException("An established connection was aborted by the server.", DisconnectReason.ConnectionLost); num += num2; } catch (SocketException ex) { if (!IsErrorResumable(ex.SocketErrorCode)) throw; ThreadAbstraction.Sleep(30); } } while (num < size); } public static bool IsErrorResumable(SocketError socketError) { if (socketError == SocketError.IOPending || socketError == SocketError.WouldBlock || socketError == SocketError.NoBufferSpaceAvailable) return true; return false; } private static void ConnectCompleted(object sender, SocketAsyncEventArgs e) { ((ManualResetEvent)e.UserToken)?.Set(); } } }