namespace System.Net.NetworkInformation { using System.Net; using System.Net.Sockets; using System; using System.Runtime.InteropServices; using System.Threading; using System.Collections.Generic; internal class SystemIPGlobalProperties:IPGlobalProperties { private FixedInfo fixedInfo; private bool fixedInfoInitialized = false; //changing these require a reboot, so we'll cache them instead. private static volatile string hostName = null; private static volatile string domainName = null; static object syncObject = new object(); internal SystemIPGlobalProperties() { } internal static FixedInfo GetFixedInfo(){ uint size = 0; SafeLocalFree buffer = null; FixedInfo fixedInfo = new FixedInfo(); //first we need to get the size of the buffer uint result = UnsafeNetInfoNativeMethods.GetNetworkParams(SafeLocalFree.Zero,ref size); while (result == IpHelperErrors.ErrorBufferOverflow) { try { //now we allocate the buffer and read the network parameters. buffer = SafeLocalFree.LocalAlloc((int)size); result = UnsafeNetInfoNativeMethods.GetNetworkParams(buffer,ref size); if ( result == IpHelperErrors.Success ) { fixedInfo = new FixedInfo( (FIXED_INFO)Marshal.PtrToStructure(buffer.DangerousGetHandle(),typeof(FIXED_INFO))); } } finally { if(buffer != null){ buffer.Close(); } } } //if the result include there being no information, we'll still throw if (result != IpHelperErrors.Success) { throw new NetworkInformationException((int)result); } return fixedInfo; } internal FixedInfo FixedInfo { get { if (!fixedInfoInitialized) { lock(this){ if (!fixedInfoInitialized) { fixedInfo = GetFixedInfo(); fixedInfoInitialized = true; } } } return fixedInfo; } } /// Specifies the host name for the local computer. public override string HostName{ get { if(hostName == null){ lock(syncObject){ if(hostName == null){ hostName = FixedInfo.HostName; domainName = FixedInfo.DomainName; } } } return hostName; } } /// Specifies the domain in which the local computer is registered. public override string DomainName{ get { if(domainName == null){ lock(syncObject){ if(domainName == null){ hostName = FixedInfo.HostName; domainName = FixedInfo.DomainName; } } } return domainName; } } /// /// The type of node. /// /// /// The exact mechanism by which NetBIOS names are resolved to IP addresses /// depends on the node's configured NetBIOS Node Type. Broadcast - uses broadcast /// NetBIOS Name Queries for name registration and resolution. /// PeerToPeer - uses a NetBIOS name server (NBNS), such as Windows Internet /// Name Service (WINS), to resolve NetBIOS names. /// Mixed - uses Broadcast then PeerToPeer. /// Hybrid - uses PeerToPeer then Broadcast. /// public override NetBiosNodeType NodeType{get { return (NetBiosNodeType)FixedInfo.NodeType;} } /// Specifies the DHCP scope name. public override string DhcpScopeName{get { return FixedInfo.ScopeId;} } /// Specifies whether the local computer is acting as an WINS proxy. public override bool IsWinsProxy{get { return (FixedInfo.EnableProxy);} } public override TcpConnectionInformation[] GetActiveTcpConnections(){ List list = new List(); List connections = GetAllTcpConnections(); foreach(TcpConnectionInformation connection in connections){ if(connection.State != TcpState.Listen){ list.Add(connection); } } return list.ToArray(); } public override IPEndPoint[] GetActiveTcpListeners (){ List list = new List(); List connections = GetAllTcpConnections(); foreach(TcpConnectionInformation connection in connections){ if(connection.State == TcpState.Listen){ list.Add(connection.LocalEndPoint); } } return list.ToArray(); } /// /// Gets the active tcp connections. Uses the native GetTcpTable api. private List GetAllTcpConnections() { uint size = 0; uint result = 0; SafeLocalFree buffer = null; List tcpConnections = new List(); // Check if it supports IPv4 for IPv6 only modes. if (Socket.OSSupportsIPv4) { // Get the size of buffer needed result = UnsafeNetInfoNativeMethods.GetTcpTable(SafeLocalFree.Zero, ref size, true); while (result == IpHelperErrors.ErrorInsufficientBuffer) { try { //allocate the buffer and get the tcptable buffer = SafeLocalFree.LocalAlloc((int)size); result = UnsafeNetInfoNativeMethods.GetTcpTable(buffer, ref size, true); if (result == IpHelperErrors.Success) { //the table info just gives us the number of rows. IntPtr newPtr = buffer.DangerousGetHandle(); MibTcpTable tcpTableInfo = (MibTcpTable)Marshal.PtrToStructure(newPtr, typeof(MibTcpTable)); if (tcpTableInfo.numberOfEntries > 0) { //we need to skip over the tableinfo to get the inline rows newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpTableInfo.numberOfEntries)); for (int i = 0; i < tcpTableInfo.numberOfEntries; i++) { MibTcpRow tcpRow = (MibTcpRow)Marshal.PtrToStructure(newPtr, typeof(MibTcpRow)); tcpConnections.Add(new SystemTcpConnectionInformation(tcpRow)); //we increment the pointer to the next row newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpRow)); } } } } finally { if (buffer != null) buffer.Close(); } } // if we don't have any ipv4 interfaces detected, just continue if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) { throw new NetworkInformationException((int)result); } } if (Socket.OSSupportsIPv6) { // IPv6 tcp connections // Get the size of buffer needed size = 0; result = UnsafeNetInfoNativeMethods.GetExtendedTcpTable(SafeLocalFree.Zero, ref size, true, (uint)AddressFamily.InterNetworkV6, TcpTableClass.TcpTableOwnerPidAll, 0); while (result == IpHelperErrors.ErrorInsufficientBuffer) { try { // Allocate the buffer and get the tcptable buffer = SafeLocalFree.LocalAlloc((int)size); result = UnsafeNetInfoNativeMethods.GetExtendedTcpTable(buffer, ref size, true, (uint)AddressFamily.InterNetworkV6, TcpTableClass.TcpTableOwnerPidAll, 0); if (result == IpHelperErrors.Success) { // The table info just gives us the number of rows. IntPtr newPtr = buffer.DangerousGetHandle(); MibTcp6TableOwnerPid tcpTable6OwnerPid = (MibTcp6TableOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibTcp6TableOwnerPid)); if (tcpTable6OwnerPid.numberOfEntries > 0) { // We need to skip over the tableinfo to get the inline rows newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcpTable6OwnerPid.numberOfEntries)); for (int i = 0; i < tcpTable6OwnerPid.numberOfEntries; i++) { MibTcp6RowOwnerPid tcp6RowOwnerPid = (MibTcp6RowOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibTcp6RowOwnerPid)); tcpConnections.Add(new SystemTcpConnectionInformation(tcp6RowOwnerPid)); // We increment the pointer to the next row newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(tcp6RowOwnerPid)); } } } } finally { if (buffer != null) buffer.Close(); } } // If we don't have any ipv6 interfaces detected, just continue if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) { throw new NetworkInformationException((int)result); } } return tcpConnections; } /// Gets the active udp listeners. Uses the native GetUdpTable api. public override IPEndPoint[] GetActiveUdpListeners(){ uint size = 0; uint result = 0; SafeLocalFree buffer = null; List udpListeners = new List(); // Check if it support IPv4 for IPv6 only modes. if (Socket.OSSupportsIPv4) { // Get the size of buffer needed result = UnsafeNetInfoNativeMethods.GetUdpTable(SafeLocalFree.Zero, ref size, true); while (result == IpHelperErrors.ErrorInsufficientBuffer) { try { //allocate the buffer and get the udptable buffer = SafeLocalFree.LocalAlloc((int)size); result = UnsafeNetInfoNativeMethods.GetUdpTable(buffer, ref size, true); if (result == IpHelperErrors.Success) { //the table info just gives us the number of rows. IntPtr newPtr = buffer.DangerousGetHandle(); MibUdpTable udpTableInfo = (MibUdpTable)Marshal.PtrToStructure(newPtr, typeof(MibUdpTable)); if (udpTableInfo.numberOfEntries > 0) { //we need to skip over the tableinfo to get the inline rows newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpTableInfo.numberOfEntries)); for (int i = 0; i < udpTableInfo.numberOfEntries; i++) { MibUdpRow udpRow = (MibUdpRow)Marshal.PtrToStructure(newPtr, typeof(MibUdpRow)); int localPort = udpRow.localPort1 << 8 | udpRow.localPort2; udpListeners.Add(new IPEndPoint(udpRow.localAddr, (int)localPort)); //we increment the pointer to the next row newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udpRow)); } } } } finally { if (buffer != null) buffer.Close(); } } // if we don't have any ipv4 interfaces detected, just continue if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) { throw new NetworkInformationException((int)result); } } if (Socket.OSSupportsIPv6) { // Get the size of buffer needed size = 0; result = UnsafeNetInfoNativeMethods.GetExtendedUdpTable(SafeLocalFree.Zero, ref size, true, (uint)AddressFamily.InterNetworkV6, UdpTableClass.UdpTableOwnerPid, 0); while (result == IpHelperErrors.ErrorInsufficientBuffer) { try { // Allocate the buffer and get the udptable buffer = SafeLocalFree.LocalAlloc((int)size); result = UnsafeNetInfoNativeMethods.GetExtendedUdpTable(buffer, ref size, true, (uint)AddressFamily.InterNetworkV6, UdpTableClass.UdpTableOwnerPid, 0); if (result == IpHelperErrors.Success) { // The table info just gives us the number of rows. IntPtr newPtr = buffer.DangerousGetHandle(); MibUdp6TableOwnerPid udp6TableOwnerPid = (MibUdp6TableOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibUdp6TableOwnerPid)); if (udp6TableOwnerPid.numberOfEntries > 0) { // We need to skip over the tableinfo to get the inline rows newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6TableOwnerPid.numberOfEntries)); for (int i = 0; i < udp6TableOwnerPid.numberOfEntries; i++) { MibUdp6RowOwnerPid udp6RowOwnerPid = (MibUdp6RowOwnerPid)Marshal.PtrToStructure(newPtr, typeof(MibUdp6RowOwnerPid)); int localPort = udp6RowOwnerPid.localPort1 << 8 | udp6RowOwnerPid.localPort2; udpListeners.Add(new IPEndPoint(new IPAddress(udp6RowOwnerPid.localAddr, udp6RowOwnerPid.localScopeId), localPort)); // We increment the pointer to the next row newPtr = (IntPtr)((long)newPtr + Marshal.SizeOf(udp6RowOwnerPid)); } } } } finally { if (buffer != null) buffer.Close(); } } // If we don't have any ipv6 interfaces detected, just continue if (result != IpHelperErrors.Success && result != IpHelperErrors.ErrorNoData) { throw new NetworkInformationException((int)result); } } return udpListeners.ToArray(); } public override IPGlobalStatistics GetIPv4GlobalStatistics(){ return new SystemIPGlobalStatistics(AddressFamily.InterNetwork); } public override IPGlobalStatistics GetIPv6GlobalStatistics(){ return new SystemIPGlobalStatistics(AddressFamily.InterNetworkV6); } public override TcpStatistics GetTcpIPv4Statistics(){ return new SystemTcpStatistics(AddressFamily.InterNetwork); } public override TcpStatistics GetTcpIPv6Statistics(){ return new SystemTcpStatistics(AddressFamily.InterNetworkV6); } public override UdpStatistics GetUdpIPv4Statistics(){ return new SystemUdpStatistics(AddressFamily.InterNetwork); } public override UdpStatistics GetUdpIPv6Statistics(){ return new SystemUdpStatistics(AddressFamily.InterNetworkV6); } public override IcmpV4Statistics GetIcmpV4Statistics(){ return new SystemIcmpV4Statistics(); } public override IcmpV6Statistics GetIcmpV6Statistics(){ return new SystemIcmpV6Statistics(); } public override UnicastIPAddressInformationCollection GetUnicastAddresses(){ // Wait for the Address Table to stabilize using (ManualResetEvent stable = new ManualResetEvent(false)) { if (!TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, stable)) { stable.WaitOne(); } } return GetUnicastAddressTable(); } public override IAsyncResult BeginGetUnicastAddresses(AsyncCallback callback, object state){ ContextAwareResult asyncResult = new ContextAwareResult(false, false, this, state, callback); asyncResult.StartPostingAsyncOp(false); if (TeredoHelper.UnsafeNotifyStableUnicastIpAddressTable(StableUnicastAddressTableCallback, asyncResult)) { asyncResult.InvokeCallback(); } asyncResult.FinishPostingAsyncOp(); return asyncResult; } public override UnicastIPAddressInformationCollection EndGetUnicastAddresses(IAsyncResult asyncResult){ if (asyncResult == null) { throw new ArgumentNullException("asyncResult"); } ContextAwareResult result = asyncResult as ContextAwareResult; if (result == null || result.AsyncObject == null || result.AsyncObject.GetType() != typeof(SystemIPGlobalProperties)) { throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult)); } if (result.EndCalled) { throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetStableUnicastAddresses")); } result.InternalWaitForCompletion(); result.EndCalled = true; return GetUnicastAddressTable(); } private static void StableUnicastAddressTableCallback(object param){ EventWaitHandle handle = param as EventWaitHandle; if (handle != null) { handle.Set(); } else { LazyAsyncResult asyncResult = (LazyAsyncResult)param; asyncResult.InvokeCallback(); } } private static UnicastIPAddressInformationCollection GetUnicastAddressTable(){ UnicastIPAddressInformationCollection rval = new UnicastIPAddressInformationCollection(); NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); for (int i = 0; i < interfaces.Length; ++i) { UnicastIPAddressInformationCollection addresses = interfaces[i].GetIPProperties().UnicastAddresses; foreach (UnicastIPAddressInformation address in addresses) { if (!rval.Contains(address)) { rval.InternalAdd(address); } } } return rval; } } //ends networkinformation class internal struct FixedInfo{ internal FIXED_INFO info; internal FixedInfo(FIXED_INFO info){ this.info = info; } internal string HostName{ get{ return info.hostName; } } internal string DomainName{ get{ return info.domainName; } } internal NetBiosNodeType NodeType{ get{ return info.nodeType; } } internal string ScopeId{ get{ return info.scopeId; } } internal bool EnableRouting{ get{ return info.enableRouting; } } internal bool EnableProxy{ get{ return info.enableProxy; } } internal bool EnableDns{ get{ return info.enableDns; } } } }