3 namespace System.Net.NetworkInformation {
6 using System.Net.Sockets;
8 using System.Runtime.InteropServices;
9 using System.Threading;
10 using System.Collections.Generic;
13 internal class SystemIPGlobalProperties:IPGlobalProperties {
14 private FixedInfo fixedInfo;
15 private bool fixedInfoInitialized = false;
17 //changing these require a reboot, so we'll cache them instead.
18 private static volatile string hostName = null;
19 private static volatile string domainName = null;
21 static object syncObject = new object();
23 internal SystemIPGlobalProperties() {
26 internal static FixedInfo GetFixedInfo(){
28 SafeLocalFree buffer = null;
29 FixedInfo fixedInfo = new FixedInfo();
31 //first we need to get the size of the buffer
32 uint result = UnsafeNetInfoNativeMethods.GetNetworkParams(SafeLocalFree.Zero,ref size);
34 while (result == IpHelperErrors.ErrorBufferOverflow) {
36 //now we allocate the buffer and read the network parameters.
37 buffer = SafeLocalFree.LocalAlloc((int)size);
38 result = UnsafeNetInfoNativeMethods.GetNetworkParams(buffer,ref size);
39 if ( result == IpHelperErrors.Success ) {
40 fixedInfo = new FixedInfo( (FIXED_INFO)Marshal.PtrToStructure(buffer.DangerousGetHandle(),typeof(FIXED_INFO)));
50 //if the result include there being no information, we'll still throw
51 if (result != IpHelperErrors.Success) {
52 throw new NetworkInformationException((int)result);
58 internal FixedInfo FixedInfo {
60 if (!fixedInfoInitialized) {
62 if (!fixedInfoInitialized) {
63 fixedInfo = GetFixedInfo();
64 fixedInfoInitialized = true;
72 /// <summary>Specifies the host name for the local computer.</summary>
73 public override string HostName{
78 hostName = FixedInfo.HostName;
79 domainName = FixedInfo.DomainName;
86 /// <summary>Specifies the domain in which the local computer is registered.</summary>
87 public override string DomainName{
89 if(domainName == null){
91 if(domainName == null){
92 hostName = FixedInfo.HostName;
93 domainName = FixedInfo.DomainName;
101 /// The type of node.
104 /// The exact mechanism by which NetBIOS names are resolved to IP addresses
105 /// depends on the node's configured NetBIOS Node Type. Broadcast - uses broadcast
106 /// NetBIOS Name Queries for name registration and resolution.
107 /// PeerToPeer - uses a NetBIOS name server (NBNS), such as Windows Internet
108 /// Name Service (WINS), to resolve NetBIOS names.
109 /// Mixed - uses Broadcast then PeerToPeer.
110 /// Hybrid - uses PeerToPeer then Broadcast.
112 public override NetBiosNodeType NodeType{get {
113 return (NetBiosNodeType)FixedInfo.NodeType;}
115 /// <summary>Specifies the DHCP scope name.</summary>
116 public override string DhcpScopeName{get {
117 return FixedInfo.ScopeId;}
119 /// <summary>Specifies whether the local computer is acting as an WINS proxy.</summary>
120 public override bool IsWinsProxy{get {
121 return (FixedInfo.EnableProxy);}
125 public override TcpConnectionInformation[] GetActiveTcpConnections(){
126 List<TcpConnectionInformation> list = new List<TcpConnectionInformation>();
127 List<SystemTcpConnectionInformation> connections = GetAllTcpConnections();
128 foreach(TcpConnectionInformation connection in connections){
129 if(connection.State != TcpState.Listen){
130 list.Add(connection);
133 return list.ToArray();
137 public override IPEndPoint[] GetActiveTcpListeners (){
138 List<IPEndPoint> list = new List<IPEndPoint>();
139 List<SystemTcpConnectionInformation> connections = GetAllTcpConnections();
140 foreach(TcpConnectionInformation connection in connections){
141 if(connection.State == TcpState.Listen){
142 list.Add(connection.LocalEndPoint);
145 return list.ToArray();
151 /// Gets the active tcp connections. Uses the native GetTcpTable api.</summary>
152 private List<SystemTcpConnectionInformation> GetAllTcpConnections() {
155 SafeLocalFree buffer = null;
156 List<SystemTcpConnectionInformation> tcpConnections = new List<SystemTcpConnectionInformation>();
158 // Check if it supports IPv4 for IPv6 only modes.
159 if (Socket.OSSupportsIPv4) {
161 // Get the size of buffer needed
162 result = UnsafeNetInfoNativeMethods.GetTcpTable(SafeLocalFree.Zero, ref size, true);
164 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
166 //allocate the buffer and get the tcptable
167 buffer = SafeLocalFree.LocalAlloc((int)size);
168 result = UnsafeNetInfoNativeMethods.GetTcpTable(buffer, ref size, true);
170 if (result == IpHelperErrors.Success) {
171 //the table info just gives us the number of rows.
172 IntPtr newPtr = buffer.DangerousGetHandle();
173 MibTcpTable tcpTableInfo = (MibTcpTable)Marshal.PtrToStructure(newPtr, typeof(MibTcpTable));
175 if (tcpTableInfo.numberOfEntries > 0) {
176 //we need to skip over the tableinfo to get the inline rows
177 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpTableInfo.numberOfEntries));
179 for (int i = 0; i < tcpTableInfo.numberOfEntries; i++) {
180 MibTcpRow tcpRow = (MibTcpRow)Marshal.PtrToStructure(newPtr, typeof(MibTcpRow));
181 tcpConnections.Add(new SystemTcpConnectionInformation(tcpRow));
183 //we increment the pointer to the next row
184 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpRow));
195 // if we don't have any ipv4 interfaces detected, just continue
196 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
197 throw new NetworkInformationException((int)result);
201 if (Socket.OSSupportsIPv6) {
203 // IPv6 tcp connections
204 // Get the size of buffer needed
206 result = UnsafeNetInfoNativeMethods.GetExtendedTcpTable(SafeLocalFree.Zero, ref size, true,
207 (uint)AddressFamily.InterNetworkV6,
208 TcpTableClass.TcpTableOwnerPidAll, 0);
210 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
212 // Allocate the buffer and get the tcptable
213 buffer = SafeLocalFree.LocalAlloc((int)size);
214 result = UnsafeNetInfoNativeMethods.GetExtendedTcpTable(buffer, ref size, true,
215 (uint)AddressFamily.InterNetworkV6,
216 TcpTableClass.TcpTableOwnerPidAll, 0);
217 if (result == IpHelperErrors.Success) {
218 // The table info just gives us the number of rows.
219 IntPtr newPtr = buffer.DangerousGetHandle();
221 MibTcp6TableOwnerPid tcpTable6OwnerPid
222 = (MibTcp6TableOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibTcp6TableOwnerPid));
224 if (tcpTable6OwnerPid.numberOfEntries > 0) {
225 // We need to skip over the tableinfo to get the inline rows
226 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpTable6OwnerPid.numberOfEntries));
228 for (int i = 0; i < tcpTable6OwnerPid.numberOfEntries; i++) {
229 MibTcp6RowOwnerPid tcp6RowOwnerPid
230 = (MibTcp6RowOwnerPid)Marshal.PtrToStructure(newPtr,
231 typeof(MibTcp6RowOwnerPid));
232 tcpConnections.Add(new SystemTcpConnectionInformation(tcp6RowOwnerPid));
234 // We increment the pointer to the next row
235 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcp6RowOwnerPid));
246 // If we don't have any ipv6 interfaces detected, just continue
247 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
248 throw new NetworkInformationException((int)result);
252 return tcpConnections;
258 /// <summary>Gets the active udp listeners. Uses the native GetUdpTable api.</summary>
259 public override IPEndPoint[] GetActiveUdpListeners(){
262 SafeLocalFree buffer = null;
263 List<IPEndPoint> udpListeners = new List<IPEndPoint>();
265 // Check if it support IPv4 for IPv6 only modes.
266 if (Socket.OSSupportsIPv4) {
267 // Get the size of buffer needed
268 result = UnsafeNetInfoNativeMethods.GetUdpTable(SafeLocalFree.Zero, ref size, true);
269 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
271 //allocate the buffer and get the udptable
272 buffer = SafeLocalFree.LocalAlloc((int)size);
273 result = UnsafeNetInfoNativeMethods.GetUdpTable(buffer, ref size, true);
275 if (result == IpHelperErrors.Success) {
276 //the table info just gives us the number of rows.
277 IntPtr newPtr = buffer.DangerousGetHandle();
278 MibUdpTable udpTableInfo = (MibUdpTable)Marshal.PtrToStructure(newPtr, typeof(MibUdpTable));
280 if (udpTableInfo.numberOfEntries > 0) {
281 //we need to skip over the tableinfo to get the inline rows
282 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpTableInfo.numberOfEntries));
283 for (int i = 0; i < udpTableInfo.numberOfEntries; i++) {
284 MibUdpRow udpRow = (MibUdpRow)Marshal.PtrToStructure(newPtr, typeof(MibUdpRow));
285 int localPort = udpRow.localPort1 << 8 | udpRow.localPort2;
287 udpListeners.Add(new IPEndPoint(udpRow.localAddr, (int)localPort));
289 //we increment the pointer to the next row
290 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpRow));
300 // if we don't have any ipv4 interfaces detected, just continue
301 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
302 throw new NetworkInformationException((int)result);
306 if (Socket.OSSupportsIPv6) {
308 // Get the size of buffer needed
310 result = UnsafeNetInfoNativeMethods.GetExtendedUdpTable(SafeLocalFree.Zero, ref size, true,
311 (uint)AddressFamily.InterNetworkV6,
312 UdpTableClass.UdpTableOwnerPid, 0);
313 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
315 // Allocate the buffer and get the udptable
316 buffer = SafeLocalFree.LocalAlloc((int)size);
317 result = UnsafeNetInfoNativeMethods.GetExtendedUdpTable(buffer, ref size, true,
318 (uint)AddressFamily.InterNetworkV6,
319 UdpTableClass.UdpTableOwnerPid, 0);
321 if (result == IpHelperErrors.Success) {
322 // The table info just gives us the number of rows.
323 IntPtr newPtr = buffer.DangerousGetHandle();
324 MibUdp6TableOwnerPid udp6TableOwnerPid
325 = (MibUdp6TableOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibUdp6TableOwnerPid));
327 if (udp6TableOwnerPid.numberOfEntries > 0) {
328 // We need to skip over the tableinfo to get the inline rows
329 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6TableOwnerPid.numberOfEntries));
330 for (int i = 0; i < udp6TableOwnerPid.numberOfEntries; i++) {
331 MibUdp6RowOwnerPid udp6RowOwnerPid
332 = (MibUdp6RowOwnerPid)Marshal.PtrToStructure(newPtr,
333 typeof(MibUdp6RowOwnerPid));
334 int localPort = udp6RowOwnerPid.localPort1 << 8 | udp6RowOwnerPid.localPort2;
336 udpListeners.Add(new IPEndPoint(new IPAddress(udp6RowOwnerPid.localAddr,
337 udp6RowOwnerPid.localScopeId), localPort));
339 // We increment the pointer to the next row
340 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6RowOwnerPid));
350 // If we don't have any ipv6 interfaces detected, just continue
351 if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) {
352 throw new NetworkInformationException((int)result);
356 return udpListeners.ToArray();
359 public override IPGlobalStatistics GetIPv4GlobalStatistics(){
360 return new SystemIPGlobalStatistics(AddressFamily.InterNetwork);
362 public override IPGlobalStatistics GetIPv6GlobalStatistics(){
363 return new SystemIPGlobalStatistics(AddressFamily.InterNetworkV6);
366 public override TcpStatistics GetTcpIPv4Statistics(){
367 return new SystemTcpStatistics(AddressFamily.InterNetwork);
369 public override TcpStatistics GetTcpIPv6Statistics(){
370 return new SystemTcpStatistics(AddressFamily.InterNetworkV6);
373 public override UdpStatistics GetUdpIPv4Statistics(){
374 return new SystemUdpStatistics(AddressFamily.InterNetwork);
376 public override UdpStatistics GetUdpIPv6Statistics(){
377 return new SystemUdpStatistics(AddressFamily.InterNetworkV6);
380 public override IcmpV4Statistics GetIcmpV4Statistics(){
381 return new SystemIcmpV4Statistics();
384 public override IcmpV6Statistics GetIcmpV6Statistics(){
385 return new SystemIcmpV6Statistics();
388 public override UnicastIPAddressInformationCollection GetUnicastAddresses(){
389 // Wait for the Address Table to stabilize
390 using (ManualResetEvent stable = new ManualResetEvent(false)) {
391 if (!TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, stable)) {
396 return GetUnicastAddressTable();
399 public override IAsyncResult BeginGetUnicastAddresses(AsyncCallback callback, object state){
400 ContextAwareResult asyncResult = new ContextAwareResult(false, false, this, state, callback);
401 asyncResult.StartPostingAsyncOp(false);
402 if (TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, asyncResult)) {
403 asyncResult.InvokeCallback();
405 asyncResult.FinishPostingAsyncOp();
410 public override UnicastIPAddressInformationCollection EndGetUnicastAddresses(IAsyncResult asyncResult){
411 if (asyncResult == null) {
412 throw new ArgumentNullException("asyncResult");
415 ContextAwareResult result = asyncResult as ContextAwareResult;
416 if (result == null || result.AsyncObject == null || result.AsyncObject.GetType() != typeof(SystemIPGlobalProperties)) {
417 throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult));
420 if (result.EndCalled) {
421 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetStableUnicastAddresses"));
424 result.InternalWaitForCompletion();
426 result.EndCalled = true;
427 return GetUnicastAddressTable();
430 private static void StableUnicastAddressTableCallback(object param){
431 EventWaitHandle handle = param as EventWaitHandle;
432 if (handle != null) {
436 LazyAsyncResult asyncResult = (LazyAsyncResult)param;
437 asyncResult.InvokeCallback();
441 private static UnicastIPAddressInformationCollection GetUnicastAddressTable(){
442 UnicastIPAddressInformationCollection rval = new UnicastIPAddressInformationCollection();
444 NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
445 for (int i = 0; i < interfaces.Length; ++i) {
446 UnicastIPAddressInformationCollection addresses = interfaces[i].GetIPProperties().UnicastAddresses;
448 foreach (UnicastIPAddressInformation address in addresses) {
449 if (!rval.Contains(address)) {
450 rval.InternalAdd(address);
458 } //ends networkinformation class
462 internal struct FixedInfo{
463 internal FIXED_INFO info;
465 internal FixedInfo(FIXED_INFO info){
469 internal string HostName{
471 return info.hostName;
475 internal string DomainName{
477 return info.domainName;
481 internal NetBiosNodeType NodeType{
483 return info.nodeType;
486 internal string ScopeId{
492 internal bool EnableRouting{
494 return info.enableRouting;
498 internal bool EnableProxy{
500 return info.enableProxy;
504 internal bool EnableDns{
506 return info.enableDns;