From 6f494294b4147ce7f1e151778d62bc934e147cb3 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Tue, 11 Jan 2022 15:18:34 +0100 Subject: [PATCH 1/3] [Android] Fix accessing network interfaces information (#62780) * Re-enable tests * Dynamically load getifaddrs if necessary * Prevent redeclaration of the ifaddrs struct * Fix typo * Do not close the dynamic library * Enable the fixed functional tests in CI * Reduce code duplication for obtaining libc file name * Simplify usage of the function pointers * Move typedefs * Rename the _ensure_ function * Remove fptr typedefs * Update comment * Add missing include * Update comment * Remove unnecessary comment * Move static variable * Remove unnecessary change * Move LIBC_FILENAME to the utilities header * Avoid error if constant is undefined * Conditionally include ifaddrs * Try to fix cmake_symbol_exists issue for browser * Minor tweaks * Try different way of detecting getifaddrs * Use the hack only for Android builds * Revert "Move LIBC_FILENAME to the utilities header" This reverts commit 4e6768718a09002680d55a13ba2693eded03d749. * Revert "Reduce code duplication for obtaining libc file name" This reverts commit aca15d1c169196ce2710a328ebb2210ccbefd283. * Simplify opening libc * Update code style * Fix race condition * Prevent race condition * Switch locking implementation for a lock-free implementation * Enable unit test for Android * Try using weak symbols * Fix function name * Revert "Fix function name" This reverts commit f927aaec9f439e70378806cd7b6947bdc9f216fd. * Revert "Try using weak symbols" This reverts commit 46d3edeed0a7f23cdcc1e4b7bbcb167b04835097. * Refactor code to use pthread_once --- .../Native/Unix/Common/pal_config.h.in | 1 + .../System.Native/pal_interfaceaddresses.c | 77 +++++++++++++++++-- src/libraries/Native/Unix/configure.cmake | 16 +++- .../FunctionalTests/IPGlobalPropertiesTest.cs | 5 +- .../NetworkInterfaceBasicTest.cs | 9 +-- src/libraries/tests.proj | 1 - src/mono/cmake/config.h.in | 3 + 7 files changed, 95 insertions(+), 17 deletions(-) diff --git a/src/libraries/Native/Unix/Common/pal_config.h.in b/src/libraries/Native/Unix/Common/pal_config.h.in index 9cffccbb0cc71..8d0d191d1c73d 100644 --- a/src/libraries/Native/Unix/Common/pal_config.h.in +++ b/src/libraries/Native/Unix/Common/pal_config.h.in @@ -12,6 +12,7 @@ #cmakedefine01 HAVE_F_FULLFSYNC #cmakedefine01 HAVE_O_CLOEXEC #cmakedefine01 HAVE_GETIFADDRS +#cmakedefine01 HAVE_IFADDRS #cmakedefine01 HAVE_UTSNAME_DOMAINNAME #cmakedefine01 HAVE_STAT64 #cmakedefine01 HAVE_FORK diff --git a/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c b/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c index 29555b7807843..620f2e81495bc 100644 --- a/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c +++ b/src/libraries/Native/Unix/System.Native/pal_interfaceaddresses.c @@ -11,7 +11,13 @@ #include #include #include +#if HAVE_IFADDRS || HAVE_GETIFADDRS #include +#endif +#if !HAVE_GETIFADDRS && TARGET_ANDROID +#include +#include +#endif #include #include #include @@ -55,7 +61,6 @@ #endif #endif -#if HAVE_GETIFADDRS // Convert mask to prefix length e.g. 255.255.255.0 -> 24 // mask parameter is pointer to buffer where address starts and length is // buffer length e.g. 4 for IPv4 and 16 for IPv6. @@ -95,6 +100,50 @@ static inline uint8_t mask2prefix(uint8_t* mask, int length) return len; } + +#if !HAVE_IFADDRS && TARGET_ANDROID +// This structure is exactly the same as struct ifaddrs defined in ifaddrs.h but since the header +// might not be available (e.g., in bionics used in Android before API 24) we need to mirror it here +// so that we can dynamically load the getifaddrs function and use it. +struct ifaddrs +{ + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + union + { + struct sockaddr *ifu_broadaddr; + struct sockaddr *ifu_dstaddr; + } ifa_ifu; + void *ifa_data; +}; +#endif + +#if !HAVE_GETIFADDRS && TARGET_ANDROID +// Try to load the getifaddrs and freeifaddrs functions manually. +// This workaround is necessary on Android prior to API 24 and it can be removed once +// we drop support for earlier Android versions. +static int (*getifaddrs)(struct ifaddrs**) = NULL; +static void (*freeifaddrs)(struct ifaddrs*) = NULL; + +static void try_loading_getifaddrs() +{ + void *libc = dlopen("libc.so", RTLD_NOW); + if (libc) + { + getifaddrs = (int (*)(struct ifaddrs**)) dlsym(libc, "getifaddrs"); + freeifaddrs = (void (*)(struct ifaddrs*)) dlsym(libc, "freeifaddrs"); + } +} + +static bool ensure_getifaddrs_is_loaded() +{ + static pthread_once_t getifaddrs_is_loaded = PTHREAD_ONCE_INIT; + pthread_once(&getifaddrs_is_loaded, try_loading_getifaddrs); + return getifaddrs != NULL && freeifaddrs != NULL; +} #endif int32_t SystemNative_EnumerateInterfaceAddresses(void* context, @@ -102,7 +151,16 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, IPv6AddressFound onIpv6Found, LinkLayerAddressFound onLinkLayerFound) { -#if HAVE_GETIFADDRS +#if !HAVE_GETIFADDRS && TARGET_ANDROID + // Workaround for Android API < 24 + if (!ensure_getifaddrs_is_loaded()) + { + errno = ENOTSUP; + return -1; + } +#endif + +#if HAVE_GETIFADDRS || TARGET_ANDROID struct ifaddrs* headAddr; if (getifaddrs(&headAddr) == -1) { @@ -235,7 +293,7 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, freeifaddrs(headAddr); return 0; #else - // Not supported on e.g. Android. Also, prevent a compiler error because parameters are unused + // Not supported. Also, prevent a compiler error because parameters are unused (void)context; (void)onIpv4Found; (void)onIpv6Found; @@ -247,7 +305,16 @@ int32_t SystemNative_EnumerateInterfaceAddresses(void* context, int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInterfaceInfo **interfaceList, int32_t * addressCount, IpAddressInfo **addressList ) { -#if HAVE_GETIFADDRS +#if !HAVE_GETIFADDRS && TARGET_ANDROID + // Workaround for Android API < 24 + if (!ensure_getifaddrs_is_loaded()) + { + errno = ENOTSUP; + return -1; + } +#endif + +#if HAVE_GETIFADDRS || TARGET_ANDROID struct ifaddrs* head; // Pointer to block allocated by getifaddrs(). struct ifaddrs* ifaddrsEntry; IpAddressInfo *ai; @@ -453,7 +520,7 @@ int32_t SystemNative_GetNetworkInterfaces(int32_t * interfaceCount, NetworkInter return 0; #else - // Not supported on e.g. Android. Also, prevent a compiler error because parameters are unused + // Not supported. Also, prevent a compiler error because parameters are unused (void)interfaceCount; (void)interfaceList; (void)addressCount; diff --git a/src/libraries/Native/Unix/configure.cmake b/src/libraries/Native/Unix/configure.cmake index e1afadb0e5249..e00b35d0f9e1f 100644 --- a/src/libraries/Native/Unix/configure.cmake +++ b/src/libraries/Native/Unix/configure.cmake @@ -7,6 +7,7 @@ include(CheckStructHasMember) include(CheckSymbolExists) include(CheckTypeSize) include(CheckLibraryExists) +include(CheckFunctionExists) # CMP0075 Include file check macros honor CMAKE_REQUIRED_LIBRARIES. if(POLICY CMP0075) @@ -141,6 +142,18 @@ check_c_source_compiles( " HAVE_FLOCK64) +check_c_source_compiles( + " + #include + #include + int main(void) + { + struct ifaddrs ia; + return 0; + } + " + HAVE_IFADDRS) + check_symbol_exists( O_CLOEXEC fcntl.h @@ -156,9 +169,8 @@ check_symbol_exists( fcntl.h HAVE_F_FULLFSYNC) -check_symbol_exists( +check_function_exists( getifaddrs - ifaddrs.h HAVE_GETIFADDRS) check_symbol_exists( diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs index 0f4903b01f848..6cf645411283d 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs @@ -26,6 +26,7 @@ public IPGlobalPropertiesTest(ITestOutputHelper output) } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void IPGlobalProperties_AccessAllMethods_NoErrors() { IPGlobalProperties gp = IPGlobalProperties.GetIPGlobalProperties(); @@ -51,6 +52,7 @@ public void IPGlobalProperties_AccessAllMethods_NoErrors() [Theory] [MemberData(nameof(Loopbacks))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void IPGlobalProperties_TcpListeners_Succeed(IPAddress address) { using (var server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) @@ -77,6 +79,7 @@ public void IPGlobalProperties_TcpListeners_Succeed(IPAddress address) [Theory] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [MemberData(nameof(Loopbacks))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public async Task IPGlobalProperties_TcpActiveConnections_Succeed(IPAddress address) { using (var server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) @@ -106,6 +109,7 @@ public async Task IPGlobalProperties_TcpActiveConnections_Succeed(IPAddress addr } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void IPGlobalProperties_TcpActiveConnections_NotListening() { TcpConnectionInformation[] tcpCconnections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections(); @@ -116,7 +120,6 @@ public void IPGlobalProperties_TcpActiveConnections_NotListening() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public async Task GetUnicastAddresses_NotEmpty() { IPGlobalProperties props = IPGlobalProperties.GetIPGlobalProperties(); diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs index 561cb687f3e75..c022f74b2c234 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceBasicTest.cs @@ -20,7 +20,6 @@ public NetworkInterfaceBasicTest(ITestOutputHelper output) } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void BasicTest_GetNetworkInterfaces_AtLeastOne() { Assert.NotEqual(0, NetworkInterface.GetAllNetworkInterfaces().Length); @@ -57,7 +56,7 @@ public void BasicTest_AccessInstanceProperties_NoExceptions() } [Fact] - [PlatformSpecific(TestPlatforms.Linux)] // Some APIs are not supported on Linux + [PlatformSpecific(TestPlatforms.Linux|TestPlatforms.Android)] // Some APIs are not supported on Linux and Android public void BasicTest_AccessInstanceProperties_NoExceptions_Linux() { foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) @@ -132,7 +131,6 @@ public void BasicTest_AccessInstanceProperties_NoExceptions_Bsd() [Fact] [Trait("IPv4", "true")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void BasicTest_StaticLoopbackIndex_MatchesLoopbackNetworkInterface() { Assert.True(Capability.IPv4Support()); @@ -156,7 +154,6 @@ public void BasicTest_StaticLoopbackIndex_MatchesLoopbackNetworkInterface() [Fact] [Trait("IPv4", "true")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void BasicTest_StaticLoopbackIndex_ExceptionIfV4NotSupported() { Assert.True(Capability.IPv4Support()); @@ -166,7 +163,6 @@ public void BasicTest_StaticLoopbackIndex_ExceptionIfV4NotSupported() [Fact] [Trait("IPv6", "true")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void BasicTest_StaticIPv6LoopbackIndex_MatchesLoopbackNetworkInterface() { Assert.True(Capability.IPv6Support()); @@ -191,7 +187,6 @@ public void BasicTest_StaticIPv6LoopbackIndex_MatchesLoopbackNetworkInterface() [Fact] [Trait("IPv6", "true")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void BasicTest_StaticIPv6LoopbackIndex_ExceptionIfV6NotSupported() { Assert.True(Capability.IPv6Support()); @@ -272,7 +267,6 @@ public void BasicTest_GetIPInterfaceStatistics_Success_Bsd() [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public void BasicTest_GetIsNetworkAvailable_Success() { Assert.True(NetworkInterface.GetIsNetworkAvailable()); @@ -284,7 +278,6 @@ public void BasicTest_GetIsNetworkAvailable_Success() [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.MacCatalyst | TestPlatforms.tvOS, "Not supported on Browser, iOS, MacCatalyst, or tvOS.")] [InlineData(false)] [InlineData(true)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public async Task NetworkInterface_LoopbackInterfaceIndex_MatchesReceivedPackets(bool ipv6) { using (var client = new Socket(SocketType.Dgram, ProtocolType.Udp)) diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index 160cc413535d9..cfcda85ec6033 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -88,7 +88,6 @@ - diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in index 6e6fc568b8b3b..439c82ad67b70 100644 --- a/src/mono/cmake/config.h.in +++ b/src/mono/cmake/config.h.in @@ -620,6 +620,9 @@ /* Have getifaddrs */ #cmakedefine HAVE_GETIFADDRS 1 +/* Have struct ifaddrs */ +#cmakedefine HAVE_IFADDRS 1 + /* Have access */ #cmakedefine HAVE_ACCESS 1 From 7c28896239fb2c4e3dfa7465e72d5f3aac9a8326 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Thu, 13 Jan 2022 16:57:12 +0100 Subject: [PATCH 2/3] [Android] Throw PNSE for unavailable network information (#63633) * Update tests * Add android specific implementation * Add UnsupportedOSPlatform attributes * Fix typo * Remove unnecessary file reference * Clean-up code * Minor code clean-up * Remove dictionary * Refactoring * Revert comment change --- .../ref/System.Net.NetworkInformation.cs | 43 ++++ .../src/System.Net.NetworkInformation.csproj | 17 +- .../AndroidIPGlobalProperties.cs | 32 +++ .../AndroidIPGlobalStatistics.cs | 73 ++++++ .../AndroidIPInterfaceProperties.cs | 30 +++ .../AndroidIPv4InterfaceProperties.cs | 24 ++ .../AndroidIPv6InterfaceProperties.cs | 31 +++ .../AndroidNetworkInterface.cs | 54 +++++ .../NetworkInformation/IPGlobalProperties.cs | 8 + .../IPGlobalPropertiesPal.Android.cs | 13 ++ .../NetworkInformation/IPGlobalStatistics.cs | 22 ++ .../IPInterfaceProperties.cs | 10 + .../IPv4InterfaceProperties.cs | 7 + .../NetworkInformation/NetworkInterface.cs | 2 + .../NetworkInterfacePal.Android.cs | 110 +++++++++ .../UnixIPGlobalProperties.cs | 2 + .../UnixNetworkInterface.cs | 2 +- .../FunctionalTests/IPGlobalPropertiesTest.cs | 70 +++++- .../IPInterfacePropertiesTest_Android.cs | 221 ++++++++++++++++++ .../NetworkInterfaceIPv4Statistics.cs | 11 + 20 files changed, 774 insertions(+), 8 deletions(-) create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalProperties.cs create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalStatistics.cs create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPInterfaceProperties.cs create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv4InterfaceProperties.cs create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv6InterfaceProperties.cs create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidNetworkInterface.cs create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalPropertiesPal.Android.cs create mode 100644 src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs create mode 100644 src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPInterfacePropertiesTest_Android.cs diff --git a/src/libraries/System.Net.NetworkInformation/ref/System.Net.NetworkInformation.cs b/src/libraries/System.Net.NetworkInformation/ref/System.Net.NetworkInformation.cs index b8d331ba9918c..66ab317a7d93d 100644 --- a/src/libraries/System.Net.NetworkInformation/ref/System.Net.NetworkInformation.cs +++ b/src/libraries/System.Net.NetworkInformation/ref/System.Net.NetworkInformation.cs @@ -123,9 +123,11 @@ public virtual void CopyTo(System.Net.NetworkInformation.IPAddressInformation[] public abstract partial class IPGlobalProperties { protected IPGlobalProperties() { } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract string DhcpScopeName { get; } public abstract string DomainName { get; } public abstract string HostName { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool IsWinsProxy { get; } public abstract System.Net.NetworkInformation.NetBiosNodeType NodeType { get; } public virtual System.IAsyncResult BeginGetUnicastAddresses(System.AsyncCallback? callback, object? state) { throw null; } @@ -136,16 +138,22 @@ protected IPGlobalProperties() { } public abstract System.Net.IPEndPoint[] GetActiveTcpListeners(); [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.IPEndPoint[] GetActiveUdpListeners(); + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.IcmpV4Statistics GetIcmpV4Statistics(); + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.IcmpV6Statistics GetIcmpV6Statistics(); [System.Runtime.Versioning.UnsupportedOSPlatform("illumos")] [System.Runtime.Versioning.UnsupportedOSPlatform("solaris")] public static System.Net.NetworkInformation.IPGlobalProperties GetIPGlobalProperties() { throw null; } public abstract System.Net.NetworkInformation.IPGlobalStatistics GetIPv4GlobalStatistics(); public abstract System.Net.NetworkInformation.IPGlobalStatistics GetIPv6GlobalStatistics(); + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.TcpStatistics GetTcpIPv4Statistics(); + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.TcpStatistics GetTcpIPv6Statistics(); + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.UdpStatistics GetUdpIPv4Statistics(); + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.UdpStatistics GetUdpIPv6Statistics(); public virtual System.Net.NetworkInformation.UnicastIPAddressInformationCollection GetUnicastAddresses() { throw null; } public virtual System.Threading.Tasks.Task GetUnicastAddressesAsync() { throw null; } @@ -153,41 +161,69 @@ protected IPGlobalProperties() { } public abstract partial class IPGlobalStatistics { protected IPGlobalStatistics() { } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract int DefaultTtl { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool ForwardingEnabled { get; } public abstract int NumberOfInterfaces { get; } public abstract int NumberOfIPAddresses { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract int NumberOfRoutes { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long OutputPacketRequests { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long OutputPacketRoutingDiscards { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long OutputPacketsDiscarded { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long OutputPacketsWithNoRoute { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long PacketFragmentFailures { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long PacketReassembliesRequired { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long PacketReassemblyFailures { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long PacketReassemblyTimeout { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long PacketsFragmented { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long PacketsReassembled { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long ReceivedPackets { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsDelivered { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsDiscarded { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsForwarded { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsWithAddressErrors { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsWithHeadersErrors { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsWithUnknownProtocol { get; } } public abstract partial class IPInterfaceProperties { protected IPInterfaceProperties() { } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.IPAddressInformationCollection AnycastAddresses { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.IPAddressCollection DhcpServerAddresses { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.IPAddressCollection DnsAddresses { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract string DnsSuffix { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.GatewayIPAddressInformationCollection GatewayAddresses { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool IsDnsEnabled { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool IsDynamicDnsEnabled { get; } public abstract System.Net.NetworkInformation.MulticastIPAddressInformationCollection MulticastAddresses { get; } public abstract System.Net.NetworkInformation.UnicastIPAddressInformationCollection UnicastAddresses { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract System.Net.NetworkInformation.IPAddressCollection WinsServersAddresses { get; } public abstract System.Net.NetworkInformation.IPv4InterfaceProperties GetIPv4Properties(); public abstract System.Net.NetworkInformation.IPv6InterfaceProperties GetIPv6Properties(); @@ -212,11 +248,16 @@ public abstract partial class IPv4InterfaceProperties { protected IPv4InterfaceProperties() { } public abstract int Index { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool IsAutomaticPrivateAddressingActive { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool IsAutomaticPrivateAddressingEnabled { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool IsDhcpEnabled { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool IsForwardingEnabled { get; } public abstract int Mtu { get; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public abstract bool UsesWins { get; } } public abstract partial class IPv4InterfaceStatistics @@ -316,7 +357,9 @@ protected NetworkInterface() { } [System.Runtime.Versioning.UnsupportedOSPlatform("solaris")] public static System.Net.NetworkInformation.NetworkInterface[] GetAllNetworkInterfaces() { throw null; } public virtual System.Net.NetworkInformation.IPInterfaceProperties GetIPProperties() { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public virtual System.Net.NetworkInformation.IPInterfaceStatistics GetIPStatistics() { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("android")] public virtual System.Net.NetworkInformation.IPv4InterfaceStatistics GetIPv4Statistics() { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatform("illumos")] [System.Runtime.Versioning.UnsupportedOSPlatform("solaris")] diff --git a/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj b/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj index dc251f9c75dc4..b1c5a10f45a64 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj +++ b/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj @@ -1,7 +1,7 @@ true - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-Solaris;$(NetCoreAppCurrent) + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-Android;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-Solaris;$(NetCoreAppCurrent) enable @@ -118,8 +118,8 @@ - - + + @@ -144,6 +144,17 @@ + + + + + + + + + + + diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalProperties.cs new file mode 100644 index 0000000000000..4cebb2c55efa9 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalProperties.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Net.NetworkInformation +{ + internal sealed class AndroidIPGlobalProperties : UnixIPGlobalProperties + { + public override TcpConnectionInformation[] GetActiveTcpConnections() => throw new PlatformNotSupportedException(); + + public override IPEndPoint[] GetActiveTcpListeners() => throw new PlatformNotSupportedException(); + + public override IPEndPoint[] GetActiveUdpListeners() => throw new PlatformNotSupportedException(); + + public override IcmpV4Statistics GetIcmpV4Statistics() => throw new PlatformNotSupportedException(); + + public override IcmpV6Statistics GetIcmpV6Statistics() => throw new PlatformNotSupportedException(); + + public override IPGlobalStatistics GetIPv4GlobalStatistics() + => new AndroidIPGlobalStatistics(ipv4: true); + + public override IPGlobalStatistics GetIPv6GlobalStatistics() + => new AndroidIPGlobalStatistics(ipv4: false); + + public override TcpStatistics GetTcpIPv4Statistics() => throw new PlatformNotSupportedException(); + + public override TcpStatistics GetTcpIPv6Statistics() => throw new PlatformNotSupportedException(); + + public override UdpStatistics GetUdpIPv4Statistics() => throw new PlatformNotSupportedException(); + + public override UdpStatistics GetUdpIPv6Statistics() => throw new PlatformNotSupportedException(); + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalStatistics.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalStatistics.cs new file mode 100644 index 0000000000000..de57e068a1ddb --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPGlobalStatistics.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; +using System.Net.Sockets; + +namespace System.Net.NetworkInformation +{ + internal sealed class AndroidIPGlobalStatistics : IPGlobalStatistics + { + public AndroidIPGlobalStatistics(bool ipv4) + { + AndroidNetworkInterface[] networkInterfaces = NetworkInterfacePal.GetAndroidNetworkInterfaces(); + + foreach (var networkInterface in networkInterfaces) + { + var component = ipv4 ? NetworkInterfaceComponent.IPv4 : NetworkInterfaceComponent.IPv6; + if (networkInterface.Supports(component)) + { + NumberOfInterfaces++; + } + + foreach (UnixUnicastIPAddressInformation addressInformation in networkInterface.UnicastAddress) + { + bool isIPv4 = addressInformation.Address.AddressFamily == AddressFamily.InterNetwork; + if (isIPv4 == ipv4) + { + NumberOfIPAddresses++; + } + } + + if (networkInterface.MulticastAddresess != null) + { + foreach (IPAddress address in networkInterface.MulticastAddresess) + { + bool isIPv4 = address.AddressFamily == AddressFamily.InterNetwork; + if (isIPv4 == ipv4) + { + NumberOfIPAddresses++; + } + } + } + } + } + + public override int NumberOfInterfaces { get; } + public override int NumberOfIPAddresses { get; } + + public override int DefaultTtl => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override bool ForwardingEnabled => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override int NumberOfRoutes => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long OutputPacketRequests => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long OutputPacketRoutingDiscards => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long OutputPacketsDiscarded => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long OutputPacketsWithNoRoute => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long PacketFragmentFailures => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long PacketReassembliesRequired => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long PacketReassemblyFailures => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long PacketReassemblyTimeout => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long PacketsFragmented => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long PacketsReassembled => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long ReceivedPackets => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long ReceivedPacketsDelivered => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long ReceivedPacketsDiscarded => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long ReceivedPacketsForwarded => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long ReceivedPacketsWithAddressErrors => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long ReceivedPacketsWithHeadersErrors => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override long ReceivedPacketsWithUnknownProtocol => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPInterfaceProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPInterfaceProperties.cs new file mode 100644 index 0000000000000..cee58c47d8447 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPInterfaceProperties.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.IO; + +namespace System.Net.NetworkInformation +{ + internal sealed class AndroidIPInterfaceProperties : UnixIPInterfaceProperties + { + private readonly AndroidIPv4InterfaceProperties _ipv4Properties; + private readonly AndroidIPv6InterfaceProperties _ipv6Properties; + + public AndroidIPInterfaceProperties(AndroidNetworkInterface ani) + : base(ani, globalConfig: true) + { + _ipv4Properties = new AndroidIPv4InterfaceProperties(ani); + _ipv6Properties = new AndroidIPv6InterfaceProperties(ani); + } + + public override IPv4InterfaceProperties GetIPv4Properties() => _ipv4Properties; + public override IPv6InterfaceProperties GetIPv6Properties() => _ipv6Properties; + + public override bool IsDynamicDnsEnabled => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override IPAddressInformationCollection AnycastAddresses => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override GatewayIPAddressInformationCollection GatewayAddresses => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override IPAddressCollection DhcpServerAddresses => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override IPAddressCollection WinsServersAddresses => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv4InterfaceProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv4InterfaceProperties.cs new file mode 100644 index 0000000000000..cc12cf7f35745 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv4InterfaceProperties.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; + +namespace System.Net.NetworkInformation +{ + internal sealed class AndroidIPv4InterfaceProperties : UnixIPv4InterfaceProperties + { + public AndroidIPv4InterfaceProperties(AndroidNetworkInterface androidNetworkInterface) + : base(androidNetworkInterface) + { + Mtu = androidNetworkInterface._mtu; + } + + public override int Mtu { get; } + + public override bool IsAutomaticPrivateAddressingActive => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override bool IsAutomaticPrivateAddressingEnabled => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override bool IsDhcpEnabled => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override bool IsForwardingEnabled => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override bool UsesWins => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv6InterfaceProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv6InterfaceProperties.cs new file mode 100644 index 0000000000000..9a5f872231efd --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidIPv6InterfaceProperties.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; + +namespace System.Net.NetworkInformation +{ + internal sealed class AndroidIPv6InterfaceProperties : UnixIPv6InterfaceProperties + { + private readonly AndroidNetworkInterface _androidNetworkInterface; + + public AndroidIPv6InterfaceProperties(AndroidNetworkInterface androidNetworkInterface) + : base(androidNetworkInterface) + { + _androidNetworkInterface = androidNetworkInterface; + } + + public override int Mtu => _androidNetworkInterface._mtu; + + public override long GetScopeId(ScopeLevel scopeLevel) + { + if (scopeLevel == ScopeLevel.None || scopeLevel == ScopeLevel.Interface || + scopeLevel == ScopeLevel.Link || scopeLevel == ScopeLevel.Subnet) + { + return _androidNetworkInterface.Index; + } + + return 0; + } + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidNetworkInterface.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidNetworkInterface.cs new file mode 100644 index 0000000000000..dcf66895aea7b --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/AndroidNetworkInterface.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Net; + +namespace System.Net.NetworkInformation +{ + /// + /// Implements a NetworkInterface on Android. + /// + internal sealed class AndroidNetworkInterface : UnixNetworkInterface + { + internal readonly int _mtu; + private readonly AndroidIPInterfaceProperties _ipProperties; + + internal unsafe AndroidNetworkInterface(string name, Interop.Sys.NetworkInterfaceInfo *networkInterfaceInfo) + : base(name) + { + _index = networkInterfaceInfo->InterfaceIndex; + if (networkInterfaceInfo->NumAddressBytes > 0) + { + _physicalAddress = new PhysicalAddress(new ReadOnlySpan(networkInterfaceInfo->AddressBytes, networkInterfaceInfo->NumAddressBytes).ToArray()); + } + + _mtu = networkInterfaceInfo->Mtu; + _ipProperties = new AndroidIPInterfaceProperties(this); + + OperationalStatus = (OperationalStatus)networkInterfaceInfo->OperationalState; + Speed = networkInterfaceInfo->Speed; + SupportsMulticast = networkInterfaceInfo->SupportsMulticast != 0; + NetworkInterfaceType = (NetworkInterfaceType)networkInterfaceInfo->HardwareType; + } + + internal unsafe void AddAddress(Interop.Sys.IpAddressInfo *addressInfo) + { + var address = new IPAddress(new ReadOnlySpan(addressInfo->AddressBytes, addressInfo->NumAddressBytes)); + if (address.IsIPv6LinkLocal) + { + address.ScopeId = addressInfo->InterfaceIndex; + } + + AddAddress(address, addressInfo->PrefixLength); + } + + public override bool SupportsMulticast { get; } + public override IPInterfaceProperties GetIPProperties() => _ipProperties; + public override IPInterfaceStatistics GetIPStatistics() => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override IPv4InterfaceStatistics GetIPv4Statistics() => throw new PlatformNotSupportedException(SR.net_InformationUnavailableOnPlatform); + public override OperationalStatus OperationalStatus { get; } + public override NetworkInterfaceType NetworkInterfaceType { get; } + public override long Speed { get; } + public override bool IsReceiveOnly => false; + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalProperties.cs index d835ce2ecd65b..1371a47d3ed94 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalProperties.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalProperties.cs @@ -40,6 +40,7 @@ public static IPGlobalProperties GetIPGlobalProperties() /// /// Gets the Dynamic Host Configuration Protocol (DHCP) scope name. /// + [UnsupportedOSPlatform("android")] public abstract string DhcpScopeName { get; } /// @@ -55,6 +56,7 @@ public static IPGlobalProperties GetIPGlobalProperties() /// /// Gets a bool value that specifies whether the local computer is acting as a Windows Internet Name Service (WINS) proxy. /// + [UnsupportedOSPlatform("android")] public abstract bool IsWinsProxy { get; } /// @@ -72,25 +74,31 @@ public virtual UnicastIPAddressInformationCollection EndGetUnicastAddresses(IAsy throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); } + [UnsupportedOSPlatform("android")] public abstract TcpStatistics GetTcpIPv4Statistics(); + [UnsupportedOSPlatform("android")] public abstract TcpStatistics GetTcpIPv6Statistics(); /// /// Provides User Datagram Protocol (UDP) statistical data for the local computer. /// + [UnsupportedOSPlatform("android")] public abstract UdpStatistics GetUdpIPv4Statistics(); + [UnsupportedOSPlatform("android")] public abstract UdpStatistics GetUdpIPv6Statistics(); /// /// Provides Internet Control Message Protocol (ICMP) version 4 statistical data for the local computer. /// + [UnsupportedOSPlatform("android")] public abstract IcmpV4Statistics GetIcmpV4Statistics(); /// /// Provides Internet Control Message Protocol (ICMP) version 6 statistical data for the local computer. /// + [UnsupportedOSPlatform("android")] public abstract IcmpV6Statistics GetIcmpV6Statistics(); /// diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalPropertiesPal.Android.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalPropertiesPal.Android.cs new file mode 100644 index 0000000000000..33e09ece17c69 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalPropertiesPal.Android.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Net.NetworkInformation +{ + internal static class IPGlobalPropertiesPal + { + public static IPGlobalProperties GetIPGlobalProperties() + { + return new AndroidIPGlobalProperties(); + } + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalStatistics.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalStatistics.cs index a8103f867e83d..04b9f14f1eab2 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalStatistics.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPGlobalStatistics.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.Versioning; + namespace System.Net.NetworkInformation { /// @@ -11,11 +13,13 @@ public abstract class IPGlobalStatistics /// /// Gets the default time-to-live (TTL) value for Internet Protocol (IP) packets. /// + [UnsupportedOSPlatform("android")] public abstract int DefaultTtl { get; } /// /// Gets a bool value that specifies whether Internet Protocol (IP) packet forwarding is enabled. /// + [UnsupportedOSPlatform("android")] public abstract bool ForwardingEnabled { get; } /// @@ -31,91 +35,109 @@ public abstract class IPGlobalStatistics /// /// Gets the number of outbound Internet Protocol (IP) packets. /// + [UnsupportedOSPlatform("android")] public abstract long OutputPacketRequests { get; } /// /// Gets the number of routes in the routing table that have been discarded. /// + [UnsupportedOSPlatform("android")] public abstract long OutputPacketRoutingDiscards { get; } /// /// Gets the number of transmitted Internet Protocol (IP) packets that have been discarded. /// + [UnsupportedOSPlatform("android")] public abstract long OutputPacketsDiscarded { get; } /// /// Gets the number of Internet Protocol (IP) packets for which the local computer could not determine a route to the destination address. /// + [UnsupportedOSPlatform("android")] public abstract long OutputPacketsWithNoRoute { get; } /// /// Gets the number of Internet Protocol (IP) packets that could not be fragmented. /// + [UnsupportedOSPlatform("android")] public abstract long PacketFragmentFailures { get; } /// /// Gets the number of Internet Protocol (IP) packets that required reassembly. /// + [UnsupportedOSPlatform("android")] public abstract long PacketReassembliesRequired { get; } /// /// Gets the number of Internet Protocol (IP) packets that were not successfully reassembled. /// + [UnsupportedOSPlatform("android")] public abstract long PacketReassemblyFailures { get; } /// /// Gets the maximum amount of time within which all fragments of an Internet Protocol (IP) packet must arrive. /// + [UnsupportedOSPlatform("android")] public abstract long PacketReassemblyTimeout { get; } /// /// Gets the number of Internet Protocol (IP) packets fragmented. /// + [UnsupportedOSPlatform("android")] public abstract long PacketsFragmented { get; } /// /// Gets the number of Internet Protocol (IP) packets reassembled. /// + [UnsupportedOSPlatform("android")] public abstract long PacketsReassembled { get; } /// /// Gets the number of Internet Protocol (IP) packets received. /// + [UnsupportedOSPlatform("android")] public abstract long ReceivedPackets { get; } /// /// Gets the number of Internet Protocol(IP) packets received and delivered. /// + [UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsDelivered { get; } /// /// Gets the number of Internet Protocol (IP) packets that have been received and discarded. /// + [UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsDiscarded { get; } /// /// Gets the number of Internet Protocol (IP) packets forwarded. /// + [UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsForwarded { get; } /// /// Gets the number of Internet Protocol (IP) packets with address errors that were received. /// + [UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsWithAddressErrors { get; } /// /// Gets the number of Internet Protocol (IP) packets with header errors that were received. /// + [UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsWithHeadersErrors { get; } /// /// Gets the number of Internet Protocol (IP) packets received on the local machine with an unknown protocol in the header. /// + [UnsupportedOSPlatform("android")] public abstract long ReceivedPacketsWithUnknownProtocol { get; } /// /// Gets the number of routes in the Internet Protocol (IP) routing table. /// + [UnsupportedOSPlatform("android")] public abstract int NumberOfRoutes { get; } } } diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPInterfaceProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPInterfaceProperties.cs index e659598f5e4f4..863737ce18f6d 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPInterfaceProperties.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPInterfaceProperties.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.Versioning; + namespace System.Net.NetworkInformation { /// @@ -12,16 +14,19 @@ public abstract class IPInterfaceProperties /// /// Gets a bool value that indicates whether this interface is configured to send name resolution queries to a Domain Name System (DNS) server. /// + [UnsupportedOSPlatform("android")] public abstract bool IsDnsEnabled { get; } /// /// Gets the Domain Name System (DNS) suffix associated with this interface. /// + [UnsupportedOSPlatform("android")] public abstract string DnsSuffix { get; } /// /// Gets a bool value that indicates whether this interface is configured to automatically register its IP address information with the Domain Name System (DNS). /// + [UnsupportedOSPlatform("android")] public abstract bool IsDynamicDnsEnabled { get; } /// @@ -37,26 +42,31 @@ public abstract class IPInterfaceProperties /// /// The address identifies multiple computers. Packets sent to an anycast address are sent to one of the computers identified by the address. /// + [UnsupportedOSPlatform("android")] public abstract IPAddressInformationCollection AnycastAddresses { get; } /// /// The address is that of a Domain Name Service (DNS) server for the local computer. /// + [UnsupportedOSPlatform("android")] public abstract IPAddressCollection DnsAddresses { get; } /// /// Gets the network gateway addresses. /// + [UnsupportedOSPlatform("android")] public abstract GatewayIPAddressInformationCollection GatewayAddresses { get; } /// /// Gets the addresses for Dynamic Host Configuration Protocol (DHCP) servers. /// + [UnsupportedOSPlatform("android")] public abstract IPAddressCollection DhcpServerAddresses { get; } /// /// Gets the list of Wins Servers registered with this interface /// + [UnsupportedOSPlatform("android")] public abstract IPAddressCollection WinsServersAddresses { get; } /// diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPv4InterfaceProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPv4InterfaceProperties.cs index 0f104e3fce8fc..9f9d0b1e3766d 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPv4InterfaceProperties.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/IPv4InterfaceProperties.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Runtime.Versioning; + namespace System.Net.NetworkInformation { /// @@ -11,21 +13,25 @@ public abstract class IPv4InterfaceProperties /// /// Gets a bool value that indicates whether an interface uses Windows Internet Name Service (WINS). /// + [UnsupportedOSPlatform("android")] public abstract bool UsesWins { get; } /// /// Gets a bool value that indicates whether the interface is configured to use a dynamic host configuration protocol (DHCP) server to obtain an IP address. /// + [UnsupportedOSPlatform("android")] public abstract bool IsDhcpEnabled { get; } /// /// Gets a bool value that indicates whether this interface has an automatic private IP addressing (APIPA) address. /// + [UnsupportedOSPlatform("android")] public abstract bool IsAutomaticPrivateAddressingActive { get; } /// /// Gets a bool value that indicates whether this interface has automatic private IP addressing (APIPA) enabled. /// + [UnsupportedOSPlatform("android")] public abstract bool IsAutomaticPrivateAddressingEnabled { get; } /// @@ -36,6 +42,7 @@ public abstract class IPv4InterfaceProperties /// /// Gets a bool value that indicates whether this interface can route packets. /// + [UnsupportedOSPlatform("android")] public abstract bool IsForwardingEnabled { get; } /// diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterface.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterface.cs index 94cb8fb0b9d81..24f02186c3dc3 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterface.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterface.cs @@ -70,6 +70,7 @@ public virtual IPInterfaceProperties GetIPProperties() /// Provides Internet Protocol (IP) statistical data for this network interface. /// /// The interface's IP statistics. + [UnsupportedOSPlatform("android")] public virtual IPInterfaceStatistics GetIPStatistics() { throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); @@ -81,6 +82,7 @@ public virtual IPInterfaceStatistics GetIPStatistics() /// Do not use this method, use GetIPStatistics instead. /// /// The interface's IP statistics. + [UnsupportedOSPlatform("android")] public virtual IPv4InterfaceStatistics GetIPv4Statistics() { throw NotImplemented.ByDesignWithMessage(SR.net_MethodNotImplementedException); diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs new file mode 100644 index 0000000000000..3b68b90e5a5fc --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs @@ -0,0 +1,110 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +namespace System.Net.NetworkInformation +{ + internal static class NetworkInterfacePal + { + /// Returns objects that describe the network interfaces on the local computer. + public static NetworkInterface[] GetAllNetworkInterfaces() => GetAndroidNetworkInterfaces(); + public static bool GetIsNetworkAvailable() => TransformNetworkInterfacess(IsSomeNetworkUp); + public static int IPv6LoopbackInterfaceIndex => LoopbackInterfaceIndex; + public static int LoopbackInterfaceIndex => TransformNetworkInterfacess(FindLoopbackInterfaceIndex); + + internal static unsafe AndroidNetworkInterface[] GetAndroidNetworkInterfaces() + => TransformNetworkInterfacess(ToAndroidNetworkInterfaceArray); + + private static unsafe T TransformNetworkInterfacess(Func transform) + { + int interfaceCount = 0; + int addressCount = 0; + Interop.Sys.NetworkInterfaceInfo *networkInterfaceInfo = null; + Interop.Sys.IpAddressInfo *addressInfo = null; + + if (Interop.Sys.GetNetworkInterfaces(&interfaceCount, &networkInterfaceInfo, &addressCount, &addressInfo) != 0) + { + string message = Interop.Sys.GetLastErrorInfo().GetErrorMessage(); + throw new NetworkInformationException(message); + } + + // the native implementation of Interop.Sys.GetNetworkInterfaces allocates one block of memory + // for both networkInterfaceInfo and addressInfo so we only need to call free once pointing at + // the start of the network itnerfaces list + var globalMemory = (IntPtr)networkInterfaceInfo; + + try + { + return transform(interfaceCount, (IntPtr)networkInterfaceInfo, addressCount, (IntPtr)addressInfo); + } + finally + { + Marshal.FreeHGlobal(globalMemory); + } + } + + private static unsafe AndroidNetworkInterface[] ToAndroidNetworkInterfaceArray(int interfaceCount, IntPtr networkInterfacesPtr, int addressCount, IntPtr addressPtr) + { + var networkInterfaces = new AndroidNetworkInterface[interfaceCount]; + + var networkInterfaceInfo = (Interop.Sys.NetworkInterfaceInfo*)networkInterfacesPtr; + for (int i = 0; i < interfaceCount; i++, networkInterfaceInfo++) + { + var name = Marshal.PtrToStringAnsi((IntPtr)networkInterfaceInfo->Name); + networkInterfaces[i] = new AndroidNetworkInterface(name!, networkInterfaceInfo); + } + + var addressInfo = (Interop.Sys.IpAddressInfo*)addressPtr; + for (int i = 0; i < addressCount; i++, addressInfo++) + { + // there is usually just a handful of few network interfaces on Android devices + // and this linear search does not have any impact on performance + foreach (var networkInterface in networkInterfaces) + { + if (networkInterface.Index == addressInfo->InterfaceIndex) + { + networkInterface.AddAddress(addressInfo); + break; + } + } + } + + return networkInterfaces; + } + + private static unsafe int FindLoopbackInterfaceIndex(int interfaceCount, IntPtr networkInterfacesPtr, int addressCount, IntPtr addressPtr) + { + var networkInterfaceInfo = (Interop.Sys.NetworkInterfaceInfo*)networkInterfacesPtr; + for (int i = 0; i < interfaceCount; i++, networkInterfaceInfo++) + { + if (networkInterfaceInfo->HardwareType == (int)NetworkInterfaceType.Loopback) + { + return networkInterfaceInfo->InterfaceIndex; + } + } + + throw new NetworkInformationException(SR.net_NoLoopback); + } + + private static unsafe bool IsSomeNetworkUp(int interfaceCount, IntPtr networkInterfacesPtr, int addressCount, IntPtr addressPtr) + { + var networkInterfaceInfo = (Interop.Sys.NetworkInterfaceInfo*)networkInterfacesPtr; + for (int i = 0; i < interfaceCount; i++, networkInterfaceInfo++) + { + if (networkInterfaceInfo->HardwareType == (int)NetworkInterfaceType.Loopback + || networkInterfaceInfo->HardwareType == (int)NetworkInterfaceType.Tunnel) + { + continue; + } + + if (networkInterfaceInfo->OperationalState == (int)OperationalStatus.Up) + { + return true; + } + } + + return false; + } + } +} diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs index cca949a317a6f..eafa42ff3fec1 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs @@ -13,6 +13,7 @@ namespace System.Net.NetworkInformation internal abstract class UnixIPGlobalProperties : IPGlobalProperties { [UnsupportedOSPlatform("linux")] + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("osx")] [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] @@ -26,6 +27,7 @@ internal abstract class UnixIPGlobalProperties : IPGlobalProperties public override string HostName { get { return HostInformation.HostName; } } [UnsupportedOSPlatform("linux")] + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("osx")] [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixNetworkInterface.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixNetworkInterface.cs index d248c72b6930c..00c5b3a9a3028 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixNetworkInterface.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixNetworkInterface.cs @@ -60,7 +60,7 @@ public override bool Supports(NetworkInterfaceComponent networkInterfaceComponen public List UnicastAddress { get { return _unicastAddresses; } } /// - /// Returns a list of all Unicast addresses of the interface's IP Addresses. + /// Returns a list of all Multicast addresses of the interface's IP Addresses. /// public List? MulticastAddresess { get { return _multicastAddresses; } } diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs index 6cf645411283d..70804e19499e2 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPGlobalPropertiesTest.cs @@ -26,7 +26,7 @@ public IPGlobalPropertiesTest(ITestOutputHelper output) } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] + [SkipOnPlatform(TestPlatforms.Android, "Expected behavior is different on Android")] public void IPGlobalProperties_AccessAllMethods_NoErrors() { IPGlobalProperties gp = IPGlobalProperties.GetIPGlobalProperties(); @@ -50,9 +50,71 @@ public void IPGlobalProperties_AccessAllMethods_NoErrors() Assert.NotNull(gp.GetUdpIPv6Statistics()); } + [Fact] + [PlatformSpecific(TestPlatforms.Android)] + public void IPGlobalProperties_AccessAllMethods_NoErrors_Android() + { + IPGlobalProperties gp = IPGlobalProperties.GetIPGlobalProperties(); + + Assert.NotNull(gp.GetIPv4GlobalStatistics()); + Assert.NotNull(gp.GetIPv6GlobalStatistics()); + + Assert.Throws(() => gp.GetActiveTcpConnections()); + Assert.Throws(() => gp.GetActiveTcpListeners()); + Assert.Throws(() => gp.GetActiveUdpListeners()); + Assert.Throws(() => gp.GetIcmpV4Statistics()); + Assert.Throws(() => gp.GetIcmpV6Statistics()); + Assert.Throws(() => gp.GetTcpIPv4Statistics()); + Assert.Throws(() => gp.GetTcpIPv6Statistics()); + Assert.Throws(() => gp.GetUdpIPv4Statistics()); + Assert.Throws(() => gp.GetUdpIPv6Statistics()); + } + + [Theory] + [InlineData(4)] + [InlineData(6)] + [PlatformSpecific(TestPlatforms.Android)] + public void IPGlobalProperties_IPv4_IPv6_NoErrors_Android(int ipVersion) + { + IPGlobalProperties gp = IPGlobalProperties.GetIPGlobalProperties(); + IPGlobalStatistics statistics = ipVersion switch { + 4 => gp.GetIPv4GlobalStatistics(), + 6 => gp.GetIPv6GlobalStatistics(), + _ => throw new ArgumentOutOfRangeException() + }; + + _log.WriteLine($"- IPv{ipVersion} statistics: -"); + _log.WriteLine($"Number of interfaces: {statistics.NumberOfInterfaces}"); + _log.WriteLine($"Number of IP addresses: {statistics.NumberOfIPAddresses}"); + + Assert.InRange(statistics.NumberOfInterfaces, 1, int.MaxValue); + Assert.InRange(statistics.NumberOfIPAddresses, 1, int.MaxValue); + + Assert.Throws(() => statistics.DefaultTtl); + Assert.Throws(() => statistics.ForwardingEnabled); + Assert.Throws(() => statistics.OutputPacketRequests); + Assert.Throws(() => statistics.OutputPacketRoutingDiscards); + Assert.Throws(() => statistics.OutputPacketsDiscarded); + Assert.Throws(() => statistics.OutputPacketsWithNoRoute); + Assert.Throws(() => statistics.PacketFragmentFailures); + Assert.Throws(() => statistics.PacketReassembliesRequired); + Assert.Throws(() => statistics.PacketReassemblyFailures); + Assert.Throws(() => statistics.PacketReassemblyTimeout); + Assert.Throws(() => statistics.PacketsFragmented); + Assert.Throws(() => statistics.PacketsReassembled); + Assert.Throws(() => statistics.ReceivedPackets); + Assert.Throws(() => statistics.ReceivedPacketsDelivered); + Assert.Throws(() => statistics.ReceivedPacketsDiscarded); + Assert.Throws(() => statistics.ReceivedPacketsForwarded); + Assert.Throws(() => statistics.ReceivedPacketsWithAddressErrors); + Assert.Throws(() => statistics.ReceivedPacketsWithHeadersErrors); + Assert.Throws(() => statistics.ReceivedPacketsWithUnknownProtocol); + Assert.Throws(() => statistics.NumberOfRoutes); + } + [Theory] [MemberData(nameof(Loopbacks))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] + [SkipOnPlatform(TestPlatforms.Android, "Unsupported on Android")] public void IPGlobalProperties_TcpListeners_Succeed(IPAddress address) { using (var server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) @@ -78,8 +140,8 @@ public void IPGlobalProperties_TcpListeners_Succeed(IPAddress address) [Theory] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] + [PlatformSpecific(~(TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.Android))] [MemberData(nameof(Loopbacks))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] public async Task IPGlobalProperties_TcpActiveConnections_Succeed(IPAddress address) { using (var server = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) @@ -109,7 +171,7 @@ public async Task IPGlobalProperties_TcpActiveConnections_Succeed(IPAddress addr } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/50567", TestPlatforms.Android)] + [SkipOnPlatform(TestPlatforms.Android, "Unsupported on Android")] public void IPGlobalProperties_TcpActiveConnections_NotListening() { TcpConnectionInformation[] tcpCconnections = IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections(); diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPInterfacePropertiesTest_Android.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPInterfacePropertiesTest_Android.cs new file mode 100644 index 0000000000000..61e57c854aa47 --- /dev/null +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/IPInterfacePropertiesTest_Android.cs @@ -0,0 +1,221 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Linq; +using System.Net.Http.Functional.Tests; +using System.Net.Sockets; +using System.Net.Test.Common; +using System.Threading.Tasks; + +using Xunit; +using Xunit.Abstractions; + +namespace System.Net.NetworkInformation.Tests +{ + [PlatformSpecific(TestPlatforms.Android)] + public class IPInterfacePropertiesTest_Android + { + private readonly ITestOutputHelper _log; + + public IPInterfacePropertiesTest_Android(ITestOutputHelper output) + { + _log = output; + } + + [Fact] + public async Task IPInfoTest_AccessAllProperties_NoErrors() + { + await Task.Run(() => + { + foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) + { + _log.WriteLine("Nic: " + nic.Name); + _log.WriteLine("- Speed:" + nic.Speed); + Assert.Equal(-1, nic.Speed); + _log.WriteLine("- Supports IPv4: " + nic.Supports(NetworkInterfaceComponent.IPv4)); + _log.WriteLine("- Supports IPv6: " + nic.Supports(NetworkInterfaceComponent.IPv6)); + Assert.False(nic.IsReceiveOnly); + + IPInterfaceProperties ipProperties = nic.GetIPProperties(); + + Assert.NotNull(ipProperties); + + Assert.Throws(() => ipProperties.AnycastAddresses); + Assert.Throws(() => ipProperties.DhcpServerAddresses); + Assert.Throws(() => ipProperties.DnsAddresses); + Assert.Throws(() => ipProperties.DnsSuffix); + Assert.Throws(() => ipProperties.GatewayAddresses); + Assert.Throws(() => ipProperties.IsDnsEnabled); + Assert.Throws(() => ipProperties.IsDynamicDnsEnabled); + + Assert.NotNull(ipProperties.MulticastAddresses); + _log.WriteLine("- Multicast Addresses: " + ipProperties.MulticastAddresses.Count); + foreach (IPAddressInformation multi in ipProperties.MulticastAddresses) + { + _log.WriteLine("-- " + multi.Address.ToString()); + Assert.Throws(() => multi.IsDnsEligible); + Assert.Throws(() => multi.IsTransient); + } + + Assert.NotNull(ipProperties.UnicastAddresses); + _log.WriteLine("- Unicast Addresses: " + ipProperties.UnicastAddresses.Count); + foreach (UnicastIPAddressInformation uni in ipProperties.UnicastAddresses) + { + _log.WriteLine("-- " + uni.Address.ToString()); + Assert.Throws(() => uni.AddressPreferredLifetime); + Assert.Throws(() => uni.AddressValidLifetime); + Assert.Throws(() => uni.DhcpLeaseLifetime); + Assert.Throws(() => uni.DuplicateAddressDetectionState); + + Assert.NotNull(uni.IPv4Mask); + _log.WriteLine("--- IPv4 Mask: " + uni.IPv4Mask); + Assert.Throws(() => uni.IsDnsEligible); + Assert.Throws(() => uni.IsTransient); + Assert.Throws(() => uni.PrefixOrigin); + Assert.Throws(() => uni.SuffixOrigin); + + // Prefix Length + _log.WriteLine("--- PrefixLength: " + uni.PrefixLength); + Assert.True(uni.PrefixLength > 0); + Assert.True((uni.Address.AddressFamily == AddressFamily.InterNetwork ? 33 : 129) > uni.PrefixLength); + } + + Assert.Throws(() => ipProperties.WinsServersAddresses); + } + }).WaitAsync(TestHelper.PassingTestTimeout); + } + + [Fact] + public async Task IPInfoTest_AccessAllIPv4Properties_NoErrors() + { + await Task.Run(() => + { + foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) + { + _log.WriteLine("Nic: " + nic.Name); + + IPInterfaceProperties ipProperties = nic.GetIPProperties(); + + _log.WriteLine("IPv4 Properties:"); + + IPv4InterfaceProperties ipv4Properties = ipProperties.GetIPv4Properties(); + + _log.WriteLine("Index: " + ipv4Properties.Index); + Assert.Throws(() => ipv4Properties.IsAutomaticPrivateAddressingActive); + Assert.Throws(() => ipv4Properties.IsAutomaticPrivateAddressingEnabled); + Assert.Throws(() => ipv4Properties.IsDhcpEnabled); + Assert.Throws(() => ipv4Properties.IsForwardingEnabled); + _log.WriteLine("Mtu: " + ipv4Properties.Mtu); + Assert.Throws(() => ipv4Properties.UsesWins); + } + }).WaitAsync(TestHelper.PassingTestTimeout); + } + + [Fact] + public async Task IPInfoTest_AccessAllIPv6Properties_NoErrors() + { + await Task.Run(() => + { + foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) + { + _log.WriteLine("Nic: " + nic.Name); + + IPInterfaceProperties ipProperties = nic.GetIPProperties(); + + _log.WriteLine("IPv6 Properties:"); + + IPv6InterfaceProperties ipv6Properties = ipProperties.GetIPv6Properties(); + + if (ipv6Properties == null) + { + _log.WriteLine("IPv6Properties is null"); + continue; + } + + _log.WriteLine("Index: " + ipv6Properties.Index); + _log.WriteLine("Mtu: " + ipv6Properties.Mtu); + _log.WriteLine("Scope: " + ipv6Properties.GetScopeId(ScopeLevel.Link)); + } + }).WaitAsync(TestHelper.PassingTestTimeout); + } + + [Fact] + [Trait("IPv6", "true")] + public async Task IPv6ScopeId_AccessAllValues_Success() + { + await Task.Run(() => + { + Assert.True(Capability.IPv6Support()); + + foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) + { + _log.WriteLine("Nic: " + nic.Name); + + if (!nic.Supports(NetworkInterfaceComponent.IPv6)) + { + continue; + } + + IPInterfaceProperties ipProperties = nic.GetIPProperties(); + + IPv6InterfaceProperties ipv6Properties = ipProperties.GetIPv6Properties(); + + Array values = Enum.GetValues(typeof(ScopeLevel)); + foreach (ScopeLevel level in values) + { + _log.WriteLine("-- Level: " + level + "; " + ipv6Properties.GetScopeId(level)); + } + } + }).WaitAsync(TestHelper.PassingTestTimeout); + } + + [Fact] + [Trait("IPv4", "true")] + public async Task IPInfoTest_IPv4Loopback_ProperAddress() + { + await Task.Run(() => + { + Assert.True(Capability.IPv4Support()); + + _log.WriteLine("Loopback IPv4 index: " + NetworkInterface.LoopbackInterfaceIndex); + + NetworkInterface loopback = NetworkInterface.GetAllNetworkInterfaces().First(ni => ni.Name == "lo"); + Assert.NotNull(loopback); + + foreach (UnicastIPAddressInformation unicast in loopback.GetIPProperties().UnicastAddresses) + { + if (unicast.Address.Equals(IPAddress.Loopback)) + { + Assert.Equal(IPAddress.Parse("255.0.0.0"), unicast.IPv4Mask); + Assert.Equal(8, unicast.PrefixLength); + break; + } + } + }).WaitAsync(TestHelper.PassingTestTimeout); + } + + [Fact] + [Trait("IPv6", "true")] + public async Task IPInfoTest_IPv6Loopback_ProperAddress() + { + await Task.Run(() => + { + Assert.True(Capability.IPv6Support()); + + _log.WriteLine("Loopback IPv6 index: " + NetworkInterface.IPv6LoopbackInterfaceIndex); + + NetworkInterface loopback = NetworkInterface.GetAllNetworkInterfaces().First(ni => ni.Name == "lo"); + Assert.NotNull(loopback); + + foreach (UnicastIPAddressInformation unicast in loopback.GetIPProperties().UnicastAddresses) + { + if (unicast.Address.Equals(IPAddress.IPv6Loopback)) + { + Assert.Equal(128, unicast.PrefixLength); + break; + } + } + }).WaitAsync(TestHelper.PassingTestTimeout); + } + } +} diff --git a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceIPv4Statistics.cs b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceIPv4Statistics.cs index 52aceb0d3f9c1..9b73374e99b26 100644 --- a/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceIPv4Statistics.cs +++ b/src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkInterfaceIPv4Statistics.cs @@ -69,6 +69,17 @@ public void BasicTest_GetIPv4InterfaceStatistics_Success_Linux() } } + [Fact] + [PlatformSpecific(TestPlatforms.Android)] // This API is not supported on Android + public void BasicTest_GetIPv4InterfaceStatistics_NotSupported_Android() + { + // This API is not actually IPv4 specific. + foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces()) + { + Assert.Throws(() => nic.GetIPv4Statistics()); + } + } + [Fact] [PlatformSpecific(TestPlatforms.OSX)] // Some APIs are not supported on OSX public void BasicTest_GetIPv4InterfaceStatistics_Success_OSX() From 514280bac4518af77e767c6795ac5790954c183d Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 14 Jan 2022 11:07:40 +0100 Subject: [PATCH 3/3] Fix usage of Interop.Sys.GetNetworkInterfaces --- .../Net/NetworkInformation/NetworkInterfacePal.Android.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs index 3b68b90e5a5fc..820e01f093b34 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkInterfacePal.Android.cs @@ -23,7 +23,7 @@ private static unsafe T TransformNetworkInterfacess(Func(Func