| | | 1 | | using System; |
| | | 2 | | using System.Net; |
| | | 3 | | using System.Net.Sockets; |
| | | 4 | | using System.Threading; |
| | | 5 | | using System.Threading.Tasks; |
| | | 6 | | |
| | | 7 | | using Renci.SshNet.Abstractions; |
| | | 8 | | using Renci.SshNet.Common; |
| | | 9 | | using Renci.SshNet.Messages.Transport; |
| | | 10 | | |
| | | 11 | | namespace Renci.SshNet.Connection |
| | | 12 | | { |
| | | 13 | | internal abstract class ConnectorBase : IConnector |
| | | 14 | | { |
| | 2294 | 15 | | protected ConnectorBase(ISocketFactory socketFactory) |
| | 2294 | 16 | | { |
| | 2294 | 17 | | if (socketFactory is null) |
| | 0 | 18 | | { |
| | 0 | 19 | | throw new ArgumentNullException(nameof(socketFactory)); |
| | | 20 | | } |
| | | 21 | | |
| | 2294 | 22 | | SocketFactory = socketFactory; |
| | 2294 | 23 | | } |
| | | 24 | | |
| | 4570 | 25 | | internal ISocketFactory SocketFactory { get; private set; } |
| | | 26 | | |
| | | 27 | | public abstract Socket Connect(IConnectionInfo connectionInfo); |
| | | 28 | | |
| | | 29 | | public abstract Task<Socket> ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken); |
| | | 30 | | |
| | | 31 | | /// <summary> |
| | | 32 | | /// Establishes a socket connection to the specified host and port. |
| | | 33 | | /// </summary> |
| | | 34 | | /// <param name="host">The host name of the server to connect to.</param> |
| | | 35 | | /// <param name="port">The port to connect to.</param> |
| | | 36 | | /// <param name="timeout">The maximum time to wait for the connection to be established.</param> |
| | | 37 | | /// <exception cref="SshOperationTimeoutException">The connection failed to establish within the configured <see |
| | | 38 | | /// <exception cref="SocketException">An error occurred trying to establish the connection.</exception> |
| | | 39 | | protected Socket SocketConnect(string host, int port, TimeSpan timeout) |
| | 2274 | 40 | | { |
| | 2274 | 41 | | var ipAddress = DnsAbstraction.GetHostAddresses(host)[0]; |
| | 2262 | 42 | | var ep = new IPEndPoint(ipAddress, port); |
| | | 43 | | |
| | 2262 | 44 | | DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port)); |
| | | 45 | | |
| | 2262 | 46 | | var socket = SocketFactory.Create(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); |
| | | 47 | | |
| | | 48 | | try |
| | 2262 | 49 | | { |
| | 2262 | 50 | | SocketAbstraction.Connect(socket, ep, timeout); |
| | | 51 | | |
| | | 52 | | const int socketBufferSize = 10 * Session.MaximumSshPacketSize; |
| | 2178 | 53 | | socket.SendBufferSize = socketBufferSize; |
| | 2178 | 54 | | socket.ReceiveBufferSize = socketBufferSize; |
| | 2178 | 55 | | return socket; |
| | | 56 | | } |
| | 84 | 57 | | catch (Exception) |
| | 84 | 58 | | { |
| | 84 | 59 | | socket.Dispose(); |
| | 84 | 60 | | throw; |
| | | 61 | | } |
| | 2178 | 62 | | } |
| | | 63 | | |
| | | 64 | | /// <summary> |
| | | 65 | | /// Establishes a socket connection to the specified host and port. |
| | | 66 | | /// </summary> |
| | | 67 | | /// <param name="host">The host name of the server to connect to.</param> |
| | | 68 | | /// <param name="port">The port to connect to.</param> |
| | | 69 | | /// <param name="cancellationToken">The cancellation token to observe.</param> |
| | | 70 | | /// <exception cref="SshOperationTimeoutException">The connection failed to establish within the configured <see |
| | | 71 | | /// <exception cref="SocketException">An error occurred trying to establish the connection.</exception> |
| | | 72 | | protected async Task<Socket> SocketConnectAsync(string host, int port, CancellationToken cancellationToken) |
| | 8 | 73 | | { |
| | 8 | 74 | | cancellationToken.ThrowIfCancellationRequested(); |
| | | 75 | | |
| | 8 | 76 | | var ipAddress = (await DnsAbstraction.GetHostAddressesAsync(host).ConfigureAwait(false))[0]; |
| | 2 | 77 | | var ep = new IPEndPoint(ipAddress, port); |
| | | 78 | | |
| | 2 | 79 | | DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port)); |
| | | 80 | | |
| | 2 | 81 | | var socket = SocketFactory.Create(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); |
| | | 82 | | try |
| | 2 | 83 | | { |
| | 2 | 84 | | await SocketAbstraction.ConnectAsync(socket, ep, cancellationToken).ConfigureAwait(false); |
| | | 85 | | |
| | | 86 | | const int socketBufferSize = 2 * Session.MaximumSshPacketSize; |
| | 2 | 87 | | socket.SendBufferSize = socketBufferSize; |
| | 2 | 88 | | socket.ReceiveBufferSize = socketBufferSize; |
| | 2 | 89 | | return socket; |
| | | 90 | | } |
| | 0 | 91 | | catch (Exception) |
| | 0 | 92 | | { |
| | 0 | 93 | | socket.Dispose(); |
| | 0 | 94 | | throw; |
| | | 95 | | } |
| | 2 | 96 | | } |
| | | 97 | | |
| | | 98 | | protected static byte SocketReadByte(Socket socket) |
| | 282 | 99 | | { |
| | 282 | 100 | | var buffer = new byte[1]; |
| | 282 | 101 | | _ = SocketRead(socket, buffer, 0, 1, Session.InfiniteTimeSpan); |
| | 282 | 102 | | return buffer[0]; |
| | 282 | 103 | | } |
| | | 104 | | |
| | | 105 | | protected static byte SocketReadByte(Socket socket, TimeSpan readTimeout) |
| | 129 | 106 | | { |
| | 129 | 107 | | var buffer = new byte[1]; |
| | 129 | 108 | | _ = SocketRead(socket, buffer, 0, 1, readTimeout); |
| | 99 | 109 | | return buffer[0]; |
| | 99 | 110 | | } |
| | | 111 | | |
| | | 112 | | /// <summary> |
| | | 113 | | /// Performs a blocking read on the socket until <paramref name="length"/> bytes are received. |
| | | 114 | | /// </summary> |
| | | 115 | | /// <param name="socket">The <see cref="Socket"/> to read from.</param> |
| | | 116 | | /// <param name="buffer">An array of type <see cref="byte"/> that is the storage location for the received data. |
| | | 117 | | /// <param name="offset">The position in <paramref name="buffer"/> parameter to store the received data.</param> |
| | | 118 | | /// <param name="length">The number of bytes to read.</param> |
| | | 119 | | /// <returns> |
| | | 120 | | /// The number of bytes read. |
| | | 121 | | /// </returns> |
| | | 122 | | /// <exception cref="SshConnectionException">The socket is closed.</exception> |
| | | 123 | | /// <exception cref="SocketException">The read failed.</exception> |
| | | 124 | | protected static int SocketRead(Socket socket, byte[] buffer, int offset, int length) |
| | 60 | 125 | | { |
| | 60 | 126 | | return SocketRead(socket, buffer, offset, length, Session.InfiniteTimeSpan); |
| | 60 | 127 | | } |
| | | 128 | | |
| | | 129 | | /// <summary> |
| | | 130 | | /// Performs a blocking read on the socket until <paramref name="length"/> bytes are received. |
| | | 131 | | /// </summary> |
| | | 132 | | /// <param name="socket">The <see cref="Socket"/> to read from.</param> |
| | | 133 | | /// <param name="buffer">An array of type <see cref="byte"/> that is the storage location for the received data. |
| | | 134 | | /// <param name="offset">The position in <paramref name="buffer"/> parameter to store the received data.</param> |
| | | 135 | | /// <param name="length">The number of bytes to read.</param> |
| | | 136 | | /// <param name="readTimeout">The maximum time to wait until <paramref name="length"/> bytes have been received. |
| | | 137 | | /// <returns> |
| | | 138 | | /// The number of bytes read. |
| | | 139 | | /// </returns> |
| | | 140 | | /// <exception cref="SshConnectionException">The socket is closed.</exception> |
| | | 141 | | /// <exception cref="SshOperationTimeoutException">The read has timed-out.</exception> |
| | | 142 | | /// <exception cref="SocketException">The read failed.</exception> |
| | | 143 | | protected static int SocketRead(Socket socket, byte[] buffer, int offset, int length, TimeSpan readTimeout) |
| | 534 | 144 | | { |
| | 534 | 145 | | var bytesRead = SocketAbstraction.Read(socket, buffer, offset, length, readTimeout); |
| | 471 | 146 | | if (bytesRead == 0) |
| | 0 | 147 | | { |
| | 0 | 148 | | throw new SshConnectionException("An established connection was aborted by the server.", |
| | 0 | 149 | | DisconnectReason.ConnectionLost); |
| | | 150 | | } |
| | | 151 | | |
| | 471 | 152 | | return bytesRead; |
| | 471 | 153 | | } |
| | | 154 | | } |
| | | 155 | | } |