Add store app workaround for Windows network monitor
authorDave Thaler <dthaler@microsoft.com>
Fri, 21 Oct 2016 21:34:13 +0000 (14:34 -0700)
committerDave Thaler <dthaler@microsoft.com>
Thu, 27 Oct 2016 00:37:31 +0000 (00:37 +0000)
Also fix some typos in run.bat

Change-Id: I0060b833a5c984bfb0555168927db845bee76c3e
Signed-off-by: Dave Thaler <dthaler@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/13635
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Soemin Tjong <stjong@microsoft.com>
Reviewed-by: Dan Mihai <Daniel.Mihai@microsoft.com>
Reviewed-by: David Antler <david.a.antler@intel.com>
resource/csdk/connectivity/src/ip_adapter/windows/caipnwmonitor.c
run.bat

index 6350025..2e401e2 100644 (file)
 
 #define TAG "IP_MONITOR"
 
+// When this is defined, a socket will be used to get address change events.  The
+// SIO_ADDRESS_LIST_CHANGE socket option is accessible on all versions of Windows
+// and is available to both desktop and store apps, but it is more complex and hence
+// more appropriate for use by applications using SIO_ADDRESS_LIST_QUERY to get addresses
+// from Winsock rather than GetAdaptersAddresses() which we need to use to get additional
+// information.  We expect NotifyUnicastIpAddressChange will be available to store apps
+// at some point in the future and this workaround can go away at that point.
+#define USE_SOCKET_ADDRESS_CHANGE_EVENT
+
 /**
  * Mutex for synchronizing access to cached address information.
  */
@@ -229,6 +238,177 @@ static void CALLBACK IpAddressChangeCallback(void *context,
     oc_mutex_unlock(g_CAIPNetworkMonitorMutex);
 }
 
