Merge pull request #3142 from henricm/fix-for-win-mono_string_to_utf8
[mono.git] / mcs / class / referencesource / System / net / System / Net / NetworkInformation / SystemNetworkInterface.cs
1
2     /// <summary><para>
3     ///    Provides support for ip configuation information and statistics.
4     ///</para></summary>
5     ///
6 namespace System.Net.NetworkInformation {
7     using System.Net;
8     using System.Net.Sockets;
9     using System;
10     using System.Runtime.InteropServices;
11     using System.Collections.Generic;
12     using System.Diagnostics.Contracts;
13     
14     internal class SystemNetworkInterface:NetworkInterface {
15
16         //common properties
17         private string name;
18         private string id;
19         private string description;
20         private byte[] physicalAddress;
21         private uint addressLength;
22         private NetworkInterfaceType type;
23         private OperationalStatus operStatus;
24         private long speed;
25         //Unfortunately, any interface can
26         //have two completely different valid indexes for ipv4 and ipv6
27         private uint index = 0;
28         private uint ipv6Index = 0;
29         private AdapterFlags adapterFlags;
30         private SystemIPInterfaceProperties interfaceProperties = null;
31
32         internal static int InternalLoopbackInterfaceIndex {
33             get {
34                 return GetBestInterfaceForAddress(IPAddress.Loopback);
35             }
36         }
37
38         internal static int InternalIPv6LoopbackInterfaceIndex {
39             get {
40                 return GetBestInterfaceForAddress(IPAddress.IPv6Loopback);
41             }
42         }
43
44         private static int GetBestInterfaceForAddress(IPAddress addr) {
45             int index;
46             SocketAddress address = new SocketAddress(addr);
47             int error = (int)UnsafeNetInfoNativeMethods.GetBestInterfaceEx(address.m_Buffer, out index);
48             if (error != 0) {
49                 throw new NetworkInformationException(error);
50             }
51
52             return index;
53         }
54
55         internal static bool InternalGetIsNetworkAvailable(){
56
57             try {
58                 NetworkInterface[] networkInterfaces = GetNetworkInterfaces();
59                 foreach (NetworkInterface netInterface in networkInterfaces) {
60                     if (netInterface.OperationalStatus == OperationalStatus.Up && netInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel
61                         && netInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback){
62                         return true;
63                     }
64                 }
65             }
66             catch (NetworkInformationException nie) {
67                 if (Logging.On) Logging.Exception(Logging.Web, "SystemNetworkInterface", "InternalGetIsNetworkAvailable", nie);
68             }
69
70             return false;
71         }
72
73         // Vista+
74         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods",
75             Justification = "DangerousGetHandle is required for marshaling")]
76         internal static NetworkInterface[] GetNetworkInterfaces() {
77             Contract.Ensures(Contract.Result<NetworkInterface[]>() != null);
78             AddressFamily family = AddressFamily.Unspecified;
79             uint bufferSize = 0;
80             SafeLocalFree buffer = null;
81             FixedInfo fixedInfo = SystemIPGlobalProperties.GetFixedInfo();
82             List<SystemNetworkInterface> interfaceList = new List<SystemNetworkInterface>();
83
84             GetAdaptersAddressesFlags flags = 
85                 GetAdaptersAddressesFlags.IncludeGateways
86                 | GetAdaptersAddressesFlags.IncludeWins;
87
88             // Figure out the right buffer size for the adapter information
89             uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(
90                 family, (uint)flags, IntPtr.Zero, SafeLocalFree.Zero, ref bufferSize);
91
92             while (result == IpHelperErrors.ErrorBufferOverflow) {
93                 try {
94                     // Allocate the buffer and get the adapter info
95                     buffer = SafeLocalFree.LocalAlloc((int)bufferSize);
96                     result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(
97                         family, (uint)flags, IntPtr.Zero, buffer, ref bufferSize);
98
99                     // If succeeded, we're going to add each new interface
100                     if (result == IpHelperErrors.Success) {
101                         // Linked list of interfaces
102                         IntPtr ptr = buffer.DangerousGetHandle();
103                         while (ptr != IntPtr.Zero) {
104                             // Traverse the list, marshal in the native structures, and create new NetworkInterfaces
105                             IpAdapterAddresses adapterAddresses = 
106                                 (IpAdapterAddresses)Marshal.PtrToStructure(ptr, typeof(IpAdapterAddresses));
107                             interfaceList.Add(new SystemNetworkInterface(fixedInfo, adapterAddresses));
108
109                             ptr = adapterAddresses.next;
110                         }
111                     }
112                 }
113                 finally {
114                     if (buffer != null) {
115                         buffer.Close();
116                     }
117                     buffer = null;
118                 }
119             }
120
121             // if we don't have any interfaces detected, return empty.
122             if (result == IpHelperErrors.ErrorNoData || result == IpHelperErrors.ErrorInvalidParameter) {
123                 return new SystemNetworkInterface[0];
124             }
125
126             // Otherwise we throw on an error
127             if (result != IpHelperErrors.Success) {
128                 throw new NetworkInformationException((int)result);
129             }
130
131             return interfaceList.ToArray();
132         }
133
134         // Vista+
135         internal SystemNetworkInterface(FixedInfo fixedInfo, IpAdapterAddresses ipAdapterAddresses) {
136             //store the common api information
137             id = ipAdapterAddresses.AdapterName;
138             name = ipAdapterAddresses.friendlyName;
139             description = ipAdapterAddresses.description;
140             index = ipAdapterAddresses.index;
141
142             physicalAddress = ipAdapterAddresses.address;
143             addressLength = ipAdapterAddresses.addressLength;
144
145             type = ipAdapterAddresses.type;
146             operStatus = ipAdapterAddresses.operStatus;
147             speed = (long)ipAdapterAddresses.receiveLinkSpeed;
148
149             //api specific info
150             ipv6Index = ipAdapterAddresses.ipv6Index;
151
152             adapterFlags = ipAdapterAddresses.flags;
153             interfaceProperties = new SystemIPInterfaceProperties(fixedInfo, ipAdapterAddresses);
154         }
155         
156         /// Basic Properties
157         
158         public override string Id{get {return id;}}
159         public override string Name{get {return name;}}
160         public override string Description{get {return description;}}
161              
162         public override PhysicalAddress GetPhysicalAddress(){
163             byte[] newAddr = new byte[addressLength];
164             Array.Copy(physicalAddress,newAddr,addressLength);
165             return new PhysicalAddress(newAddr);
166         }
167         public override NetworkInterfaceType NetworkInterfaceType{get {return type;}}
168
169         public override IPInterfaceProperties GetIPProperties(){
170             return interfaceProperties;
171         }
172         
173         /// Despite the naming, the results are not IPv4 specific.
174         /// Do not use this method, use GetIPStatistics instead.
175         /// <include file='doc\NetworkInterface.uex' path='docs/doc[@for="NetworkInterface.GetInterfaceStatistics"]/*' />
176         public override IPv4InterfaceStatistics GetIPv4Statistics(){
177             return new SystemIPv4InterfaceStatistics(index);
178         }
179         
180         public override IPInterfaceStatistics GetIPStatistics() {
181             return new SystemIPInterfaceStatistics(index);
182         }
183
184         public override bool Supports(NetworkInterfaceComponent networkInterfaceComponent){
185             if (networkInterfaceComponent ==  NetworkInterfaceComponent.IPv6 
186                 && ((adapterFlags & AdapterFlags.IPv6Enabled) != 0)) {
187                 return true;
188             }
189             if (networkInterfaceComponent == NetworkInterfaceComponent.IPv4
190                 && ((adapterFlags & AdapterFlags.IPv4Enabled) != 0)) {
191                 return true;
192             }
193             return false;
194         }
195
196         //We cache this to be consistent across all platforms
197         public override OperationalStatus OperationalStatus{
198             get {
199                 return operStatus;
200             }
201         }
202
203         public override long Speed{
204             get {
205                 return speed;
206             }
207         }  
208
209         public override bool IsReceiveOnly {
210             get {
211                 return ((adapterFlags & AdapterFlags.ReceiveOnly) > 0);
212             }
213         }
214         /// <summary>The interface doesn't allow multicast.</summary>
215         public override bool SupportsMulticast {
216             get {
217                 return ((adapterFlags & AdapterFlags.NoMulticast) == 0);
218             }
219         }
220     }
221 }
222
223
224