Merge pull request #5198 from BrzVlad/fix-binprot-stats
[mono.git] / mcs / class / System / System.Net.NetworkInformation / NetworkInterface.cs
index ece698af2b45ee2714a2c52e822ce4a09c90083d..fedf95dbb4d323b3fda4dae6266c6a27f99bb15a 100644 (file)
@@ -82,6 +82,22 @@ namespace System.Net.NetworkInformation {
        {
                internal abstract class UnixNetworkInterfaceAPI : NetworkInterfaceFactory
                {
+#if ORBIS
+                       public static int if_nametoindex(string ifname)
+                       {
+                               throw new PlatformNotSupportedException ();
+                       }
+
+                       protected static int getifaddrs (out IntPtr ifap)
+                       {
+                               throw new PlatformNotSupportedException ();
+                       }
+
+                       protected static void freeifaddrs (IntPtr ifap)
+                       {
+                               throw new PlatformNotSupportedException ();
+                       }
+#else
                        [DllImport("libc")]
                        public static extern int if_nametoindex(string ifname);
 
@@ -90,6 +106,7 @@ namespace System.Net.NetworkInformation {
 
                        [DllImport ("libc")]
                        protected static extern void freeifaddrs (IntPtr ifap);
+#endif
                }
 
                class MacOsNetworkInterfaceAPI : UnixNetworkInterfaceAPI
@@ -290,8 +307,6 @@ namespace System.Net.NetworkInformation {
                                                        } else if (sockaddr.sin_family == AF_PACKET) {
                                                                sockaddr_ll sockaddrll = (sockaddr_ll) Marshal.PtrToStructure (addr.ifa_addr, typeof (sockaddr_ll));
                                                                if (((int)sockaddrll.sll_halen) > sockaddrll.sll_addr.Length){
-                                                                       Console.Error.WriteLine ("Got a bad hardware address length for an AF_PACKET {0} {1}",
-                                                                                                sockaddrll.sll_halen, sockaddrll.sll_addr.Length);
                                                                        next = addr.ifa_next;
                                                                        continue;
                                                                }
@@ -435,31 +450,34 @@ namespace System.Net.NetworkInformation {
                        }
                }
 
-#if !MOBILE
+#if WIN_PLATFORM
                class Win32NetworkInterfaceAPI : NetworkInterfaceFactory
                {
-                       [DllImport ("iphlpapi.dll", SetLastError = true)]
-                       static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
+                       private const string IPHLPAPI = "iphlpapi.dll";
 
-                       unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
+                       [DllImport (IPHLPAPI, SetLastError = true)]
+                       static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, IntPtr info, ref int size);
+
+                       [DllImport (IPHLPAPI)]
+                       static extern uint GetBestInterfaceEx (byte[] ipAddress, out int index);
+
+                       static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
                        {
-                               byte [] bytes = null;
+                               IntPtr ptr = IntPtr.Zero;
                                int len = 0;
-                               GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
-                               bytes = new byte [len];
-                               int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, bytes, ref len);
+                               GetAdaptersAddresses (0, 0, IntPtr.Zero, ptr, ref len);
+                               ptr = Marshal.AllocHGlobal(len);
+                               int ret = GetAdaptersAddresses (0, 0, IntPtr.Zero, ptr, ref len);
                                if (ret != 0)
                                        throw new NetworkInformationException (ret);
 
                                List<Win32_IP_ADAPTER_ADDRESSES> l = new List<Win32_IP_ADAPTER_ADDRESSES> ();
-                               fixed (byte* ptr = bytes) {
-                                       Win32_IP_ADAPTER_ADDRESSES info;
-                                       for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
-                                               info = new Win32_IP_ADAPTER_ADDRESSES ();
-                                               Marshal.PtrToStructure (p, info);
-                                               l.Add (info);
-                                       }
+                               Win32_IP_ADAPTER_ADDRESSES info;
+                               for (IntPtr p = ptr; p != IntPtr.Zero; p = info.Next) {
+                                       info = Marshal.PtrToStructure<Win32_IP_ADAPTER_ADDRESSES> (p);
+                                       l.Add (info);
                                }
+
                                return l.ToArray ();
                        }
 
@@ -473,9 +491,20 @@ namespace System.Net.NetworkInformation {
                                return ret;
                        }
 
+                       private static int GetBestInterfaceForAddress (IPAddress addr) {
+                               int index;
+                               SocketAddress address = new SocketAddress (addr);
+                               int error = (int) GetBestInterfaceEx (address.m_Buffer, out index);
+                               if (error != 0) {
+                                       throw new NetworkInformationException (error);
+                               }
+
+                               return index;
+                       }
+
                        public override int GetLoopbackInterfaceIndex ()
                        {
-                               throw new NotImplementedException ();
+                               return GetBestInterfaceForAddress (IPAddress.Loopback);
                        }
 
                        public override IPAddress GetNetMask (IPAddress address)
@@ -494,7 +523,6 @@ namespace System.Net.NetworkInformation {
 #if MONOTOUCH || XAMMAC
                        return new MacOsNetworkInterfaceAPI ();
 #else
-                       Version windowsVer51 = new Version (5, 1);
                        bool runningOnUnix = (Environment.OSVersion.Platform == PlatformID.Unix);
 
                        if (runningOnUnix) {
@@ -504,7 +532,8 @@ namespace System.Net.NetworkInformation {
                                return new LinuxNetworkInterfaceAPI ();
                        }
 
-#if !MOBILE
+#if WIN_PLATFORM
+                       Version windowsVer51 = new Version (5, 1);
                        if (Environment.OSVersion.Version >= windowsVer51)
                                return new Win32NetworkInterfaceAPI ();
 #endif
@@ -615,6 +644,19 @@ namespace System.Net.NetworkInformation {
                string               iface_operstate_path;
                string               iface_flags_path;          
 
+#if MONODROID
+               [DllImport ("__Internal")]
+               static extern int _monodroid_get_android_api_level ();
+
+               [DllImport ("__Internal")]
+               static extern bool _monodroid_get_network_interface_up_state (string ifname, ref bool is_up);
+
+               [DllImport ("__Internal")]
+               static extern bool _monodroid_get_network_interface_supports_multicast (string ifname, ref bool supports_multicast);
+
+               bool android_use_java_api;
+#endif
+
                internal string IfacePath {
                        get { return iface_path; }
                }
@@ -625,6 +667,9 @@ namespace System.Net.NetworkInformation {
                        iface_path = "/sys/class/net/" + name + "/";
                        iface_operstate_path = iface_path + "operstate";
                        iface_flags_path = iface_path + "flags";
+#if MONODROID
+                       android_use_java_api = _monodroid_get_android_api_level () >= 24;
+#endif
                }
 
                public override IPInterfaceProperties GetIPProperties ()
@@ -643,6 +688,23 @@ namespace System.Net.NetworkInformation {
 
                public override OperationalStatus OperationalStatus {
                        get {
+#if MONODROID
+                               if (android_use_java_api) {
+                                       // Starting from API 24 (Android 7 "Nougat") Android restricts access to many
+                                       // files in the /sys filesystem (see https://code.google.com/p/android/issues/detail?id=205565
+                                       // for more information) and therefore we are forced to call into Java API in
+                                       // order to get the information. Alas, what we can obtain in this way is quite
+                                       // limited. In the case of OperationalStatus we can only determine whether the
+                                       // interface is up or down. There is a way to get more detailed information but
+                                       // it requires an instance of the Android Context class which is not available
+                                       // to us here.
+                                       bool is_up = false;
+                                       if (_monodroid_get_network_interface_up_state (Name, ref is_up))
+                                               return is_up ? OperationalStatus.Up : OperationalStatus.Down;
+                                       else
+                                               return OperationalStatus.Unknown;
+                               }
+#endif
                                if (!Directory.Exists (iface_path))
                                        return OperationalStatus.Unknown;
                                
@@ -679,6 +741,17 @@ namespace System.Net.NetworkInformation {
 
                public override bool SupportsMulticast {
                        get {
+#if MONODROID
+                               if (android_use_java_api) {
+                                       // Starting from API 24 (Android 7 "Nougat") Android restricts access to many
+                                       // files in the /sys filesystem (see https://code.google.com/p/android/issues/detail?id=205565
+                                       // for more information) and therefore we are forced to call into Java API in
+                                       // order to get the information.
+                                       bool supports_multicast = false;
+                                       _monodroid_get_network_interface_supports_multicast (Name, ref supports_multicast);
+                                       return supports_multicast;
+                               }
+#endif
                                if (!Directory.Exists (iface_path))
                                        return false;
                                
@@ -747,11 +820,11 @@ namespace System.Net.NetworkInformation {
                }
        }
 
-#if !MOBILE
+#if WIN_PLATFORM
        class Win32NetworkInterface2 : NetworkInterface
        {
                [DllImport ("iphlpapi.dll", SetLastError = true)]
-               static extern int GetAdaptersInfo (byte [] info, ref int size);
+               static extern int GetAdaptersInfo (IntPtr info, ref int size);
 
                [DllImport ("iphlpapi.dll", SetLastError = true)]
                static extern int GetIfEntry (ref Win32_MIB_IFROW row);
@@ -761,28 +834,25 @@ namespace System.Net.NetworkInformation {
                        foreach (Win32_IP_ADAPTER_INFO info in GetAdaptersInfo ())
                                if (info.Index == index)
                                        return info;
-                       return null;
+                       throw new IndexOutOfRangeException ("No adapter found for index " + index);
                }
 
-               unsafe static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
+               static Win32_IP_ADAPTER_INFO [] GetAdaptersInfo ()
                {
-                       byte [] bytes = null;
                        int len = 0;
-                       GetAdaptersInfo (bytes, ref len);
-                       bytes = new byte [len];
-                       int ret = GetAdaptersInfo (bytes, ref len);
+                       IntPtr ptr = IntPtr.Zero;
+                       GetAdaptersInfo (ptr, ref len);
+                       ptr = Marshal.AllocHGlobal(len);
+                       int ret = GetAdaptersInfo (ptr, ref len);
 
                        if (ret != 0)
                                throw new NetworkInformationException (ret);
 
                        List<Win32_IP_ADAPTER_INFO> l = new List<Win32_IP_ADAPTER_INFO> ();
-                       fixed (byte* ptr = bytes) {
-                               Win32_IP_ADAPTER_INFO info;
-                               for (IntPtr p = (IntPtr) ptr; p != IntPtr.Zero; p = info.Next) {
-                                       info = new Win32_IP_ADAPTER_INFO ();
-                                       Marshal.PtrToStructure (p, info);
-                                       l.Add (info);
-                               }
+                       Win32_IP_ADAPTER_INFO info;
+                       for (IntPtr p = ptr; p != IntPtr.Zero; p = info.Next) {
+                               info = Marshal.PtrToStructure<Win32_IP_ADAPTER_INFO> (p);
+                               l.Add (info);
                        }
                        return l.ToArray ();
                }