Extensions.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Globalization;
  5. using System.Linq;
  6. using System.Net;
  7. using System.Net.Sockets;
  8. using System.Text;
  9. using Renci.SshNet.Abstractions;
  10. using Renci.SshNet.Common;
  11. using Renci.SshNet.Messages;
  12. using Renci.SshNet.Messages.Connection;
  13. namespace Renci.SshNet
  14. {
  15. /// <summary>
  16. /// Collection of different extension method
  17. /// </summary>
  18. internal static partial class Extensions
  19. {
  20. /// <summary>
  21. /// Determines whether [is null or white space] [the specified value].
  22. /// </summary>
  23. /// <param name="value">The value.</param>
  24. /// <returns>
  25. /// <c>true</c> if [is null or white space] [the specified value]; otherwise, <c>false</c>.
  26. /// </returns>
  27. public static bool IsNullOrWhiteSpace(this string value)
  28. {
  29. if (string.IsNullOrEmpty(value)) return true;
  30. return value.All(char.IsWhiteSpace);
  31. }
  32. internal static byte[] ToArray(this GlobalRequestName globalRequestName)
  33. {
  34. switch (globalRequestName)
  35. {
  36. case GlobalRequestName.TcpIpForward:
  37. return SshData.Ascii.GetBytes("tcpip-forward");
  38. case GlobalRequestName.CancelTcpIpForward:
  39. return SshData.Ascii.GetBytes("cancel-tcpip-forward");
  40. default:
  41. throw new NotSupportedException(string.Format("Global request name '{0}' is not supported.", globalRequestName));
  42. }
  43. }
  44. internal static byte[] ToArray(this ServiceName serviceName)
  45. {
  46. switch (serviceName)
  47. {
  48. case ServiceName.UserAuthentication:
  49. return SshData.Ascii.GetBytes("ssh-userauth");
  50. case ServiceName.Connection:
  51. return SshData.Ascii.GetBytes("ssh-connection");
  52. default:
  53. throw new NotSupportedException(string.Format("Service name '{0}' is not supported.", serviceName));
  54. }
  55. }
  56. internal static ServiceName ToServiceName(this byte[] data)
  57. {
  58. var sshServiceName = SshData.Ascii.GetString(data, 0, data.Length);
  59. switch (sshServiceName)
  60. {
  61. case "ssh-userauth":
  62. return ServiceName.UserAuthentication;
  63. case "ssh-connection":
  64. return ServiceName.Connection;
  65. default:
  66. throw new NotSupportedException(string.Format("Service name '{0}' is not supported.", sshServiceName));
  67. }
  68. }
  69. internal static GlobalRequestName ToGlobalRequestName(this byte[] data)
  70. {
  71. var sshGlobalRequestName = SshData.Ascii.GetString(data, 0, data.Length);
  72. switch (sshGlobalRequestName)
  73. {
  74. case "tcpip-forward":
  75. return GlobalRequestName.TcpIpForward;
  76. case "cancel-tcpip-forward":
  77. return GlobalRequestName.CancelTcpIpForward;
  78. default:
  79. throw new NotSupportedException(string.Format("Global request name '{0}' is not supported.", sshGlobalRequestName));
  80. }
  81. }
  82. internal static BigInteger ToBigInteger(this byte[] data)
  83. {
  84. var reversed = new byte[data.Length];
  85. Buffer.BlockCopy(data, 0, reversed, 0, data.Length);
  86. return new BigInteger(reversed.Reverse());
  87. }
  88. /// <summary>
  89. /// Reverses the sequence of the elements in the entire one-dimensional <see cref="Array"/>.
  90. /// </summary>
  91. /// <param name="array">The one-dimensional <see cref="Array"/> to reverse.</param>
  92. /// <returns>
  93. /// The <see cref="Array"/> with its elements reversed.
  94. /// </returns>
  95. internal static T[] Reverse<T>(this T[] array)
  96. {
  97. Array.Reverse(array);
  98. return array;
  99. }
  100. /// <summary>
  101. /// Prints out
  102. /// </summary>
  103. /// <param name="bytes">The bytes.</param>
  104. internal static void DebugPrint(this IEnumerable<byte> bytes)
  105. {
  106. var sb = new StringBuilder();
  107. foreach (var b in bytes)
  108. {
  109. sb.AppendFormat(CultureInfo.CurrentCulture, "0x{0:x2}, ", b);
  110. }
  111. Debug.WriteLine(sb.ToString());
  112. }
  113. /// <summary>
  114. /// Creates an instance of the specified type using that type's default constructor.
  115. /// </summary>
  116. /// <typeparam name="T">The type to create.</typeparam>
  117. /// <param name="type">Type of the instance to create.</param>
  118. /// <returns>A reference to the newly created object.</returns>
  119. internal static T CreateInstance<T>(this Type type) where T : class
  120. {
  121. if (type == null)
  122. return null;
  123. return Activator.CreateInstance(type) as T;
  124. }
  125. /// <summary>
  126. /// Returns the specified 16-bit unsigned integer value as an array of bytes.
  127. /// </summary>
  128. /// <param name="value">The number to convert.</param>
  129. /// <returns>An array of bytes with length 2.</returns>
  130. internal static byte[] GetBytes(this ushort value)
  131. {
  132. return new[] {(byte) (value >> 8), (byte) (value & 0xFF)};
  133. }
  134. /// <summary>
  135. /// Returns the specified 32-bit unsigned integer value as an array of bytes.
  136. /// </summary>
  137. /// <param name="value">The number to convert.</param>
  138. /// <returns>An array of bytes with length 4.</returns>
  139. internal static byte[] GetBytes(this uint value)
  140. {
  141. var buffer = new byte[4];
  142. value.Write(buffer, 0);
  143. return buffer;
  144. }
  145. /// <summary>
  146. /// Returns the specified 32-bit unsigned integer value as an array of bytes.
  147. /// </summary>
  148. /// <param name="value">The number to convert.</param>
  149. /// <param name="buffer">The array of bytes to write <paramref name="value"/> to.</param>
  150. /// <param name="offset">The zero-based offset in <paramref name="buffer"/> at which to begin writing.</param>
  151. internal static void Write(this uint value, byte[] buffer, int offset)
  152. {
  153. buffer[offset++] = (byte) (value >> 24);
  154. buffer[offset++] = (byte) (value >> 16);
  155. buffer[offset++] = (byte)(value >> 8);
  156. buffer[offset] = (byte) (value & 0xFF);
  157. }
  158. /// <summary>
  159. /// Returns the specified 64-bit unsigned integer value as an array of bytes.
  160. /// </summary>
  161. /// <param name="value">The number to convert.</param>
  162. /// <returns>An array of bytes with length 8.</returns>
  163. internal static byte[] GetBytes(this ulong value)
  164. {
  165. return new[]
  166. {
  167. (byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32),
  168. (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) (value & 0xFF)
  169. };
  170. }
  171. /// <summary>
  172. /// Returns the specified 64-bit signed integer value as an array of bytes.
  173. /// </summary>
  174. /// <param name="value">The number to convert.</param>
  175. /// <returns>An array of bytes with length 8.</returns>
  176. internal static byte[] GetBytes(this long value)
  177. {
  178. return new[]
  179. {
  180. (byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32),
  181. (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) (value & 0xFF)
  182. };
  183. }
  184. internal static void ValidatePort(this uint value, string argument)
  185. {
  186. if (value > IPEndPoint.MaxPort)
  187. throw new ArgumentOutOfRangeException(argument,
  188. string.Format(CultureInfo.InvariantCulture, "Specified value cannot be greater than {0}.",
  189. IPEndPoint.MaxPort));
  190. }
  191. internal static void ValidatePort(this int value, string argument)
  192. {
  193. if (value < IPEndPoint.MinPort)
  194. throw new ArgumentOutOfRangeException(argument,
  195. string.Format(CultureInfo.InvariantCulture, "Specified value cannot be less than {0}.",
  196. IPEndPoint.MinPort));
  197. if (value > IPEndPoint.MaxPort)
  198. throw new ArgumentOutOfRangeException(argument,
  199. string.Format(CultureInfo.InvariantCulture, "Specified value cannot be greater than {0}.",
  200. IPEndPoint.MaxPort));
  201. }
  202. /// <summary>
  203. /// Returns a specified number of contiguous bytes from a given offset.
  204. /// </summary>
  205. /// <param name="value">The array to return a number of bytes from.</param>
  206. /// <param name="offset">The zero-based offset in <paramref name="value"/> at which to begin taking bytes.</param>
  207. /// <param name="count">The number of bytes to take from <paramref name="value"/>.</param>
  208. /// <returns>
  209. /// A <see cref="byte"/> array that contains the specified number of bytes at the specified offset
  210. /// of the input array.
  211. /// </returns>
  212. /// <exception cref="ArgumentNullException"><paramref name="value"/> is <c>null</c>.</exception>
  213. /// <remarks>
  214. /// When <paramref name="offset"/> is zero and <paramref name="count"/> equals the length of <paramref name="value"/>,
  215. /// then <paramref name="value"/> is returned.
  216. /// </remarks>
  217. public static byte[] Take(this byte[] value, int offset, int count)
  218. {
  219. if (value == null)
  220. throw new ArgumentNullException("value");
  221. if (count == 0)
  222. return Array<byte>.Empty;
  223. if (offset == 0 && value.Length == count)
  224. return value;
  225. var taken = new byte[count];
  226. Buffer.BlockCopy(value, offset, taken, 0, count);
  227. return taken;
  228. }
  229. /// <summary>
  230. /// Returns a specified number of contiguous bytes from the start of the specified byte array.
  231. /// </summary>
  232. /// <param name="value">The array to return a number of bytes from.</param>
  233. /// <param name="count">The number of bytes to take from <paramref name="value"/>.</param>
  234. /// <returns>
  235. /// A <see cref="byte"/> array that contains the specified number of bytes at the start of the input array.
  236. /// </returns>
  237. /// <exception cref="ArgumentNullException"><paramref name="value"/> is <c>null</c>.</exception>
  238. /// <remarks>
  239. /// When <paramref name="count"/> equals the length of <paramref name="value"/>, then <paramref name="value"/>
  240. /// is returned.
  241. /// </remarks>
  242. public static byte[] Take(this byte[] value, int count)
  243. {
  244. if (value == null)
  245. throw new ArgumentNullException("value");
  246. if (count == 0)
  247. return Array<byte>.Empty;
  248. if (value.Length == count)
  249. return value;
  250. var taken = new byte[count];
  251. Buffer.BlockCopy(value, 0, taken, 0, count);
  252. return taken;
  253. }
  254. public static bool IsEqualTo(this byte[] left, byte[] right)
  255. {
  256. if (left == null)
  257. throw new ArgumentNullException("left");
  258. if (right == null)
  259. throw new ArgumentNullException("right");
  260. if (left == right)
  261. return true;
  262. if (left.Length != right.Length)
  263. return false;
  264. for (var i = 0; i < left.Length; i++)
  265. {
  266. if (left[i] != right[i])
  267. return false;
  268. }
  269. return true;
  270. }
  271. /// <summary>
  272. /// Trims the leading zero from a byte array.
  273. /// </summary>
  274. /// <param name="value">The value.</param>
  275. /// <returns>
  276. /// <paramref name="value"/> without leading zeros.
  277. /// </returns>
  278. public static byte[] TrimLeadingZeros(this byte[] value)
  279. {
  280. if (value == null)
  281. throw new ArgumentNullException("value");
  282. for (var i = 0; i < value.Length; i++)
  283. {
  284. if (value[i] == 0)
  285. continue;
  286. // if the first byte is non-zero, then we return the byte array as is
  287. if (i == 0)
  288. return value;
  289. var remainingBytes = value.Length - i;
  290. var cleaned = new byte[remainingBytes];
  291. Buffer.BlockCopy(value, i, cleaned, 0, remainingBytes);
  292. return cleaned;
  293. }
  294. return value;
  295. }
  296. public static byte[] Concat(this byte[] first, byte[] second)
  297. {
  298. if (first == null || first.Length == 0)
  299. return second;
  300. if (second == null || second.Length == 0)
  301. return first;
  302. var concat = new byte[first.Length + second.Length];
  303. Buffer.BlockCopy(first, 0, concat, 0, first.Length);
  304. Buffer.BlockCopy(second, 0, concat, first.Length, second.Length);
  305. return concat;
  306. }
  307. internal static bool CanRead(this Socket socket)
  308. {
  309. return SocketAbstraction.CanRead(socket);
  310. }
  311. internal static bool CanWrite(this Socket socket)
  312. {
  313. return SocketAbstraction.CanWrite(socket);
  314. }
  315. }
  316. }