3 namespace System.Net.NetworkInformation {
6 using System.Net.Sockets;
8 using System.Runtime.InteropServices;
9 using System.Threading;
10 using System.Collections.Generic;
12 internal class SystemIPGlobalProperties:IPGlobalProperties {
13 private FixedInfo fixedInfo;
14 private bool fixedInfoInitialized = false;
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;
20 static object syncObject = new object();
22 internal SystemIPGlobalProperties() {
25 internal static FixedInfo GetFixedInfo(){
27 SafeLocalFree buffer = null;
28 FixedInfo fixedInfo = new FixedInfo();
30 //first we need to get the size of the buffer
31 uint result = UnsafeNetInfoNativeMethods.GetNetworkParams(SafeLocalFree.Zero,ref size);
33 while (result == IpHelperErrors.ErrorBufferOverflow) {
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)));
49 //if the result include there being no information, we'll still throw
50 if (result != IpHelperErrors.Success) {
51 throw new NetworkInformationException((int)result);
57 internal FixedInfo FixedInfo {
59 if (!fixedInfoInitialized) {
61 if (!fixedInfoInitialized) {
62 fixedInfo = GetFixedInfo();
63 fixedInfoInitialized = true;
71 /// <summary>Specifies the host name for the local computer.</summary>
72 public override string HostName{
77 hostName = FixedInfo.HostName;
78 domainName = FixedInfo.DomainName;
85 /// <summary>Specifies the domain in which the local computer is registered.</summary>
86 public override string DomainName{
88 if(domainName == null){
90 if(domainName == null){
91 hostName = FixedInfo.HostName;
92 domainName = FixedInfo.DomainName;
100 /// The type of node.
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.
111 public override NetBiosNodeType NodeType{get {
112 return (NetBiosNodeType)FixedInfo.NodeType;}
114 /// <summary>Specifies the DHCP scope name.</summary>
115 public override string DhcpScopeName{get {
116 return FixedInfo.ScopeId;}
118 /// <summary>Specifies whether the local computer is acting as an WINS proxy.</summary>
119 public override bool IsWinsProxy{get {
120 return (FixedInfo.EnableProxy);}
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);
132 return list.ToArray();
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);
144 return list.ToArray();
150 /// Gets the active tcp connections. Uses the native GetTcpTable api.</summary>
151 private List<SystemTcpConnectionInformation> GetAllTcpConnections() {
154 SafeLocalFree buffer = null;
155 List<SystemTcpConnectionInformation> tcpConnections = new List<SystemTcpConnectionInformation>();
157 // Check if it supports IPv4 for IPv6 only modes.
158 if (Socket.OSSupportsIPv4) {
160 // Get the size of buffer needed
161 result = UnsafeNetInfoNativeMethods.GetTcpTable(SafeLocalFree.Zero, ref size, true);
163 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
165 //allocate the buffer and get the tcptable
166 buffer = SafeLocalFree.LocalAlloc((int)size);
167 result = UnsafeNetInfoNativeMethods.GetTcpTable(buffer, ref size, true);
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));
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));
178 for (int i = 0; i < tcpTableInfo.numberOfEntries; i++) {
179 MibTcpRow tcpRow = (MibTcpRow)Marshal.PtrToStructure(newPtr, typeof(MibTcpRow));
180 tcpConnections.Add(new SystemTcpConnectionInformation(tcpRow));
182 //we increment the pointer to the next row
183 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpRow));
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);
200 if (Socket.OSSupportsIPv6) {
202 // IPv6 tcp connections
203 // Get the size of buffer needed
205 result = UnsafeNetInfoNativeMethods.GetExtendedTcpTable(SafeLocalFree.Zero, ref size, true,
206 (uint)AddressFamily.InterNetworkV6,
207 TcpTableClass.TcpTableOwnerPidAll, 0);
209 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
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();
220 MibTcp6TableOwnerPid tcpTable6OwnerPid
221 = (MibTcp6TableOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibTcp6TableOwnerPid));
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));
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));
233 // We increment the pointer to the next row
234 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcp6RowOwnerPid));
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);
251 return tcpConnections;
257 /// <summary>Gets the active udp listeners. Uses the native GetUdpTable api.</summary>
258 public override IPEndPoint[] GetActiveUdpListeners(){
261 SafeLocalFree buffer = null;
262 List<IPEndPoint> udpListeners = new List<IPEndPoint>();
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) {
270 //allocate the buffer and get the udptable
271 buffer = SafeLocalFree.LocalAlloc((int)size);
272 result = UnsafeNetInfoNativeMethods.GetUdpTable(buffer, ref size, true);
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));
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;
286 udpListeners.Add(new IPEndPoint(udpRow.localAddr, (int)localPort));
288 //we increment the pointer to the next row
289 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpRow));
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);
305 if (Socket.OSSupportsIPv6) {
307 // Get the size of buffer needed
309 result = UnsafeNetInfoNativeMethods.GetExtendedUdpTable(SafeLocalFree.Zero, ref size, true,
310 (uint)AddressFamily.InterNetworkV6,
311 UdpTableClass.UdpTableOwnerPid, 0);
312 while (result == IpHelperErrors.ErrorInsufficientBuffer) {
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);
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));
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;
335 udpListeners.Add(new IPEndPoint(new IPAddress(udp6RowOwnerPid.localAddr,
336 udp6RowOwnerPid.localScopeId), localPort));
338 // We increment the pointer to the next row
339 newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6RowOwnerPid));
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);
355 return udpListeners.ToArray();
358 public override IPGlobalStatistics GetIPv4GlobalStatistics(){
359 return new SystemIPGlobalStatistics(AddressFamily.InterNetwork);
361 public override IPGlobalStatistics GetIPv6GlobalStatistics(){
362 return new SystemIPGlobalStatistics(AddressFamily.InterNetworkV6);
365 public override TcpStatistics GetTcpIPv4Statistics(){
366 return new SystemTcpStatistics(AddressFamily.InterNetwork);
368 public override TcpStatistics GetTcpIPv6Statistics(){
369 return new SystemTcpStatistics(AddressFamily.InterNetworkV6);
372 public override UdpStatistics GetUdpIPv4Statistics(){
373 return new SystemUdpStatistics(AddressFamily.InterNetwork);
375 public override UdpStatistics GetUdpIPv6Statistics(){
376 return new SystemUdpStatistics(AddressFamily.InterNetworkV6);
379 public override IcmpV4Statistics GetIcmpV4Statistics(){
380 return new SystemIcmpV4Statistics();
383 public override IcmpV6Statistics GetIcmpV6Statistics(){
384 return new SystemIcmpV6Statistics();
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)) {
395 return GetUnicastAddressTable();
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();
404 asyncResult.FinishPostingAsyncOp();
409 public override UnicastIPAddressInformationCollection EndGetUnicastAddresses(IAsyncResult asyncResult){
410 if (asyncResult == null) {
411 throw new ArgumentNullException("asyncResult");
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));
419 if (result.EndCalled) {
420 throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetStableUnicastAddresses"));
423 result.InternalWaitForCompletion();
425 result.EndCalled = true;
426 return GetUnicastAddressTable();
429 private static void StableUnicastAddressTableCallback(object param){
430 EventWaitHandle handle = param as EventWaitHandle;
431 if (handle != null) {
435 LazyAsyncResult asyncResult = (LazyAsyncResult)param;
436 asyncResult.InvokeCallback();
440 private static UnicastIPAddressInformationCollection GetUnicastAddressTable(){
441 UnicastIPAddressInformationCollection rval = new UnicastIPAddressInformationCollection();
443 NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
444 for (int i = 0; i < interfaces.Length; ++i) {
445 UnicastIPAddressInformationCollection addresses = interfaces[i].GetIPProperties().UnicastAddresses;
447 foreach (UnicastIPAddressInformation address in addresses) {
448 if (!rval.Contains(address)) {
449 rval.InternalAdd(address);
457 } //ends networkinformation class
461 internal struct FixedInfo{
462 internal FIXED_INFO info;
464 internal FixedInfo(FIXED_INFO info){
468 internal string HostName{
470 return info.hostName;
474 internal string DomainName{
476 return info.domainName;
480 internal NetBiosNodeType NodeType{
482 return info.nodeType;
485 internal string ScopeId{
491 internal bool EnableRouting{
493 return info.enableRouting;
497 internal bool EnableProxy{
499 return info.enableProxy;
503 internal bool EnableDns{
505 return info.enableDns;