Enable NetworkAddressChange on FreeBSD (#1602)
authorAdeel Mujahid <adeelbm@outlook.com>
Wed, 22 Jan 2020 21:26:37 +0000 (23:26 +0200)
committerStephen Toub <stoub@microsoft.com>
Wed, 22 Jan 2020 21:26:37 +0000 (16:26 -0500)
src/libraries/Common/src/Interop/Unix/System.Native/Interop.NetworkChange.cs [moved from src/libraries/Common/src/Interop/Linux/System.Native/Interop.NetworkChange.cs with 100% similarity]
src/libraries/Native/Unix/System.Native/CMakeLists.txt
src/libraries/Native/Unix/System.Native/pal_networkchange.c
src/libraries/Native/Unix/System.Native/pal_networkchange.h
src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj
src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Unix.cs [moved from src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.Linux.cs with 100% similarity]
src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkAddressChangedTests.cs
src/libraries/System.Net.NetworkInformation/tests/FunctionalTests/NetworkAvailabilityChangedTests.cs

index 73e8ccd..7421436 100644 (file)
@@ -29,6 +29,12 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
     if (!HAVE_LINUX_RTNETLINK_H)
         message(FATAL_ERROR "Could not find linux/rtnetlink.h")
     endif ()
+elseif (CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+    set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_networkchange.c)
+
+    if (!HAVE_RT_MSGHDR)
+        message(FATAL_ERROR "Could not find net/route.h")
+    endif ()
 endif ()
 
 if (GEN_SHARED_LIB)
index dc1378c..7dd6d79 100644 (file)
 #include "pal_utilities.h"
 
 #include <errno.h>
-#include <linux/rtnetlink.h>
 #include <net/if.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/uio.h>
 #include <unistd.h>
+#if HAVE_LINUX_RTNETLINK_H
+#include <linux/rtnetlink.h>
+#elif HAVE_RT_MSGHDR
+#include <net/route.h>
+#else
+#error System must have linux/rtnetlink.h or net/route.h.
+#endif
 
 #pragma clang diagnostic ignored "-Wcast-align" // NLMSG_* macros trigger this
 
 Error SystemNative_CreateNetworkChangeListenerSocket(int32_t* retSocket)
 {
+#if HAVE_LINUX_RTNETLINK_H
     struct sockaddr_nl sa;
     memset(&sa, 0, sizeof(struct sockaddr_nl));
 
     sa.nl_family = AF_NETLINK;
     sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_ROUTE;
     int32_t sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+#elif HAVE_RT_MSGHDR
+    int32_t sock = socket(PF_ROUTE, SOCK_RAW, 0);
+#endif
     if (sock == -1)
     {
         *retSocket = -1;
         return (Error)(SystemNative_ConvertErrorPlatformToPal(errno));
     }
+
+#if HAVE_LINUX_RTNETLINK_H
     if (bind(sock, (struct sockaddr*)(&sa), sizeof(sa)) != 0)
     {
         *retSocket = -1;
@@ -39,6 +51,7 @@ Error SystemNative_CreateNetworkChangeListenerSocket(int32_t* retSocket)
         close(sock);
         return palError;
     }
+#endif
 
     *retSocket = sock;
     return Error_SUCCESS;
@@ -50,6 +63,7 @@ Error SystemNative_CloseNetworkChangeListenerSocket(int32_t socket)
     return err == 0 || CheckInterrupted(err) ? Error_SUCCESS : (Error)(SystemNative_ConvertErrorPlatformToPal(errno));
 }
 
+#if HAVE_LINUX_RTNETLINK_H
 static NetworkChangeKind ReadNewLinkMessage(struct nlmsghdr* hdr)
 {
     assert(hdr != NULL);
@@ -117,3 +131,44 @@ void SystemNative_ReadEvents(int32_t sock, NetworkChangeEvent onNetworkChange)
         }
     }
 }
+#elif HAVE_RT_MSGHDR
+void SystemNative_ReadEvents(int32_t sock, NetworkChangeEvent onNetworkChange)
+{
+    char buffer[4096];
+    ssize_t count = read(sock, buffer, sizeof(buffer));
+    if (count < 0)
+    {
+        return;
+    }
+
+    struct rt_msghdr msghdr;
+    for (char *ptr = buffer; (ptr + sizeof(struct rt_msghdr)) <= (buffer + count); ptr += msghdr.rtm_msglen)
+    {
+        memcpy(&msghdr, ptr, sizeof(msghdr));
+        if (msghdr.rtm_version != RTM_VERSION)
+        {
+            // version mismatch
+            return;
+        }
+
+        switch (msghdr.rtm_type)
+        {
+            case RTM_NEWADDR:
+                onNetworkChange(sock, AddressAdded);
+                break;
+            case RTM_DELADDR:
+                onNetworkChange(sock, AddressRemoved);
+                break;
+            case RTM_ADD:
+            case RTM_DELETE:
+            case RTM_REDIRECT:
+            {
+                onNetworkChange(sock, AvailabilityChanged);
+                return;
+            }
+            default:
+                break;
+        }
+    }
+}
+#endif
index cb61b39..2357582 100644 (file)
     <Compile Include="System\Net\NetworkInformation\LinuxIcmpV6Statistics.cs" />
     <Compile Include="System\Net\NetworkInformation\LinuxTcpStatistics.cs" />
     <Compile Include="System\Net\NetworkInformation\LinuxUdpStatistics.cs" />
