With Android 7.0 (Nougat) it is no longer possible to read some
[mono.git] / mcs / class / System / System.Net.NetworkInformation / NetworkInterface.cs
index 27927a81f61092cf2d17a009c4e756bc54b62d6a..56d0e4d61f9453ecd233301ebdcf936cb30b354c 100644 (file)
@@ -41,15 +41,11 @@ using System.IO;
 using System.Globalization;
 
 namespace System.Net.NetworkInformation {
-       public abstract class NetworkInterface {
+       static class SystemNetworkInterface {
 
                static readonly NetworkInterfaceFactory nif = NetworkInterfaceFactory.Create ();
 
-               protected NetworkInterface ()
-               {
-               }
-
-               public static NetworkInterface [] GetAllNetworkInterfaces ()
+               public static NetworkInterface [] GetNetworkInterfaces ()
                {
                        try {
                                return nif.GetAllNetworkInterfaces ();
@@ -58,36 +54,28 @@ namespace System.Net.NetworkInformation {
                        }
                }
 
-               [MonoTODO("Always returns true")]
-               public static bool GetIsNetworkAvailable ()
+               public static bool InternalGetIsNetworkAvailable ()
                {
+                       // TODO:
                        return true;
                }
-               
-               public static int LoopbackInterfaceIndex {
+
+               public static int InternalLoopbackInterfaceIndex {
                        get {
                                return nif.GetLoopbackInterfaceIndex ();
                        }
                }
 
+               public static int InternalIPv6LoopbackInterfaceIndex {
+                       get {
+                               throw new NotImplementedException ();
+                       }
+               }
+
                public static IPAddress GetNetMask (IPAddress address)
                {
                        return nif.GetNetMask (address);
                }
-
-               public abstract IPInterfaceProperties GetIPProperties ();
-               public abstract IPv4InterfaceStatistics GetIPv4Statistics ();
-               public abstract PhysicalAddress GetPhysicalAddress ();
-               public abstract bool Supports (NetworkInterfaceComponent networkInterfaceComponent);
-
-               public abstract string Description { get; }
-               public abstract string Id { get; }
-               public abstract bool IsReceiveOnly { get; }
-               public abstract string Name { get; }
-               public abstract NetworkInterfaceType NetworkInterfaceType { get; }
-               public abstract OperationalStatus OperationalStatus { get; }
-               public abstract long Speed { get; }
-               public abstract bool SupportsMulticast { get; }
        }
 
        abstract class NetworkInterfaceFactory
@@ -450,9 +438,14 @@ namespace System.Net.NetworkInformation {
 #if !MOBILE
                class Win32NetworkInterfaceAPI : NetworkInterfaceFactory
                {
-                       [DllImport ("iphlpapi.dll", SetLastError = true)]
+                       private const string IPHLPAPI = "iphlpapi.dll";
+
+                       [DllImport (IPHLPAPI, SetLastError = true)]
                        static extern int GetAdaptersAddresses (uint family, uint flags, IntPtr reserved, byte [] info, ref int size);
 
+                       [DllImport (IPHLPAPI)]
+                       static extern uint GetBestInterfaceEx (byte[] ipAddress, out int index);
+
                        unsafe static Win32_IP_ADAPTER_ADDRESSES [] GetAdaptersAddresses ()
                        {
                                byte [] bytes = null;
@@ -485,9 +478,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)
@@ -627,6 +631,19 @@ namespace System.Net.NetworkInformation {
                string               iface_operstate_path;
                string               iface_flags_path;          
 
+#if MONODROID
+               [DllImport ("__Internal")]
+               protected static extern int _monodroid_get_android_api_level ();
+
+               [DllImport ("__Internal")]
+               protected static extern bool _monodroid_get_network_interface_up_state (string ifname, ref bool is_up);
+
+               [DllImport ("__Internal")]
+               protected 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; }
                }
@@ -637,6 +654,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 ()
@@ -655,6 +675,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;
                                
@@ -691,6 +728,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;