Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / System / System.Net.NetworkInformation / IPGlobalProperties.cs
1 //
2 // System.Net.NetworkInformation.IPGlobalProperties
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@novell.com)
6 //      Atsushi Enomoto (atsushi@ximian.com)
7 //
8 // Copyright (c) 2006-2007 Novell, Inc. (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
32 using System.Globalization;
33 using System.IO;
34 using System.Net.Sockets;
35 using System.Runtime.InteropServices;
36 using System.Text;
37
38 namespace System.Net.NetworkInformation {
39         public abstract class IPGlobalProperties {
40                 protected IPGlobalProperties ()
41                 {
42                 }
43
44                 public static IPGlobalProperties GetIPGlobalProperties ()
45                 {
46                         switch (Environment.OSVersion.Platform) {
47                         case PlatformID.Unix:
48                                 MibIPGlobalProperties impl = null;
49                                 if (Directory.Exists (MibIPGlobalProperties.ProcDir)) {
50                                         impl = new MibIPGlobalProperties (MibIPGlobalProperties.ProcDir);
51                                         if (File.Exists (impl.StatisticsFile))
52                                                 return impl;
53                                 }
54                                 if (Directory.Exists (MibIPGlobalProperties.CompatProcDir)) {
55                                         impl = new MibIPGlobalProperties (MibIPGlobalProperties.CompatProcDir);
56                                         if (File.Exists (impl.StatisticsFile))
57                                                 return impl;
58                                 }
59                                 throw new NotSupportedException ("This platform is not supported");
60                         default:
61                                 return new Win32IPGlobalProperties ();
62                         }
63                 }
64
65                 public abstract TcpConnectionInformation [] GetActiveTcpConnections ();
66                 public abstract IPEndPoint [] GetActiveTcpListeners ();
67                 public abstract IPEndPoint [] GetActiveUdpListeners ();
68                 public abstract IcmpV4Statistics GetIcmpV4Statistics ();
69                 public abstract IcmpV6Statistics GetIcmpV6Statistics ();
70                 public abstract IPGlobalStatistics GetIPv4GlobalStatistics ();
71                 public abstract IPGlobalStatistics GetIPv6GlobalStatistics ();
72                 public abstract TcpStatistics GetTcpIPv4Statistics ();
73                 public abstract TcpStatistics GetTcpIPv6Statistics ();
74                 public abstract UdpStatistics GetUdpIPv4Statistics ();
75                 public abstract UdpStatistics GetUdpIPv6Statistics ();
76
77                 public abstract string DhcpScopeName { get; }
78                 public abstract string DomainName { get; }
79                 public abstract string HostName { get; }
80                 public abstract bool IsWinsProxy { get; }
81                 public abstract NetBiosNodeType NodeType { get; }
82         }
83
84         // It expects /proc/net/snmp (or /usr/compat/linux/proc/net/snmp),
85         // formatted like:
86         // http://www.linuxdevcenter.com/linux/2000/11/16/example5.html
87         // http://www.linuxdevcenter.com/linux/2000/11/16/example2.html
88         class MibIPGlobalProperties : IPGlobalProperties
89         {
90                 [DllImport ("libc")]
91                 static extern int gethostname ([MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] byte [] name, int len);
92
93                 [DllImport ("libc")]
94                 static extern int getdomainname ([MarshalAs (UnmanagedType.LPArray, SizeParamIndex = 1)] byte [] name, int len);
95
96                 public const string ProcDir = "/proc";
97                 public const string CompatProcDir = "/usr/compat/linux/proc";
98
99                 public readonly string StatisticsFile, StatisticsFileIPv6, TcpFile, Tcp6File, UdpFile, Udp6File;
100
101                 public MibIPGlobalProperties (string procDir)
102                 {
103                         StatisticsFile = Path.Combine (procDir, "net/snmp");
104                         StatisticsFileIPv6 = Path.Combine (procDir, "net/snmp6");
105                         TcpFile = Path.Combine (procDir,"net/tcp");
106                         Tcp6File = Path.Combine (procDir,"net/tcp6");
107                         UdpFile = Path.Combine (procDir,"net/udp");
108                         Udp6File = Path.Combine (procDir,"net/udp6");
109                 }
110
111                 StringDictionary GetProperties4 (string item)
112                 {
113                         string file = StatisticsFile;
114
115                         string head = item + ": ";
116                         using (StreamReader sr = new StreamReader (file, Encoding.ASCII)) {
117                                 string [] keys = null;
118                                 string [] values = null;
119                                 string s = String.Empty;
120                                 do {
121                                         s = sr.ReadLine ();
122                                         if (String.IsNullOrEmpty (s))
123                                                 continue;
124                                         if (s.Length <= head.Length || String.CompareOrdinal (s, 0, head, 0, head.Length) != 0)
125                                                 continue;
126                                         if (keys == null)
127                                                 keys = s.Substring (head.Length).Split (' ');
128                                         else if (values != null)
129                                                 // hmm, there may be better error type...
130                                                 throw CreateException (file, String.Format ("Found duplicate line for values for the same item '{0}'", item));
131                                         else {
132                                                 values = s.Substring (head.Length).Split (' ');
133                                                 break;
134                                         }
135                                 } while (!sr.EndOfStream);
136
137                                 if (values == null)
138                                         throw CreateException (file, String.Format ("No corresponding line was not found for '{0}'", item));
139                                 if (keys.Length != values.Length)
140                                         throw CreateException (file, String.Format ("The counts in the header line and the value line do not match for '{0}'", item));
141                                 StringDictionary dic = new StringDictionary ();
142                                 for (int i = 0; i < keys.Length; i++)
143                                         dic [keys [i]] = values [i];
144                                 return dic;
145                         }
146                 }
147
148                 StringDictionary GetProperties6 (string item)
149                 {
150                         if (!File.Exists (StatisticsFileIPv6))
151                                 throw new NetworkInformationException ();
152
153                         string file = StatisticsFileIPv6;
154
155                         string head = item;
156                         using (StreamReader sr = new StreamReader (file, Encoding.ASCII)) {
157                                 StringDictionary dic = new StringDictionary ();
158                                 string s = String.Empty;
159                                 do {
160                                         s = sr.ReadLine ();
161                                         if (String.IsNullOrEmpty (s))
162                                                 continue;
163                                         if (s.Length <= head.Length || String.CompareOrdinal (s, 0, head, 0, head.Length) != 0)
164                                                 continue;
165                                         int idx = s.IndexOfAny (wsChars, head.Length);
166                                         if (idx < 0)
167                                                 throw CreateException (file, null);
168                                         dic [s.Substring (head.Length, idx - head.Length)] = s.Substring (idx + 1).Trim (wsChars);
169                                 } while (!sr.EndOfStream);
170
171                                 return dic;
172                         }
173                 }
174
175                 static readonly char [] wsChars = new char [] {' ', '\t'};
176
177                 Exception CreateException (string file, string msg)
178                 {
179                         return new InvalidOperationException (String.Format ("Unsupported (unexpected) '{0}' file format. ", file) + msg);
180                 }
181                 IPEndPoint [] GetLocalAddresses (List<string []> list)
182                 {
183                         IPEndPoint [] ret = new IPEndPoint [list.Count];
184                         for (int i = 0; i < ret.Length; i++)
185                                 ret [i] = ToEndpoint (list [i] [1]);
186                         return ret;
187                 }
188
189                 IPEndPoint ToEndpoint (string s)
190                 {
191                         int idx = s.IndexOf (':');
192                         int port = int.Parse (s.Substring (idx + 1), NumberStyles.HexNumber);
193                         if (s.Length == 13)
194                                 return new IPEndPoint (long.Parse (s.Substring (0, idx), NumberStyles.HexNumber), port);
195                         else {
196                                 byte [] bytes = new byte [16];
197                                 for (int i = 0; (i << 1) < idx; i++)
198                                         bytes [i] = byte.Parse (s.Substring (i << 1, 2), NumberStyles.HexNumber);
199                                 return new IPEndPoint (new IPAddress (bytes), port);
200                         }
201                 }
202
203                 void GetRows (string file, List<string []> list)
204                 {
205                         if (!File.Exists (file))
206                                 return;
207                         using (StreamReader sr = new StreamReader (file, Encoding.ASCII)) {
208                                 sr.ReadLine (); // skip first line
209                                 while (!sr.EndOfStream) {
210                                         string [] item = sr.ReadLine ().Split (wsChars, StringSplitOptions.RemoveEmptyEntries);
211                                         if (item.Length < 4)
212                                                 throw CreateException (file, null);
213                                         list.Add (item);
214                                 }
215                         }
216                 }
217
218                 public override TcpConnectionInformation [] GetActiveTcpConnections ()
219                 {
220                         List<string []> list = new List<string []> ();
221                         GetRows (TcpFile, list);
222                         GetRows (Tcp6File, list);
223
224                         TcpConnectionInformation [] ret = new TcpConnectionInformation [list.Count];
225                         for (int i = 0; i < ret.Length; i++) {
226                                 // sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode
227                                 IPEndPoint local = ToEndpoint (list [i] [1]);
228                                 IPEndPoint remote = ToEndpoint (list [i] [2]);
229                                 TcpState state = (TcpState) int.Parse (list [i] [3], NumberStyles.HexNumber);
230                                 ret [i] = new TcpConnectionInformationImpl (local, remote, state);
231                         }
232                         return ret;
233                 }
234
235                 public override IPEndPoint [] GetActiveTcpListeners ()
236                 {
237                         List<string []> list = new List<string []> ();
238                         GetRows (TcpFile, list);
239                         GetRows (Tcp6File, list);
240                         return GetLocalAddresses (list);
241                 }
242
243                 public override IPEndPoint [] GetActiveUdpListeners ()
244                 {
245                         List<string []> list = new List<string []> ();
246                         GetRows (UdpFile, list);
247                         GetRows (Udp6File, list);
248                         return GetLocalAddresses (list);
249                 }
250
251                 public override IcmpV4Statistics GetIcmpV4Statistics ()
252                 {
253                         return new MibIcmpV4Statistics (GetProperties4 ("Icmp"));
254                 }
255
256                 public override IcmpV6Statistics GetIcmpV6Statistics ()
257                 {
258                         return new MibIcmpV6Statistics (GetProperties6 ("Icmp6"));
259                 }
260
261                 public override IPGlobalStatistics GetIPv4GlobalStatistics ()
262                 {
263                         return new MibIPGlobalStatistics (GetProperties4 ("Ip"));
264                 }
265
266                 public override IPGlobalStatistics GetIPv6GlobalStatistics ()
267                 {
268                         return new MibIPGlobalStatistics (GetProperties6 ("Ip6"));
269                 }
270
271                 public override TcpStatistics GetTcpIPv4Statistics ()
272                 {
273                         return new MibTcpStatistics (GetProperties4 ("Tcp"));
274                 }
275
276                 public override TcpStatistics GetTcpIPv6Statistics ()
277                 {
278                         // There is no TCP info in /proc/net/snmp,
279                         // so it is shared with IPv4 info.
280                         return new MibTcpStatistics (GetProperties4 ("Tcp"));
281                 }
282
283                 public override UdpStatistics GetUdpIPv4Statistics ()
284                 {
285                         return new MibUdpStatistics (GetProperties4 ("Udp"));
286                 }
287
288                 public override UdpStatistics GetUdpIPv6Statistics ()
289                 {
290                         return new MibUdpStatistics (GetProperties6 ("Udp6"));
291                 }
292
293                 public override string DhcpScopeName {
294                         get { return String.Empty; }
295                 }
296
297                 public override string DomainName {
298                         get {
299                                 byte [] bytes = new byte [256];
300                                 if (getdomainname (bytes, 256) != 0)
301                                         throw new NetworkInformationException ();
302                                 int len = Array.IndexOf<byte> (bytes, 0);
303                                 return Encoding.ASCII.GetString (bytes, 0, len < 0 ? 256 : len);
304                         }
305                 }
306
307                 public override string HostName {
308                         get {
309                                 byte [] bytes = new byte [256];
310                                 if (gethostname (bytes, 256) != 0)
311                                         throw new NetworkInformationException ();
312                                 int len = Array.IndexOf<byte> (bytes, 0);
313                                 return Encoding.ASCII.GetString (bytes, 0, len < 0 ? 256 : len);
314                         }
315                 }
316
317                 public override bool IsWinsProxy {
318                         get { return false; } // no WINS
319                 }
320
321                 public override NetBiosNodeType NodeType {
322                         get { return NetBiosNodeType.Unknown; } // no NetBios
323                 }
324         }
325
326         class Win32IPGlobalProperties : IPGlobalProperties
327         {
328                 public const int AF_INET = 2;
329                 public const int AF_INET6 = 23;
330
331                 // FIXME: it might be getting wrong table. I'm getting
332                 // different results from .NET 2.0.
333                 unsafe void FillTcpTable (out List<Win32_MIB_TCPROW> tab4, out List<Win32_MIB_TCP6ROW> tab6)
334                 {
335                         tab4 = new List<Win32_MIB_TCPROW> ();
336                         int size4 = 0;
337                         GetTcpTable (null, ref size4, true); // get size
338                         byte [] bytes4 = new byte [size4];
339                         GetTcpTable (bytes4, ref size4, true); // get list
340
341                         int structSize4 = Marshal.SizeOf (typeof (Win32_MIB_TCPROW));
342
343                         fixed (byte* ptr = bytes4) {
344                                 int count = Marshal.ReadInt32 ((IntPtr) ptr);
345                                 for (int i = 0; i < count; i++) {
346                                         Win32_MIB_TCPROW row = new Win32_MIB_TCPROW ();
347                                         Marshal.PtrToStructure ((IntPtr) (ptr + i * structSize4 + 4), row);
348                                         tab4.Add (row);
349                                 }
350                         }
351
352                         tab6 = new List<Win32_MIB_TCP6ROW> ();
353                         if (Environment.OSVersion.Version.Major >= 6) { // Vista
354                                 int size6 = 0;
355                                 GetTcp6Table (null, ref size6, true); // get size
356                                 byte [] bytes6 = new byte [size6];
357                                 GetTcp6Table (bytes6, ref size6, true); // get list
358
359                                 int structSize6 = Marshal.SizeOf (typeof (Win32_MIB_TCP6ROW));
360
361                                 fixed (byte* ptr = bytes6) {
362                                         int count = Marshal.ReadInt32 ((IntPtr) ptr);
363                                         for (int i = 0; i < count; i++) {
364                                                 Win32_MIB_TCP6ROW row = new Win32_MIB_TCP6ROW ();
365                                                 Marshal.PtrToStructure ((IntPtr) (ptr + i * structSize6 + 4), row);
366                                                 tab6.Add (row);
367                                         }
368                                 }
369                         }
370                 }
371
372                 bool IsListenerState (TcpState state)
373                 {
374                         switch (state) {
375                         case TcpState.SynSent:
376                         case TcpState.Listen:
377                         case TcpState.FinWait1:
378                         case TcpState.FinWait2:
379                         case TcpState.CloseWait:
380                                 return true;
381                         }
382                         return false;
383                 }
384
385                 public override TcpConnectionInformation [] GetActiveTcpConnections ()
386                 {
387                         List<Win32_MIB_TCPROW> tab4 = null;
388                         List<Win32_MIB_TCP6ROW> tab6 = null;
389                         FillTcpTable (out tab4, out tab6);
390                         int size4 = tab4.Count;
391
392                         TcpConnectionInformation [] ret = new TcpConnectionInformation [size4 + tab6.Count];
393                         for (int i = 0; i < size4; i++)
394                                 ret [i] = tab4 [i].TcpInfo;
395                         for (int i = 0; i < tab6.Count; i++)
396                                 ret [size4 + i] = tab6 [i].TcpInfo;
397                         return ret;
398                 }
399
400                 public override IPEndPoint [] GetActiveTcpListeners ()
401                 {
402                         List<Win32_MIB_TCPROW> tab4 = null;
403                         List<Win32_MIB_TCP6ROW> tab6 = null;
404                         FillTcpTable (out tab4, out tab6);
405
406                         List<IPEndPoint> ret = new List<IPEndPoint> ();
407                         for (int i = 0, count = tab4.Count; i < count; i++)
408                                 if (IsListenerState (tab4 [i].State))
409                                         ret.Add (tab4 [i].LocalEndPoint);
410                         for (int i = 0, count = tab6.Count; i < count; i++)
411                                 if (IsListenerState (tab6 [i].State))
412                                         ret.Add (tab6 [i].LocalEndPoint);
413                         return ret.ToArray ();
414                 }
415
416                 public unsafe override IPEndPoint [] GetActiveUdpListeners ()
417                 {
418                         List<IPEndPoint> list = new List<IPEndPoint> ();
419
420                         byte [] bytes4 = null;
421                         int size4 = 0;
422                         GetUdpTable (null, ref size4, true); // get size
423                         bytes4 = new byte [size4];
424                         GetUdpTable (bytes4, ref size4, true); // get list
425
426                         int structSize4 = Marshal.SizeOf (typeof (Win32_MIB_UDPROW));
427
428                         fixed (byte* ptr = bytes4) {
429                                 int count = Marshal.ReadInt32 ((IntPtr) ptr);
430                                 for (int i = 0; i < count; i++) {
431                                         Win32_MIB_UDPROW row = new Win32_MIB_UDPROW ();
432                                         Marshal.PtrToStructure ((IntPtr) (ptr + i * structSize4 + 4), row);
433                                         list.Add (row.LocalEndPoint);
434                                 }
435                         }
436
437                         if (Environment.OSVersion.Version.Major >= 6) { // Vista
438                                 byte [] bytes6 = null;
439                                 int size6 = 0;
440                                 GetUdp6Table (null, ref size6, true); // get size
441                                 bytes6 = new byte [size6];
442                                 GetUdp6Table (bytes6, ref size6, true); // get list
443
444                                 int structSize6 = Marshal.SizeOf (typeof (Win32_MIB_UDP6ROW));
445
446                                 fixed (byte* ptr = bytes6) {
447                                         int count = Marshal.ReadInt32 ((IntPtr) ptr);
448                                         for (int i = 0; i < count; i++) {
449                                                 Win32_MIB_UDP6ROW row = new Win32_MIB_UDP6ROW ();
450                                                 Marshal.PtrToStructure ((IntPtr) (ptr + i * structSize6 + 4), row);
451                                                 list.Add (row.LocalEndPoint);
452                                         }
453                                 }
454                         }
455
456                         return list.ToArray ();
457                 }
458
459                 public override IcmpV4Statistics GetIcmpV4Statistics ()
460                 {
461                         if (!Socket.SupportsIPv4)
462                                 throw new NetworkInformationException ();
463                         Win32_MIBICMPINFO stats;
464                         GetIcmpStatistics (out stats, AF_INET);
465                         return new Win32IcmpV4Statistics (stats);
466                 }
467
468                 public override IcmpV6Statistics GetIcmpV6Statistics ()
469                 {
470                         if (!Socket.OSSupportsIPv6)
471                                 throw new NetworkInformationException ();
472                         Win32_MIB_ICMP_EX stats;
473                         GetIcmpStatisticsEx (out stats, AF_INET6);
474                         return new Win32IcmpV6Statistics (stats);
475                 }
476
477                 public override IPGlobalStatistics GetIPv4GlobalStatistics ()
478                 {
479                         if (!Socket.SupportsIPv4)
480                                 throw new NetworkInformationException ();
481                         Win32_MIB_IPSTATS stats;
482                         GetIpStatisticsEx (out stats, AF_INET);
483                         return new Win32IPGlobalStatistics (stats);
484                 }
485
486                 public override IPGlobalStatistics GetIPv6GlobalStatistics ()
487                 {
488                         if (!Socket.OSSupportsIPv6)
489                                 throw new NetworkInformationException ();
490                         Win32_MIB_IPSTATS stats;
491                         GetIpStatisticsEx (out stats, AF_INET6);
492                         return new Win32IPGlobalStatistics (stats);
493                 }
494
495                 public override TcpStatistics GetTcpIPv4Statistics ()
496                 {
497                         if (!Socket.SupportsIPv4)
498                                 throw new NetworkInformationException ();
499                         Win32_MIB_TCPSTATS stats;
500                         GetTcpStatisticsEx (out stats, AF_INET);
501                         return new Win32TcpStatistics (stats);
502                 }
503
504                 public override TcpStatistics GetTcpIPv6Statistics ()
505                 {
506                         if (!Socket.OSSupportsIPv6)
507                                 throw new NetworkInformationException ();
508                         Win32_MIB_TCPSTATS stats;
509                         GetTcpStatisticsEx (out stats, AF_INET6);
510                         return new Win32TcpStatistics (stats);
511                 }
512
513                 public override UdpStatistics GetUdpIPv4Statistics ()
514                 {
515                         if (!Socket.SupportsIPv4)
516                                 throw new NetworkInformationException ();
517                         Win32_MIB_UDPSTATS stats;
518                         GetUdpStatisticsEx (out stats, AF_INET);
519                         return new Win32UdpStatistics (stats);
520                 }
521
522                 public override UdpStatistics GetUdpIPv6Statistics ()
523                 {
524                         if (!Socket.OSSupportsIPv6)
525                                 throw new NetworkInformationException ();
526                         Win32_MIB_UDPSTATS stats;
527                         GetUdpStatisticsEx (out stats, AF_INET6);
528                         return new Win32UdpStatistics (stats);
529                 }
530
531                 public override string DhcpScopeName {
532                         get { return Win32_FIXED_INFO.Instance.ScopeId; }
533                 }
534
535                 public override string DomainName {
536                         get { return Win32_FIXED_INFO.Instance.DomainName; }
537                 }
538
539                 public override string HostName {
540                         get { return Win32_FIXED_INFO.Instance.HostName; }
541                 }
542
543                 public override bool IsWinsProxy {
544                         get { return Win32_FIXED_INFO.Instance.EnableProxy != 0; }
545                 }
546
547                 public override NetBiosNodeType NodeType {
548                         get { return Win32_FIXED_INFO.Instance.NodeType; }
549                 }
550
551                 // PInvokes
552
553                 [DllImport ("iphlpapi.dll")]
554                 static extern int GetTcpTable (byte [] pTcpTable, ref int pdwSize, bool bOrder);
555
556                 [DllImport ("iphlpapi.dll")]
557                 static extern int GetTcp6Table (byte [] TcpTable, ref int SizePointer, bool Order);
558
559                 [DllImport ("iphlpapi.dll")]
560                 static extern int GetUdpTable (byte [] pUdpTable, ref int pdwSize, bool bOrder);
561
562                 [DllImport ("iphlpapi.dll")]
563                 static extern int GetUdp6Table (byte [] Udp6Table, ref int SizePointer, bool Order);
564
565                 [DllImport ("iphlpapi.dll")]
566                 static extern int GetTcpStatisticsEx (out Win32_MIB_TCPSTATS pStats, int dwFamily);
567
568                 [DllImport ("iphlpapi.dll")]
569                 static extern int GetUdpStatisticsEx (out Win32_MIB_UDPSTATS pStats, int dwFamily);
570
571                 [DllImport ("iphlpapi.dll")]
572                 static extern int GetIcmpStatistics (out Win32_MIBICMPINFO pStats, int dwFamily);
573
574                 [DllImport ("iphlpapi.dll")]
575                 static extern int GetIcmpStatisticsEx (out Win32_MIB_ICMP_EX pStats, int dwFamily);
576
577                 [DllImport ("iphlpapi.dll")]
578                 static extern int GetIpStatisticsEx (out Win32_MIB_IPSTATS pStats, int dwFamily);
579
580                 // Win32 structures
581
582                 [StructLayout (LayoutKind.Explicit)]
583                 struct Win32_IN6_ADDR
584                 {
585                         [FieldOffset (0)]
586                         [MarshalAs ( UnmanagedType.ByValArray, SizeConst = 16)]
587                         public byte [] Bytes;
588                 }
589
590                 [StructLayout (LayoutKind.Sequential)]
591                 class Win32_MIB_TCPROW
592                 {
593                         public TcpState State;
594                         public uint LocalAddr;
595                         public int LocalPort;
596                         public uint RemoteAddr;
597                         public int RemotePort;
598
599                         public IPEndPoint LocalEndPoint {
600                                 get { return new IPEndPoint (LocalAddr, LocalPort); }
601                         }
602
603                         public IPEndPoint RemoteEndPoint {
604                                 get { return new IPEndPoint (RemoteAddr, RemotePort); }
605                         }
606
607                         public TcpConnectionInformation TcpInfo {
608                                 get { return new TcpConnectionInformationImpl (LocalEndPoint, RemoteEndPoint, State); }
609                         }
610                 }
611
612                 [StructLayout (LayoutKind.Sequential)]
613                 class Win32_MIB_TCP6ROW
614                 {
615                         public TcpState State;
616                         public Win32_IN6_ADDR LocalAddr;
617                         public uint LocalScopeId;
618                         public int LocalPort;
619                         public Win32_IN6_ADDR RemoteAddr;
620                         public uint RemoteScopeId;
621                         public int RemotePort;
622
623                         public IPEndPoint LocalEndPoint {
624                                 get { return new IPEndPoint (new IPAddress (LocalAddr.Bytes, LocalScopeId), LocalPort); }
625                         }
626
627                         public IPEndPoint RemoteEndPoint {
628                                 get { return new IPEndPoint (new IPAddress (RemoteAddr.Bytes, RemoteScopeId), RemotePort); }
629                         }
630
631                         public TcpConnectionInformation TcpInfo {
632                                 get { return new TcpConnectionInformationImpl (LocalEndPoint, RemoteEndPoint, State); }
633                         }
634                 }
635
636                 [StructLayout (LayoutKind.Sequential)]
637                 class Win32_MIB_UDPROW
638                 {
639                         public uint LocalAddr;
640                         public int LocalPort;
641
642                         public IPEndPoint LocalEndPoint {
643                                 get { return new IPEndPoint (LocalAddr, LocalPort); }
644                         }
645                 }
646
647                 [StructLayout (LayoutKind.Sequential)]
648                 class Win32_MIB_UDP6ROW
649                 {
650                         public Win32_IN6_ADDR LocalAddr;
651                         public uint LocalScopeId;
652                         public int LocalPort;
653
654                         public IPEndPoint LocalEndPoint {
655                                 get { return new IPEndPoint (new IPAddress (LocalAddr.Bytes, LocalScopeId), LocalPort); }
656                         }
657                 }
658         }
659 }