
    /// <summary><para>
    ///    Provides support for ip configuation information and statistics.
    ///</para></summary>
    ///
namespace System.Net.NetworkInformation {
    using System.Net;
    using System.Net.Sockets;
    using System;
    using System.Runtime.InteropServices;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    
    internal class SystemNetworkInterface:NetworkInterface {

        //common properties
        private string name;
        private string id;
        private string description;
        private byte[] physicalAddress;
        private uint addressLength;
        private NetworkInterfaceType type;
        private OperationalStatus operStatus;
        private long speed;
        //Unfortunately, any interface can
        //have two completely different valid indexes for ipv4 and ipv6
        private uint index = 0;
        private uint ipv6Index = 0;
        private AdapterFlags adapterFlags;
        private SystemIPInterfaceProperties interfaceProperties = null;

        internal static int InternalLoopbackInterfaceIndex {
            get {
                return GetBestInterfaceForAddress(IPAddress.Loopback);
            }
        }

        internal static int InternalIPv6LoopbackInterfaceIndex {
            get {
                return GetBestInterfaceForAddress(IPAddress.IPv6Loopback);
            }
        }

        private static int GetBestInterfaceForAddress(IPAddress addr) {
            int index;
            SocketAddress address = new SocketAddress(addr);
            int error = (int)UnsafeNetInfoNativeMethods.GetBestInterfaceEx(address.m_Buffer, out index);
            if (error != 0) {
                throw new NetworkInformationException(error);
            }

            return index;
        }

        internal static bool InternalGetIsNetworkAvailable(){

            try {
                NetworkInterface[] networkInterfaces = GetNetworkInterfaces();
                foreach (NetworkInterface netInterface in networkInterfaces) {
                    if (netInterface.OperationalStatus == OperationalStatus.Up && netInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel
                        && netInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback){
                        return true;
                    }
                }
            }
            catch (NetworkInformationException nie) {
                if (Logging.On) Logging.Exception(Logging.Web, "SystemNetworkInterface", "InternalGetIsNetworkAvailable", nie);
            }

            return false;
        }

        // Vista+
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods",
            Justification = "DangerousGetHandle is required for marshaling")]
        internal static NetworkInterface[] GetNetworkInterfaces() {
            Contract.Ensures(Contract.Result<NetworkInterface[]>() != null);
            AddressFamily family = AddressFamily.Unspecified;
            uint bufferSize = 0;
            SafeLocalFree buffer = null;
            FixedInfo fixedInfo = SystemIPGlobalProperties.GetFixedInfo();
            List<SystemNetworkInterface> interfaceList = new List<SystemNetworkInterface>();

            GetAdaptersAddressesFlags flags = 
                GetAdaptersAddressesFlags.IncludeGateways
                | GetAdaptersAddressesFlags.IncludeWins;

            // Figure out the right buffer size for the adapter information
            uint result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(
                family, (uint)flags, IntPtr.Zero, SafeLocalFree.Zero, ref bufferSize);

            while (result == IpHelperErrors.ErrorBufferOverflow) {
                try {
                    // Allocate the buffer and get the adapter info
                    buffer = SafeLocalFree.LocalAlloc((int)bufferSize);
                    result = UnsafeNetInfoNativeMethods.GetAdaptersAddresses(
                        family, (uint)flags, IntPtr.Zero, buffer, ref bufferSize);

                    // If succeeded, we're going to add each new interface
                    if (result == IpHelperErrors.Success) {
                        // Linked list of interfaces
                        IntPtr ptr = buffer.DangerousGetHandle();
                        while (ptr != IntPtr.Zero) {
                            // Traverse the list, marshal in the native structures, and create new NetworkInterfaces
                            IpAdapterAddresses adapterAddresses = 
                                (IpAdapterAddresses)Marshal.PtrToStructure(ptr, typeof(IpAdapterAddresses));
                            interfaceList.Add(new SystemNetworkInterface(fixedInfo, adapterAddresses));

                            ptr = adapterAddresses.next;
                        }
                    }
                }
                finally {
                    if (buffer != null) {
                        buffer.Close();
                    }
                    buffer = null;
                }
            }

            // if we don't have any interfaces detected, return empty.
            if (result == IpHelperErrors.ErrorNoData || result == IpHelperErrors.ErrorInvalidParameter) {
                return new SystemNetworkInterface[0];
            }

            // Otherwise we throw on an error
            if (result != IpHelperErrors.Success) {
                throw new NetworkInformationException((int)result);
            }

            return interfaceList.ToArray();
        }

        // Vista+
        internal SystemNetworkInterface(FixedInfo fixedInfo, IpAdapterAddresses ipAdapterAddresses) {
            //store the common api information
            id = ipAdapterAddresses.AdapterName;
            name = ipAdapterAddresses.friendlyName;
            description = ipAdapterAddresses.description;
            index = ipAdapterAddresses.index;

            physicalAddress = ipAdapterAddresses.address;
            addressLength = ipAdapterAddresses.addressLength;

            type = ipAdapterAddresses.type;
            operStatus = ipAdapterAddresses.operStatus;
            speed = (long)ipAdapterAddresses.receiveLinkSpeed;

            //api specific info
            ipv6Index = ipAdapterAddresses.ipv6Index;

            adapterFlags = ipAdapterAddresses.flags;
            interfaceProperties = new SystemIPInterfaceProperties(fixedInfo, ipAdapterAddresses);
        }
        
        /// Basic Properties
        
        public override string Id{get {return id;}}
        public override string Name{get {return name;}}
        public override string Description{get {return description;}}
             
        public override PhysicalAddress GetPhysicalAddress(){
            byte[] newAddr = new byte[addressLength];
            Array.Copy(physicalAddress,newAddr,addressLength);
            return new PhysicalAddress(newAddr);
        }
        public override NetworkInterfaceType NetworkInterfaceType{get {return type;}}

        public override IPInterfaceProperties GetIPProperties(){
            return interfaceProperties;
        }
        
        /// Despite the naming, the results are not IPv4 specific.
        /// Do not use this method, use GetIPStatistics instead.
        /// <include file='doc\NetworkInterface.uex' path='docs/doc[@for="NetworkInterface.GetInterfaceStatistics"]/*' />
        public override IPv4InterfaceStatistics GetIPv4Statistics(){
            return new SystemIPv4InterfaceStatistics(index);
        }
        
        public override IPInterfaceStatistics GetIPStatistics() {
            return new SystemIPInterfaceStatistics(index);
        }

        public override bool Supports(NetworkInterfaceComponent networkInterfaceComponent){
            if (networkInterfaceComponent ==  NetworkInterfaceComponent.IPv6 
                && ((adapterFlags & AdapterFlags.IPv6Enabled) != 0)) {
                return true;
            }
            if (networkInterfaceComponent == NetworkInterfaceComponent.IPv4
                && ((adapterFlags & AdapterFlags.IPv4Enabled) != 0)) {
                return true;
            }
            return false;
        }

        //We cache this to be consistent across all platforms
        public override OperationalStatus OperationalStatus{
            get {
                return operStatus;
            }
        }

        public override long Speed{
            get {
                return speed;
            }
        }  

        public override bool IsReceiveOnly {
            get {
                return ((adapterFlags & AdapterFlags.ReceiveOnly) > 0);
            }
        }
        /// <summary>The interface doesn't allow multicast.</summary>
        public override bool SupportsMulticast {
            get {
                return ((adapterFlags & AdapterFlags.NoMulticast) == 0);
            }
        }
    }
}



