File: net\System\Net\NetworkInformation\SystemIPGlobalProperties.cs
Project: ndp\fx\src\System.csproj (System)

 
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;
            }
        }
 
        /// <summary>Specifies the host name for the local computer.</summary>
        public override string HostName{
            get {
                if(hostName == null){
                    lock(syncObject){
                        if(hostName == null){
                            hostName = FixedInfo.HostName;
                            domainName = FixedInfo.DomainName;
                        }
                    }
                }
                return hostName;
            }
        }
        /// <summary>Specifies the domain in which the local computer is registered.</summary>
        public override string DomainName{
            get {
                if(domainName == null){
                    lock(syncObject){
                        if(domainName == null){
                            hostName = FixedInfo.HostName;
                            domainName = FixedInfo.DomainName;
                        }
                    }
                }
                return domainName;
            }
        }
        /// <summary>
        /// The type of node.
        /// </summary>
        /// <remarks>
        /// 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.
        /// </remarks>
        public override NetBiosNodeType NodeType{get {
            return (NetBiosNodeType)FixedInfo.NodeType;}
        }
        /// <summary>Specifies the DHCP scope name.</summary>
        public override string DhcpScopeName{get {
            return FixedInfo.ScopeId;}
        }
        /// <summary>Specifies whether the local computer is acting as an WINS proxy.</summary>
        public override bool IsWinsProxy{get {
            return (FixedInfo.EnableProxy);}
        }
 
          
        public override TcpConnectionInformation[] GetActiveTcpConnections(){
            List<TcpConnectionInformation> list = new List<TcpConnectionInformation>();
            List<SystemTcpConnectionInformation> connections = GetAllTcpConnections();
            foreach(TcpConnectionInformation connection in connections){
                if(connection.State != TcpState.Listen){
                    list.Add(connection);
                }
            }
            return list.ToArray();
        }
 
 
        public override IPEndPoint[] GetActiveTcpListeners (){
            List<IPEndPoint> list = new List<IPEndPoint>();
            List<SystemTcpConnectionInformation> connections = GetAllTcpConnections();
            foreach(TcpConnectionInformation connection in connections){
                if(connection.State == TcpState.Listen){
                    list.Add(connection.LocalEndPoint);
                }
            }
            return list.ToArray();
        }
 
 
 
        /// <summary>
        /// Gets the active tcp connections. Uses the native GetTcpTable api.</summary>
        private List<SystemTcpConnectionInformation> GetAllTcpConnections() {
            uint size = 0;
            uint result = 0;
            SafeLocalFree buffer = null;
            List<SystemTcpConnectionInformation> tcpConnections = new List<SystemTcpConnectionInformation>();
 
            // 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;
        }
 
 
 
 
        /// <summary>Gets the active udp listeners. Uses the native GetUdpTable api.</summary>
        public override IPEndPoint[] GetActiveUdpListeners(){
            uint    size = 0;
            uint result = 0;
            SafeLocalFree buffer = null;
            List<IPEndPoint> udpListeners = new List<IPEndPoint>();
 
            // 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;
            }
        }
    }
}