Making sure mono_marshal_free is used instead of g_free in mono_string_builder_to_utf8
[mono.git] / mcs / class / referencesource / System / net / System / Net / NetworkInformation / SystemIPGlobalProperties.cs
1
2
3 namespace System.Net.NetworkInformation {
4
5     using System.Net;
6     using System.Net.Sockets;
7     using System;
8     using System.Runtime.InteropServices;
9     using System.Threading;
10     using System.Collections.Generic;
11
12     internal class SystemIPGlobalProperties:IPGlobalProperties {
13         private FixedInfo fixedInfo;
14         private bool fixedInfoInitialized = false;
15     
16         //changing these require a reboot, so we'll cache them instead.
17         private static volatile string hostName = null;
18         private static volatile string domainName = null;
19
20         static object syncObject = new object();
21
22         internal SystemIPGlobalProperties() {
23         }
24
25         internal static FixedInfo GetFixedInfo(){
26             uint    size = 0;
27             SafeLocalFree buffer = null; 
28             FixedInfo fixedInfo = new FixedInfo();
29             
30             //first we need to get the size of the buffer
31             uint result = UnsafeNetInfoNativeMethods.GetNetworkParams(SafeLocalFree.Zero,ref size);
32             
33             while (result == IpHelperErrors.ErrorBufferOverflow) {
34                 try {
35                     //now we allocate the buffer and read the network parameters.
36                     buffer = SafeLocalFree.LocalAlloc((int)size);
37                     result = UnsafeNetInfoNativeMethods.GetNetworkParams(buffer,ref size);
38                     if ( result == IpHelperErrors.Success ) {
39                         fixedInfo = new FixedInfo( (FIXED_INFO)Marshal.PtrToStructure(buffer.DangerousGetHandle(),typeof(FIXED_INFO)));
40                     }
41                 }
42                 finally {
43                     if(buffer != null){
44                         buffer.Close();
45                     }
46                 }
47             }
48             
49             //if the result include there being no information, we'll still throw
50             if (result != IpHelperErrors.Success) {
51                 throw new NetworkInformationException((int)result);
52             }
53             return fixedInfo; 
54         }
55
56         
57         internal FixedInfo FixedInfo {
58             get {
59                 if (!fixedInfoInitialized) {
60                     lock(this){
61                         if (!fixedInfoInitialized) {
62                             fixedInfo = GetFixedInfo();
63                             fixedInfoInitialized = true;
64                         }
65                     }
66                 }
67                 return fixedInfo;
68             }
69         }
70
71         /// <summary>Specifies the host name for the local computer.</summary>
72         public override string HostName{
73             get {
74                 if(hostName == null){
75                     lock(syncObject){
76                         if(hostName == null){
77                             hostName = FixedInfo.HostName;
78                             domainName = FixedInfo.DomainName;
79                         }
80                     }
81                 }
82                 return hostName;
83             }
84         }
85         /// <summary>Specifies the domain in which the local computer is registered.</summary>
86         public override string DomainName{
87             get {
88                 if(domainName == null){
89                     lock(syncObject){
90                         if(domainName == null){
91                             hostName = FixedInfo.HostName;
92                             domainName = FixedInfo.DomainName;
93                         }
94                     }
95                 }
96                 return domainName;
97             }
98         }
99         /// <summary>
100         /// The type of node.
101         /// </summary>
102         /// <remarks>
103         /// The exact mechanism by which NetBIOS names are resolved to IP addresses
104         /// depends on the node's configured NetBIOS Node Type. Broadcast - uses broadcast
105         /// NetBIOS Name Queries for name registration and resolution.
106         /// PeerToPeer - uses a NetBIOS name server (NBNS), such as Windows Internet
107         /// Name Service (WINS), to resolve NetBIOS names.
108         /// Mixed - uses Broadcast then PeerToPeer.
109         /// Hybrid - uses PeerToPeer then Broadcast.
110         /// </remarks>
111         public override NetBiosNodeType NodeType{get {
112             return (NetBiosNodeType)FixedInfo.NodeType;}
113         }
114         /// <summary>Specifies the DHCP scope name.</summary>
115         public override string DhcpScopeName{get {
116             return FixedInfo.ScopeId;}
117         }
118         /// <summary>Specifies whether the local computer is acting as an WINS proxy.</summary>
119         public override bool IsWinsProxy{get {
120             return (FixedInfo.EnableProxy);}
121         }
122
123           
124         public override TcpConnectionInformation[] GetActiveTcpConnections(){
125             List<TcpConnectionInformation> list = new List<TcpConnectionInformation>();
126             List<SystemTcpConnectionInformation> connections = GetAllTcpConnections();
127             foreach(TcpConnectionInformation connection in connections){
128                 if(connection.State != TcpState.Listen){
129                     list.Add(connection);
130                 }
131             }
132             return list.ToArray();
133         }
134
135
136         public override IPEndPoint[] GetActiveTcpListeners (){
137             List<IPEndPoint> list = new List<IPEndPoint>();
138             List<SystemTcpConnectionInformation> connections = GetAllTcpConnections();
139             foreach(TcpConnectionInformation connection in connections){
140                 if(connection.State == TcpState.Listen){
141                     list.Add(connection.LocalEndPoint);
142                 }
143             }
144             return list.ToArray();
145         }
146
147
148
149         /// <summary>
150         /// Gets the active tcp connections. Uses the native GetTcpTable api.</summary>
151         private List<SystemTcpConnectionInformation> GetAllTcpConnections() {
152             uint size = 0;
153             uint result = 0;
154             SafeLocalFree buffer = null;
155             List<SystemTcpConnectionInformation> tcpConnections = new List<SystemTcpConnectionInformation>();
156
157             // Check if it supports IPv4 for IPv6 only modes.
158             if (Socket.OSSupportsIPv4) {
159
160                 // Get the size of buffer needed
161                 result = UnsafeNetInfoNativeMethods.GetTcpTable(SafeLocalFree.Zero, ref size, true);
162
163                 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
164                     try {
165                         //allocate the buffer and get the tcptable
166                         buffer = SafeLocalFree.LocalAlloc((int)size);
167                         result = UnsafeNetInfoNativeMethods.GetTcpTable(buffer, ref size, true);
168
169                         if (result == IpHelperErrors.Success) {
170                             //the table info just gives us the number of rows.
171                             IntPtr newPtr = buffer.DangerousGetHandle();
172                             MibTcpTable tcpTableInfo = (MibTcpTable)Marshal.PtrToStructure(newPtr, typeof(MibTcpTable));
173
174                             if (tcpTableInfo.numberOfEntries > 0) {
175                                 //we need to skip over the tableinfo to get the inline rows
176                                 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpTableInfo.numberOfEntries));
177
178                                 for (int i = 0; i < tcpTableInfo.numberOfEntries; i++) {
179                                     MibTcpRow tcpRow = (MibTcpRow)Marshal.PtrToStructure(newPtr, typeof(MibTcpRow));
180                                     tcpConnections.Add(new SystemTcpConnectionInformation(tcpRow));
181
182                                     //we increment the pointer to the next row
183                                     newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpRow));
184                                 }
185                             }
186                         }
187                     }
188                     finally {
189                         if (buffer != null)
190                             buffer.Close();
191                     }
192                 }
193
194                 // if we don't have any ipv4 interfaces detected, just continue
195                 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
196                     throw new NetworkInformationException((int)result);
197                 }
198             }
199
200             if (Socket.OSSupportsIPv6) {
201
202                 // IPv6 tcp connections
203                 // Get the size of buffer needed
204                 size = 0;
205                 result = UnsafeNetInfoNativeMethods.GetExtendedTcpTable(SafeLocalFree.Zero, ref size, true,
206                                                                         (uint)AddressFamily.InterNetworkV6,
207                                                                         TcpTableClass.TcpTableOwnerPidAll, 0);
208
209                 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
210                     try {
211                         // Allocate the buffer and get the tcptable
212                         buffer = SafeLocalFree.LocalAlloc((int)size);
213                         result = UnsafeNetInfoNativeMethods.GetExtendedTcpTable(buffer, ref size, true,
214                                                                                 (uint)AddressFamily.InterNetworkV6,
215                                                                                 TcpTableClass.TcpTableOwnerPidAll, 0);
216                         if (result == IpHelperErrors.Success) {
217                             // The table info just gives us the number of rows.
218                             IntPtr newPtr = buffer.DangerousGetHandle();
219
220                             MibTcp6TableOwnerPid tcpTable6OwnerPid 
221                                 = (MibTcp6TableOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibTcp6TableOwnerPid));
222
223                             if (tcpTable6OwnerPid.numberOfEntries > 0) {
224                                 // We need to skip over the tableinfo to get the inline rows
225                                 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpTable6OwnerPid.numberOfEntries));
226
227                                 for (int i = 0; i < tcpTable6OwnerPid.numberOfEntries; i++) {
228                                     MibTcp6RowOwnerPid tcp6RowOwnerPid 
229                                         = (MibTcp6RowOwnerPid)Marshal.PtrToStructure(newPtr, 
230                                         typeof(MibTcp6RowOwnerPid));
231                                     tcpConnections.Add(new SystemTcpConnectionInformation(tcp6RowOwnerPid));
232
233                                     // We increment the pointer to the next row
234                                     newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcp6RowOwnerPid));
235                                 }
236                             }
237                         }
238                     }
239                     finally {
240                         if (buffer != null)
241                             buffer.Close();
242                     }
243                 }
244
245                 // If we don't have any ipv6 interfaces detected, just continue
246                 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
247                     throw new NetworkInformationException((int)result);
248                 }
249             }
250
251             return tcpConnections;
252         }
253
254
255
256
257         /// <summary>Gets the active udp listeners. Uses the native GetUdpTable api.</summary>
258         public override IPEndPoint[] GetActiveUdpListeners(){
259             uint    size = 0;
260             uint result = 0;
261             SafeLocalFree buffer = null;
262             List<IPEndPoint> udpListeners = new List<IPEndPoint>();
263
264             // Check if it support IPv4 for IPv6 only modes.
265             if (Socket.OSSupportsIPv4) {
266                 // Get the size of buffer needed
267                 result = UnsafeNetInfoNativeMethods.GetUdpTable(SafeLocalFree.Zero, ref size, true);
268                 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
269                     try {
270                         //allocate the buffer and get the udptable
271                         buffer = SafeLocalFree.LocalAlloc((int)size);
272                         result = UnsafeNetInfoNativeMethods.GetUdpTable(buffer, ref size, true);
273
274                         if (result == IpHelperErrors.Success) {
275                             //the table info just gives us the number of rows.
276                             IntPtr newPtr = buffer.DangerousGetHandle();
277                             MibUdpTable udpTableInfo = (MibUdpTable)Marshal.PtrToStructure(newPtr, typeof(MibUdpTable));
278
279                             if (udpTableInfo.numberOfEntries > 0) {
280                                 //we need to skip over the tableinfo to get the inline rows
281                                 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpTableInfo.numberOfEntries));
282                                 for (int i = 0; i < udpTableInfo.numberOfEntries; i++) {
283                                     MibUdpRow udpRow = (MibUdpRow)Marshal.PtrToStructure(newPtr, typeof(MibUdpRow));
284                                     int localPort = udpRow.localPort1 << 8 | udpRow.localPort2;
285
286                                     udpListeners.Add(new IPEndPoint(udpRow.localAddr, (int)localPort));
287                                     
288                                     //we increment the pointer to the next row
289                                     newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpRow));
290                                 }
291                             }
292                         }
293                     }
294                     finally {
295                         if (buffer != null)
296                             buffer.Close();
297                     }
298                 }
299                 // if we don't have any ipv4 interfaces detected, just continue
300                 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
301                     throw new NetworkInformationException((int)result);
302                 }
303             }
304
305             if (Socket.OSSupportsIPv6) {
306
307                 // Get the size of buffer needed
308                 size = 0;
309                 result = UnsafeNetInfoNativeMethods.GetExtendedUdpTable(SafeLocalFree.Zero, ref size, true,
310                                                                         (uint)AddressFamily.InterNetworkV6,
311                                                                         UdpTableClass.UdpTableOwnerPid, 0);
312                 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
313                     try {
314                         // Allocate the buffer and get the udptable
315                         buffer = SafeLocalFree.LocalAlloc((int)size);
316                         result = UnsafeNetInfoNativeMethods.GetExtendedUdpTable(buffer, ref size, true,
317                                                                                 (uint)AddressFamily.InterNetworkV6,
318                                                                                 UdpTableClass.UdpTableOwnerPid, 0);
319
320                         if (result == IpHelperErrors.Success) {
321                             // The table info just gives us the number of rows.
322                             IntPtr newPtr = buffer.DangerousGetHandle();
323                             MibUdp6TableOwnerPid udp6TableOwnerPid 
324                                 = (MibUdp6TableOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibUdp6TableOwnerPid));
325
326                             if (udp6TableOwnerPid.numberOfEntries > 0) {
327                                 // We need to skip over the tableinfo to get the inline rows
328                                 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6TableOwnerPid.numberOfEntries));
329                                 for (int i = 0; i < udp6TableOwnerPid.numberOfEntries; i++) {
330                                     MibUdp6RowOwnerPid udp6RowOwnerPid  
331                                         = (MibUdp6RowOwnerPid)Marshal.PtrToStructure(newPtr, 
332                                         typeof(MibUdp6RowOwnerPid));
333                                     int localPort = udp6RowOwnerPid.localPort1 << 8 | udp6RowOwnerPid.localPort2;
334
335                                     udpListeners.Add(new IPEndPoint(new IPAddress(udp6RowOwnerPid.localAddr, 
336                                         udp6RowOwnerPid.localScopeId), localPort));
337
338                                     // We increment the pointer to the next row
339                                     newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6RowOwnerPid));
340                                 }
341                             }
342                         }
343                     }
344                     finally {
345                         if (buffer != null)
346                             buffer.Close();
347                     }
348                 }
349                 // If we don't have any ipv6 interfaces detected, just continue
350                 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
351                     throw new NetworkInformationException((int)result);
352                 }
353             }
354
355             return udpListeners.ToArray();
356         }
357
358         public override IPGlobalStatistics GetIPv4GlobalStatistics(){
359             return new SystemIPGlobalStatistics(AddressFamily.InterNetwork);
360         }
361         public override IPGlobalStatistics GetIPv6GlobalStatistics(){
362             return new SystemIPGlobalStatistics(AddressFamily.InterNetworkV6);
363         }
364         
365        public override TcpStatistics GetTcpIPv4Statistics(){
366             return new SystemTcpStatistics(AddressFamily.InterNetwork);
367         }
368         public override TcpStatistics GetTcpIPv6Statistics(){
369             return new SystemTcpStatistics(AddressFamily.InterNetworkV6);
370         }
371
372         public override UdpStatistics GetUdpIPv4Statistics(){
373             return new SystemUdpStatistics(AddressFamily.InterNetwork);
374         }
375         public override UdpStatistics GetUdpIPv6Statistics(){
376             return new SystemUdpStatistics(AddressFamily.InterNetworkV6);
377         }
378          
379         public override IcmpV4Statistics GetIcmpV4Statistics(){
380             return new SystemIcmpV4Statistics();
381         }
382         
383         public override IcmpV6Statistics GetIcmpV6Statistics(){
384             return new SystemIcmpV6Statistics();
385         }
386
387         public override UnicastIPAddressInformationCollection GetUnicastAddresses(){
388             // Wait for the Address Table to stabilize
389             using (ManualResetEvent stable = new ManualResetEvent(false)) {
390                 if (!TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, stable)) {
391                     stable.WaitOne();
392                 }
393             }
394
395             return GetUnicastAddressTable();
396         }
397
398         public override IAsyncResult BeginGetUnicastAddresses(AsyncCallback callback, object state){
399             ContextAwareResult asyncResult = new ContextAwareResult(false, false, this, state, callback);
400             asyncResult.StartPostingAsyncOp(false);
401             if (TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, asyncResult)) {
402                 asyncResult.InvokeCallback();
403             }
404             asyncResult.FinishPostingAsyncOp();
405
406             return asyncResult;
407         }
408
409         public override UnicastIPAddressInformationCollection EndGetUnicastAddresses(IAsyncResult asyncResult){
410             if (asyncResult == null) {
411                 throw new ArgumentNullException("asyncResult");
412             }
413
414             ContextAwareResult result = asyncResult as ContextAwareResult;
415             if (result == null || result.AsyncObject == null || result.AsyncObject.GetType() != typeof(SystemIPGlobalProperties)) {
416                 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult));
417             }
418
419             if (result.EndCalled) {
420                 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetStableUnicastAddresses"));
421             }
422
423             result.InternalWaitForCompletion();
424
425             result.EndCalled = true;
426             return GetUnicastAddressTable();
427         }
428
429         private static void StableUnicastAddressTableCallback(object param){
430             EventWaitHandle handle = param as EventWaitHandle;
431             if (handle != null) {
432                 handle.Set();
433             }
434             else {
435                 LazyAsyncResult asyncResult = (LazyAsyncResult)param;
436                 asyncResult.InvokeCallback();
437             }
438         }
439
440         private static UnicastIPAddressInformationCollection GetUnicastAddressTable(){
441             UnicastIPAddressInformationCollection rval = new UnicastIPAddressInformationCollection();
442             
443             NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
444             for (int i = 0; i < interfaces.Length; ++i) {
445                 UnicastIPAddressInformationCollection addresses = interfaces[i].GetIPProperties().UnicastAddresses;
446
447                 foreach (UnicastIPAddressInformation address in addresses) {
448                     if (!rval.Contains(address)) {
449                         rval.InternalAdd(address);
450                     }
451                 }
452             }
453
454             return rval;
455         }
456
457     }   //ends networkinformation class
458
459    
460
461     internal struct FixedInfo{
462         internal FIXED_INFO info;
463
464         internal FixedInfo(FIXED_INFO info){
465             this.info = info;
466         }
467         
468         internal string HostName{
469             get{
470                 return info.hostName;
471             }
472         }
473             
474         internal string DomainName{
475             get{
476                 return info.domainName;
477             }
478         }
479         
480         internal NetBiosNodeType NodeType{
481             get{
482                 return info.nodeType;
483             }
484         }
485         internal string ScopeId{
486             get{
487                 return info.scopeId;
488             }
489         }
490
491         internal bool EnableRouting{
492             get{
493                 return info.enableRouting;
494             }
495         }
496
497         internal bool EnableProxy{
498             get{
499                 return info.enableProxy;
500             }
501         }
502
503         internal bool EnableDns{
504             get{
505                 return info.enableDns;
506             }
507         }
508     }
509 }
510