/src/System.Net.NetworkInformation/src/System/Net/NetworkInformation/StringParsingHelpers.Connections.cs

https://github.com/davidfowl/corefx · C# · 283 lines · 216 code · 47 blank · 20 comment · 35 complexity · 5748f9ae9278c9028151999ac6fdd536 MD5 · raw file

  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT license.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Diagnostics;
  5. using System.Globalization;
  6. using System.IO;
  7. namespace System.Net.NetworkInformation
  8. {
  9. internal static partial class StringParsingHelpers
  10. {
  11. private static readonly string[] s_newLineSeparator = new string[] { Environment.NewLine }; // Used for string splitting
  12. internal static int ParseNumSocketConnections(string filePath, string protocolName)
  13. {
  14. if (!File.Exists(filePath))
  15. {
  16. throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform);
  17. }
  18. // Parse the number of active connections out of /proc/net/sockstat
  19. string sockstatFile = File.ReadAllText(filePath);
  20. int indexOfTcp = sockstatFile.IndexOf(protocolName, StringComparison.Ordinal);
  21. int endOfTcpLine = sockstatFile.IndexOf(Environment.NewLine, indexOfTcp + 1, StringComparison.Ordinal);
  22. string tcpLineData = sockstatFile.Substring(indexOfTcp, endOfTcpLine - indexOfTcp);
  23. StringParser sockstatParser = new StringParser(tcpLineData, ' ');
  24. sockstatParser.MoveNextOrFail(); // Skip "<name>:"
  25. sockstatParser.MoveNextOrFail(); // Skip: "inuse"
  26. return sockstatParser.ParseNextInt32();
  27. }
  28. internal static TcpConnectionInformation[] ParseActiveTcpConnectionsFromFiles(string tcp4ConnectionsFile, string tcp6ConnectionsFile)
  29. {
  30. if (!File.Exists(tcp4ConnectionsFile) || !File.Exists(tcp6ConnectionsFile))
  31. {
  32. throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform);
  33. }
  34. string tcp4FileContents = File.ReadAllText(tcp4ConnectionsFile);
  35. string[] v4connections = tcp4FileContents.Split(s_newLineSeparator, StringSplitOptions.RemoveEmptyEntries);
  36. string tcp6FileContents = File.ReadAllText(tcp6ConnectionsFile);
  37. string[] v6connections = tcp6FileContents.Split(s_newLineSeparator, StringSplitOptions.RemoveEmptyEntries);
  38. // First line is header in each file.
  39. TcpConnectionInformation[] connections = new TcpConnectionInformation[v4connections.Length + v6connections.Length - 2];
  40. int index = 0;
  41. // TCP Connections
  42. for (int i = 1; i < v4connections.Length; i++) // Skip first line header.
  43. {
  44. string line = v4connections[i];
  45. connections[index++] = ParseTcpConnectionInformationFromLine(line);
  46. }
  47. // TCP6 Connections
  48. for (int i = 1; i < v6connections.Length; i++) // Skip first line header.
  49. {
  50. string line = v6connections[i];
  51. connections[index++] = ParseTcpConnectionInformationFromLine(line);
  52. }
  53. return connections;
  54. }
  55. internal static IPEndPoint[] ParseActiveTcpListenersFromFiles(string tcp4ConnectionsFile, string tcp6ConnectionsFile)
  56. {
  57. if (!File.Exists(tcp4ConnectionsFile) || !File.Exists(tcp6ConnectionsFile))
  58. {
  59. throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform);
  60. }
  61. string tcp4FileContents = File.ReadAllText(tcp4ConnectionsFile);
  62. string[] v4connections = tcp4FileContents.Split(s_newLineSeparator, StringSplitOptions.RemoveEmptyEntries);
  63. string tcp6FileContents = File.ReadAllText(tcp6ConnectionsFile);
  64. string[] v6connections = tcp6FileContents.Split(s_newLineSeparator, StringSplitOptions.RemoveEmptyEntries);
  65. /// First line is header in each file.
  66. IPEndPoint[] endPoints = new IPEndPoint[v4connections.Length + v6connections.Length - 2];
  67. int index = 0;
  68. // TCP Connections
  69. for (int i = 1; i < v4connections.Length; i++) // Skip first line header.
  70. {
  71. string line = v4connections[i];
  72. IPEndPoint endPoint = ParseLocalConnectionInformation(line);
  73. endPoints[index++] = endPoint;
  74. }
  75. // TCP6 Connections
  76. for (int i = 1; i < v6connections.Length; i++) // Skip first line header.
  77. {
  78. string line = v6connections[i];
  79. IPEndPoint endPoint = ParseLocalConnectionInformation(line);
  80. endPoints[index++] = endPoint;
  81. }
  82. return endPoints;
  83. }
  84. public static IPEndPoint[] ParseActiveUdpListenersFromFiles(string udp4File, string udp6File)
  85. {
  86. if (!File.Exists(udp4File) || !File.Exists(udp6File))
  87. {
  88. throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform);
  89. }
  90. string udp4FileContents = File.ReadAllText(udp4File);
  91. string[] v4connections = udp4FileContents.Split(s_newLineSeparator, StringSplitOptions.RemoveEmptyEntries);
  92. string udp6FileContents = File.ReadAllText(udp6File);
  93. string[] v6connections = udp6FileContents.Split(s_newLineSeparator, StringSplitOptions.RemoveEmptyEntries);
  94. // First line is header in each file.
  95. IPEndPoint[] endPoints = new IPEndPoint[v4connections.Length + v6connections.Length - 2];
  96. int index = 0;
  97. // UDP Connections
  98. for (int i = 1; i < v4connections.Length; i++) // Skip first line header.
  99. {
  100. string line = v4connections[i];
  101. IPEndPoint endPoint = ParseLocalConnectionInformation(line);
  102. endPoints[index++] = endPoint;
  103. }
  104. // UDP6 Connections
  105. for (int i = 1; i < v6connections.Length; i++) // Skip first line header.
  106. {
  107. string line = v6connections[i];
  108. IPEndPoint endPoint = ParseLocalConnectionInformation(line);
  109. endPoints[index++] = endPoint;
  110. }
  111. return endPoints;
  112. }
  113. // Parsing logic for local and remote addresses and ports, as well as socket state.
  114. internal static TcpConnectionInformation ParseTcpConnectionInformationFromLine(string line)
  115. {
  116. StringParser parser = new StringParser(line, ' ', skipEmpty: true);
  117. parser.MoveNextOrFail(); // skip Index
  118. string localAddressAndPort = parser.MoveAndExtractNext(); // local_address
  119. IPEndPoint localEndPoint = ParseAddressAndPort(localAddressAndPort);
  120. string remoteAddressAndPort = parser.MoveAndExtractNext(); // rem_address
  121. IPEndPoint remoteEndPoint = ParseAddressAndPort(remoteAddressAndPort);
  122. string socketStateHex = parser.MoveAndExtractNext();
  123. int nativeTcpState;
  124. if (!int.TryParse(socketStateHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out nativeTcpState))
  125. {
  126. throw ExceptionHelper.CreateForParseFailure();
  127. }
  128. TcpState tcpState = MapTcpState(nativeTcpState);
  129. return new SimpleTcpConnectionInformation(localEndPoint, remoteEndPoint, tcpState);
  130. }
  131. // Common parsing logic for the local connection information.
  132. private static IPEndPoint ParseLocalConnectionInformation(string line)
  133. {
  134. StringParser parser = new StringParser(line, ' ', skipEmpty: true);
  135. parser.MoveNextOrFail(); // skip Index
  136. string localAddressAndPort = parser.MoveAndExtractNext();
  137. int indexOfColon = localAddressAndPort.IndexOf(':');
  138. if (indexOfColon == -1)
  139. {
  140. throw ExceptionHelper.CreateForParseFailure();
  141. }
  142. string remoteAddressString = localAddressAndPort.Substring(0, indexOfColon);
  143. IPAddress localIPAddress = ParseHexIPAddress(remoteAddressString);
  144. string portString = localAddressAndPort.Substring(indexOfColon + 1, localAddressAndPort.Length - (indexOfColon + 1));
  145. int localPort;
  146. if (!int.TryParse(portString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out localPort))
  147. {
  148. throw ExceptionHelper.CreateForParseFailure();
  149. }
  150. return new IPEndPoint(localIPAddress, localPort);
  151. }
  152. private static IPEndPoint ParseAddressAndPort(string colonSeparatedAddress)
  153. {
  154. int indexOfColon = colonSeparatedAddress.IndexOf(':');
  155. if (indexOfColon == -1)
  156. {
  157. throw ExceptionHelper.CreateForParseFailure();
  158. }
  159. string remoteAddressString = colonSeparatedAddress.Substring(0, indexOfColon);
  160. IPAddress ipAddress = ParseHexIPAddress(remoteAddressString);
  161. string portString = colonSeparatedAddress.Substring(indexOfColon + 1, colonSeparatedAddress.Length - (indexOfColon + 1));
  162. int port;
  163. if (!int.TryParse(portString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out port))
  164. {
  165. throw ExceptionHelper.CreateForParseFailure();
  166. }
  167. return new IPEndPoint(ipAddress, port);
  168. }
  169. // Maps from Linux TCP states to .NET TcpStates.
  170. private static TcpState MapTcpState(int state)
  171. {
  172. return Interop.Sys.MapTcpState((int)state);
  173. }
  174. internal static IPAddress ParseHexIPAddress(string remoteAddressString)
  175. {
  176. if (remoteAddressString.Length <= 8) // IPv4 Address
  177. {
  178. return ParseIPv4HexString(remoteAddressString);
  179. }
  180. else if (remoteAddressString.Length == 32) // IPv6 Address
  181. {
  182. return ParseIPv6HexString(remoteAddressString);
  183. }
  184. else
  185. {
  186. throw ExceptionHelper.CreateForParseFailure();
  187. }
  188. }
  189. // Simply converts the hex string into a long and uses the IPAddress(long) constructor.
  190. // Strings passed to this method must be 8 or less characters in length (32-bit address).
  191. private static IPAddress ParseIPv4HexString(string hexAddress)
  192. {
  193. IPAddress ipAddress;
  194. long addressValue;
  195. if (!long.TryParse(hexAddress, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out addressValue))
  196. {
  197. throw ExceptionHelper.CreateForParseFailure();
  198. }
  199. ipAddress = new IPAddress(addressValue);
  200. return ipAddress;
  201. }
  202. // Parses a 128-bit IPv6 Address stored as a 32-character hex number.
  203. // Strings passed to this must be 32 characters in length.
  204. private static IPAddress ParseIPv6HexString(string hexAddress)
  205. {
  206. Debug.Assert(hexAddress.Length == 32);
  207. byte[] addressBytes = new byte[16];
  208. for (int i = 0; i < 16; i++)
  209. {
  210. addressBytes[i] = (byte)(HexToByte(hexAddress[(i * 2)])
  211. + HexToByte(hexAddress[(i * 2) + 1]));
  212. }
  213. IPAddress ipAddress = new IPAddress(addressBytes);
  214. return ipAddress;
  215. }
  216. private static byte HexToByte(char val)
  217. {
  218. if (val <= '9' && val >= '0')
  219. {
  220. return (byte)(val - '0');
  221. }
  222. else if (val >= 'a' && val <= 'f')
  223. {
  224. return (byte)((val - 'a') + 10);
  225. }
  226. else if (val >= 'A' && val <= 'F')
  227. {
  228. return (byte)((val - 'A') + 10);
  229. }
  230. else
  231. {
  232. throw ExceptionHelper.CreateForParseFailure();
  233. }
  234. }
  235. }
  236. }