-    <Compile Include="System\Net\NetworkInformation\NetworkAddressChange.Linux.cs" />
     <Compile Include="System\Net\NetworkInformation\IPGlobalPropertiesPal.Linux.cs" />
     <Compile Include="System\Net\NetworkInformation\LinuxIPAddressInformation.cs" />
     <Compile Include="System\Net\NetworkInformation\LinuxIPGlobalProperties.cs" />
     <Compile Include="$(CommonPath)Interop\Linux\Interop.LinuxNetDeviceFlags.cs">
       <Link>Common\Interop\Linux\Interop.LinuxNetDeviceFlags.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)Interop\Linux\System.Native\Interop.NetworkChange.cs">
-      <Link>Common\Interop\Linux\System.Native\Interop.NetworkChange.cs</Link>
-    </Compile>
   </ItemGroup>
   <!-- OSX -->
   <ItemGroup Condition=" '$(TargetsOsx)' == 'true' or '$(TargetsFreeBSD)' == 'true'">
     </Compile>
   </ItemGroup>
   <ItemGroup Condition=" '$(TargetsFreeBSD)' == 'true'">
-    <Compile Include="System\Net\NetworkInformation\NetworkAddressChange.UnknownUnix.cs" />
     <Compile Include="$(CommonPath)Interop\FreeBSD\Interop.Libraries.cs">
       <Link>Common\Interop\FreeBSD\Interop.Libraries.cs</Link>
     </Compile>
   </ItemGroup>
+  <ItemGroup Condition=" '$(TargetsLinux)' == 'true' OR '$(TargetsFreeBSD)' == 'true'">
+    <Compile Include="System\Net\NetworkInformation\NetworkAddressChange.Unix.cs" />
+    <Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.NetworkChange.cs">
+      <Link>Common\Interop\Unix\System.Native\Interop.NetworkChange.cs</Link>
+    </Compile>
+  </ItemGroup>
   <!-- Unknown Unix -->
   <ItemGroup Condition=" '$(TargetsUnknownUnix)' == 'true' ">
     <Compile Include="System\Net\NetworkInformation\IPGlobalPropertiesPal.UnknownUnix.cs" />
     <Reference Include="System.IO.FileSystem" />
     <Reference Include="System.Threading.Thread" />
   </ItemGroup>
-  <ItemGroup Condition="'$(TargetsLinux)' == 'true'">
+  <ItemGroup Condition="'$(TargetsLinux)' == 'true' OR '$(TargetsFreeBSD)' == 'true'">
     <Reference Include="System.Threading.Timer" />
   </ItemGroup>
 </Project>
index 25d6821..a3d0ed4 100644 (file)
@@ -13,7 +13,6 @@ namespace System.Net.NetworkInformation.Tests
         private readonly NetworkAddressChangedEventHandler _addressHandler = delegate { };
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/33530", TestPlatforms.FreeBSD)]
         public void NetworkAddressChanged_AddRemove_Success()
         {
             NetworkChange.NetworkAddressChanged += _addressHandler;
@@ -21,7 +20,6 @@ namespace System.Net.NetworkInformation.Tests
         }
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/33530", TestPlatforms.FreeBSD)]
         public void NetworkAddressChanged_JustRemove_Success()
         {
             NetworkChange.NetworkAddressChanged -= _addressHandler;
index b13c458..1a96895 100644 (file)
@@ -13,7 +13,6 @@ namespace System.Net.NetworkInformation.Tests
         private readonly NetworkAvailabilityChangedEventHandler _availabilityHandler = delegate { };
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/33530", TestPlatforms.FreeBSD)]
         public void NetworkAvailabilityChanged_AddRemove_Success()
         {
             NetworkChange.NetworkAvailabilityChanged += _availabilityHandler;
@@ -21,14 +20,12 @@ namespace System.Net.NetworkInformation.Tests
         }
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/33530", TestPlatforms.FreeBSD)]
         public void NetworkAvailabilityChanged_JustRemove_Success()
         {
             NetworkChange.NetworkAvailabilityChanged -= _availabilityHandler;
         }
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/33530", TestPlatforms.FreeBSD)]
         public void NetworkAddressChanged_Add_DoesNotBlock()
         {
             // Register without unregistering.
@@ -42,7 +39,6 @@ namespace System.Net.NetworkInformation.Tests
         }
 
         [Fact]
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/33530", TestPlatforms.FreeBSD)]
         public void NetworkAddressChanged_AddAndRemove_NetworkAvailabilityChanged_JustRemove_Success()
         {
             NetworkChange.NetworkAddressChanged += _addressHandler;
@@ -55,7 +51,6 @@ namespace System.Net.NetworkInformation.Tests
         [InlineData(false, true)]
         [InlineData(true, false)]
         [InlineData(true, true)]
-        [ActiveIssue("https://github.com/dotnet/corefx/issues/33530", TestPlatforms.FreeBSD)]
         public void NetworkAvailabilityChanged_NetworkAddressChanged_AddAndRemove_Success(bool addAddressFirst, bool removeAddressFirst)
         {
             if (addAddressFirst)