+#ifdef USE_SOCKET_ADDRESS_CHANGE_EVENT
+static HANDLE g_CAIPNetworkMonitorShutdownEvent = NULL;
+
+void UnregisterForIpAddressChange()
+{
+    if (g_CAIPNetworkMonitorShutdownEvent != NULL)
+    {
+        // Cancel the worker thread.
+        if (SetEvent(g_CAIPNetworkMonitorShutdownEvent))
+        {
+            WaitForSingleObject(g_CAIPNetworkMonitorChangeNotificationHandle, INFINITE);
+        }
+
+        CloseHandle(g_CAIPNetworkMonitorShutdownEvent);
+        g_CAIPNetworkMonitorShutdownEvent = NULL;
+    }
+    if (g_CAIPNetworkMonitorChangeNotificationHandle != NULL)
+    {
+        CloseHandle(g_CAIPNetworkMonitorChangeNotificationHandle);
+        g_CAIPNetworkMonitorChangeNotificationHandle = NULL;
+    }
+}
+
+DWORD WINAPI IpNetworkMonitorWorker(PVOID context)
+{
+    OVERLAPPED overlapped = {0};
+
+    WORD wVersionRequested = MAKEWORD(2, 2);
+    WSADATA wsaData = {.wVersion = 0};
+    int err = WSAStartup(wVersionRequested, &wsaData);
+    if (err != NO_ERROR)
+    {
+        return err;
+    }
+
+    SOCKET nwmSocket = WSASocket(
+        AF_INET6,
+        SOCK_DGRAM,
+        0, // Default proto.
+        NULL, // No other protocol info.
+        0, // Ignore group.
+        WSA_FLAG_OVERLAPPED);
+    if (INVALID_SOCKET == nwmSocket)
+    {
+        err = WSAGetLastError();
+        goto done;
+    }
+
+    // Put socket into dual IPv4/IPv6 mode.
+    BOOL ipv6Only = FALSE;
+    if (SOCKET_ERROR == setsockopt(nwmSocket,
+                                   IPPROTO_IPV6,
+                                   IPV6_V6ONLY,
+                                   (char*)&ipv6Only,
+                                   sizeof(ipv6Only)))
+    {
+        err = WSAGetLastError();
+        goto done;
+    }
+
+    overlapped.hEvent = CreateEvent(
+        NULL, // No security descriptor.
+        TRUE, // Manual reset event.
+        FALSE, // Start not signaled.
+        NULL); // No name.
+    if (NULL == overlapped.hEvent)
+    {
+        err = GetLastError();
+        goto done;
+    }
+
+    WSAEVENT eventList[2] = { overlapped.hEvent,
+                              g_CAIPNetworkMonitorShutdownEvent,
+                            };
+    DWORD bytesReturned = 0;
+    for (;;)
+    {
+        if (SOCKET_ERROR == WSAIoctl(nwmSocket,
+                                     SIO_ADDRESS_LIST_CHANGE,
+                                     NULL, // No input buffer.
+                                     0,
+                                     NULL, // No outupt buffer.
+                                     0,
+                                     &bytesReturned,
+                                     &overlapped,
+                                     NULL)) // No completion routine.
+        {
+            err = WSAGetLastError();
+            if (err != ERROR_IO_PENDING)
+            {
+                break;
+            }
+            else
+            {
+                // Wait for an address change or a request to cancel the thread.
+                DWORD waitStatus = WSAWaitForMultipleEvents(_countof(eventList),
+                                                            eventList,
+                                                            FALSE, // Wait for any one to fire.
+                                                            WSA_INFINITE,
+                                                            FALSE); // No I/O completion routines.
+
+                if (waitStatus != WSA_WAIT_EVENT_0)
+                {
+                    // The cancel event was signaled.  There is no need to call CancelIo
+                    // here, because we will close the socket handle below, causing any
+                    // pending I/O to be canceled then.
+                    assert(waitStatus == WSA_WAIT_EVENT_0 + 1);
+                    break;
+                }
+
+                WSAResetEvent(overlapped.hEvent);
+            }
+        }
+
+        // We have a change to process.  The address change callback ignores
+        // the parameters, so we just pass default values.
+        IpAddressChangeCallback(context, NULL, MibInitialNotification);
+    }
+
+done:
+    if (nwmSocket != INVALID_SOCKET)
+    {
+        closesocket(nwmSocket);
+        nwmSocket = INVALID_SOCKET;
+    }
+    if (overlapped.hEvent != NULL)
+    {
+        CloseHandle(overlapped.hEvent);
+        overlapped.hEvent = NULL;
+    }
+    WSACleanup();
+    return err;
+}
+
+BOOL RegisterForIpAddressChange()
+{
+    assert(g_CAIPNetworkMonitorChangeNotificationHandle == NULL);
+
+    g_CAIPNetworkMonitorShutdownEvent = CreateEvent(
+        NULL, // No security descriptor.
+        TRUE, // Manual reset event.
+        FALSE, // Start not signaled.
+        NULL); // No name.
+    if (g_CAIPNetworkMonitorShutdownEvent == NULL)
+    {
+        return false;
+    }
+
+    g_CAIPNetworkMonitorChangeNotificationHandle = CreateThread(
+        NULL, // Default security attributes.
+        0, // Default stack size.
+        IpNetworkMonitorWorker,
+        NULL, // No context.
+        0, // Run immediately.
+        NULL); // We don't need the thread id.
+
+    if (g_CAIPNetworkMonitorChangeNotificationHandle == NULL)
+    {
+        CloseHandle(g_CAIPNetworkMonitorShutdownEvent);
+        g_CAIPNetworkMonitorShutdownEvent = NULL;
+        return false;
+    }
+
+    // Signal the callback to query the initial state.  The address change callback ignores
+    // the parameters, so we just pass default values.
+    IpAddressChangeCallback(NULL, NULL, MibInitialNotification);
+
+    return true;
+}
+#endif
+
 /**
  * Start network monitor.
  *
@@ -253,6 +433,12 @@ CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
 
     if (g_CAIPNetworkMonitorChangeNotificationHandle == NULL)
     {
+#ifdef USE_SOCKET_ADDRESS_CHANGE_EVENT
+        if (!RegisterForIpAddressChange())
+        {
+            return CA_STATUS_FAILED;
+        }
+#else
         int err = NotifyUnicastIpAddressChange(AF_UNSPEC, IpAddressChangeCallback, NULL,
                                                true,
                                                &g_CAIPNetworkMonitorChangeNotificationHandle);
@@ -260,6 +446,7 @@ CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
         {
             return CA_STATUS_FAILED;
         }
+#endif
     }
     return CA_STATUS_OK;
 }
@@ -274,9 +461,13 @@ CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
 {
     if (g_CAIPNetworkMonitorChangeNotificationHandle != NULL)
     {
+#ifdef USE_SOCKET_ADDRESS_CHANGE_EVENT
+        UnregisterForIpAddressChange();
+#else
         int err = CancelMibChangeNotify2(g_CAIPNetworkMonitorChangeNotificationHandle);
         assert(err == NO_ERROR);
         g_CAIPNetworkMonitorChangeNotificationHandle = NULL;
+#endif
     }
 
     CAIPDestroyNetworkMonitorList();
diff --git a/run.bat b/run.bat
index 53e2f79..1c7b1c9 100644 (file)
--- a/run.bat
+++ b/run.bat
@@ -97,7 +97,7 @@ if "!RUN_ARG!"=="server" (
 ) else if "!RUN_ARG!"=="clienthq" (
   cd %BUILD_DIR%\resource\examples
   %DEBUG% simpleclientHQ.exe
-)else if "!RUN_ARG!"=="mediaclient" (
+) else if "!RUN_ARG!"=="mediaclient" (
   cd %BUILD_DIR%\resource\examples
   %DEBUG% mediaclient.exe
 ) else if "!RUN_ARG!"=="mediaserver" (
@@ -140,6 +140,7 @@ if "!RUN_ARG!"=="server" (
   echo   WITH_RD=%WITH_RD%
   echo   ROUTING=%ROUTING%
   echo   WITH_UPSTREAM_LIBCOAP=%WITH_UPSTREAM_LIBCOAP%
+  echo   MSVC_VERSION=%MSVC_VERSION%
   echo.scons VERBOSE=1 %BUILD_OPTIONS%
   scons VERBOSE=1 %BUILD_OPTIONS%
 ) else if "!RUN_ARG!"=="clean" (
@@ -152,11 +153,12 @@ if "!RUN_ARG!"=="server" (
   erase resource\c_common\iotivity_config.h
   erase extlibs\libcoap\coap.lib
   erase extlibs\libcoap\libcoap\include\coap\coap_config.h
+  erase extlibs\mbedtls\mbed*.lib
 ) else if "!RUN_ARG!"=="cleangtest" (
   rd /s /q extlibs\gtest\gtest-1.7.0
   del extlibs\gtest\gtest-1.7.0.zip
 ) else (
-    echo %0 - Script requires a valid argument!
+    echo.%0 - Script requires a valid argument!
     goto :EOF
 )
 
@@ -170,11 +172,11 @@ goto EOF
 echo %0 - Helper to build/test iotivity.  Requires an argument.
 echo Installation: Drop this into your iotivity root directory to use it.
 echo.
-echo. Default buidl settings are: debug binaries run unittests and no logging
+echo. Default build settings are: debug binaries run unittests and no logging
 echo.
 echo. Default build parameters can be overridden using the following arguments
 echo. 
-echo   -arch [x86 | amd64]    - Build either amd64 or x86 architecture binaries
+echo   -arch [x86 ^| amd64]    - Build either amd64 or x86 architecture binaries
 echo.
 echo   -noTest                - Don't run the unittests after building the binaries
 echo.