Browse Source

simplify the internal API for multicast discovery

Julius Pfrommer 7 years ago
parent
commit
54e39e9635

+ 3 - 4
src/server/ua_server.c

@@ -168,7 +168,7 @@ void UA_Server_delete(UA_Server *server) {
 
 # ifdef UA_ENABLE_DISCOVERY_MULTICAST
     if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
-        UA_Discovery_multicastDestroy(server);
+        destroyMulticastDiscoveryServer(server);
 
     serverOnNetwork_list_entry *son, *son_tmp;
     LIST_FOREACH_SAFE(son, &server->serverOnNetwork, pointers, son_tmp) {
@@ -329,9 +329,8 @@ UA_Server_new(const UA_ServerConfig config) {
     server->mdnsDaemon = NULL;
     server->mdnsSocket = 0;
     server->mdnsMainSrvAdded = UA_FALSE;
-    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) {
-        UA_Discovery_multicastInit(server);
-    }
+    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
+        initMulticastDiscoveryServer(server);
 
     LIST_INIT(&server->serverOnNetwork);
     server->serverOnNetworkSize = 0;

+ 17 - 11
src/server/ua_server_internal.h

@@ -98,13 +98,13 @@ extern UA_THREAD_LOCAL UA_Session* methodCallSession;
 #endif
 
 #ifdef UA_ENABLE_DISCOVERY
+
 typedef struct registeredServer_list_entry {
     LIST_ENTRY(registeredServer_list_entry) pointers;
     UA_RegisteredServer registeredServer;
     UA_DateTime lastSeen;
 } registeredServer_list_entry;
 
-
 # ifdef UA_ENABLE_DISCOVERY_MULTICAST
 typedef struct serverOnNetwork_list_entry {
     LIST_ENTRY(serverOnNetwork_list_entry) pointers;
@@ -116,15 +116,15 @@ typedef struct serverOnNetwork_list_entry {
     char* pathTmp;
 } serverOnNetwork_list_entry;
 
-
 #define SERVER_ON_NETWORK_HASH_PRIME 1009
 typedef struct serverOnNetwork_hash_entry {
     serverOnNetwork_list_entry* entry;
     struct serverOnNetwork_hash_entry* next;
 } serverOnNetwork_hash_entry;
-#endif
 
-#endif
+#endif /* UA_ENABLE_DISCOVERY_MULTICAST */
+
+#endif /* UA_ENABLE_DISCOVERY */
 
 struct UA_Server {
     /* Meta */
@@ -339,14 +339,25 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic);
 
 # ifdef UA_ENABLE_DISCOVERY_MULTICAST
 
-UA_StatusCode UA_Discovery_multicastInit(UA_Server* server);
-void UA_Discovery_multicastDestroy(UA_Server* server);
+UA_StatusCode
+initMulticastDiscoveryServer(UA_Server* server);
+
+void startMulticastDiscoveryServer(UA_Server *server);
+
+void stopMulticastDiscoveryServer(UA_Server *server);
+
+UA_StatusCode
+iterateMulticastDiscoveryServer(UA_Server* server, UA_DateTime *nextRepeat,
+                                UA_Boolean processIn);
+
+void destroyMulticastDiscoveryServer(UA_Server* server);
 
 typedef enum {
     UA_DISCOVERY_TCP,     /* OPC UA TCP mapping */
     UA_DISCOVERY_TLS     /* OPC UA HTTPS mapping */
 } UA_DiscoveryProtocol;
 
+/* Send a multicast probe to find any other OPC UA server on the network through mDNS. */
 UA_StatusCode
 UA_Discovery_multicastQuery(UA_Server* server);
 
@@ -359,11 +370,6 @@ UA_StatusCode
 UA_Discovery_removeRecord(UA_Server* server, const char* servername, const char* hostname,
                           unsigned short port, UA_Boolean removeTxt);
 
-#  ifdef UA_ENABLE_MULTITHREADING
-UA_StatusCode UA_Discovery_multicastListenStart(UA_Server* server);
-UA_StatusCode UA_Discovery_multicastListenStop(UA_Server* server);
-#  endif
-UA_StatusCode UA_Discovery_multicastIterate(UA_Server* server, UA_DateTime *nextRepeat, UA_Boolean processIn);
 # endif
 
 /*****************************/

+ 15 - 86
src/server/ua_server_worker.c

@@ -321,33 +321,6 @@ static void processMainLoopJobs(UA_Server *server) {
 }
 #endif
 
-#ifdef UA_ENABLE_DISCOVERY_MULTICAST
-static UA_StatusCode
-UA_Server_addMdnsRecordForNetworkLayer(UA_Server *server, const char* appName, const UA_ServerNetworkLayer* nl) {
-    UA_UInt16 port = 0;
-    char hostname[256]; hostname[0] = '\0';
-    const char *path;
-    {
-        char* uri = (char*)UA_malloc(sizeof(char) * nl->discoveryUrl.length + 1);
-        strncpy(uri, (char*) nl->discoveryUrl.data, nl->discoveryUrl.length);
-        uri[nl->discoveryUrl.length] = '\0';
-        UA_StatusCode retval;
-        if ((retval = UA_EndpointUrl_split(uri, hostname, &port, &path)) != UA_STATUSCODE_GOOD) {
-            if (retval == UA_STATUSCODE_BADOUTOFRANGE)
-                UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_NETWORK, "Server url is invalid", uri);
-            else if (retval == UA_STATUSCODE_BADATTRIBUTEIDINVALID)
-                UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_NETWORK, "Server url '%s' does not begin with opc.tcp://", uri);
-            UA_free(uri);
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-        }
-        UA_free(uri);
-    }
-    UA_Discovery_addRecord(server, appName, hostname, port, path != NULL && strlen(path) ? path : "", UA_DISCOVERY_TCP, UA_TRUE,
-                           server->config.serverCapabilities, &server->config.serverCapabilitiesSize);
-    return UA_STATUSCODE_GOOD;
-}
-#endif //UA_ENABLE_DISCOVERY_MULTICAST
-
 UA_StatusCode UA_Server_run_startup(UA_Server *server) {
 #ifdef UA_ENABLE_MULTITHREADING
     /* Spin up the worker threads */
@@ -381,30 +354,9 @@ UA_StatusCode UA_Server_run_startup(UA_Server *server) {
 
 
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
-    if (server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) {
-
-        char *appName = (char*)UA_malloc(server->config.mdnsServerName.length +1);
-        memcpy(appName, server->config.mdnsServerName.data, server->config.mdnsServerName.length);
-        appName[server->config.mdnsServerName.length] = '\0';
-
-        for(size_t i = 0; i < server->config.networkLayersSize; i++) {
-            UA_StatusCode retVal = UA_Server_addMdnsRecordForNetworkLayer(
-                    server, appName, &server->config.networkLayers[i]);
-            if (UA_STATUSCODE_GOOD != retVal) {
-                UA_free(appName);
-                return retVal;
-            }
-        }
-        UA_free(appName);
-
-        // find any other server on the net
-        UA_Discovery_multicastQuery(server);
-
-# ifdef UA_ENABLE_MULTITHREADING
-        UA_Discovery_multicastListenStart(server);
-# endif
-    }
-#endif //UA_ENABLE_DISCOVERY_MULTICAST
+    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
+        startMulticastDiscoveryServer(server);
+#endif
 
     return result;
 }
@@ -502,20 +454,17 @@ UA_UInt16 UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) {
     processDelayedCallbacks(server);
 #endif
 
-#ifdef UA_ENABLE_DISCOVERY_MULTICAST
-# ifndef UA_ENABLE_MULTITHREADING
-    if (server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) {
-        UA_DateTime multicastNextRepeat;
-        UA_DateTime_init(&multicastNextRepeat);
-        //TODO multicastNextRepeat does not consider new input data (requests) on the socket. It will be handled on the next call.
-        // if needed, we need to use select with timeout on the multicast socket server->mdnsSocket (see example in mdnsd library) on higher level.
-        if (UA_Discovery_multicastIterate(server, &multicastNextRepeat, UA_TRUE)) {
-            if (multicastNextRepeat < nextRepeated) {
-                UA_DateTime_copy(&multicastNextRepeat, &nextRepeated);
-            }
-        }
+#if defined(UA_ENABLE_DISCOVERY_MULTICAST) && defined(UA_ENABLE_MULTITHREADING)
+    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) {
+        UA_DateTime multicastNextRepeat = 0;
+        // TODO multicastNextRepeat does not consider new input data (requests)
+        // on the socket. It will be handled on the next call. if needed, we
+        // need to use select with timeout on the multicast socket
+        // server->mdnsSocket (see example in mdnsd library) on higher level.
+        if(iterateMulticastDiscoveryServer(server, &multicastNextRepeat, UA_TRUE) &&
+           multicastNextRepeat < nextRepeated)
+            nextRepeated = multicastNextRepeat;
     }
-# endif
 #endif
 
     now = UA_DateTime_nowMonotonic();
@@ -560,28 +509,8 @@ UA_StatusCode UA_Server_run_shutdown(UA_Server *server) {
 #endif
 
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
-    if (server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) {
-        char* hostname = (char*)UA_malloc(sizeof(char) * 256);
-        if (gethostname(hostname, 255) == 0) {
-            char *appName = (char*)UA_malloc(server->config.mdnsServerName.length +1);
-            memcpy(appName, server->config.mdnsServerName.data, server->config.mdnsServerName.length);
-            appName[server->config.mdnsServerName.length] = '\0';
-            UA_Discovery_removeRecord(server,appName, hostname, 4840, UA_TRUE);
-            UA_free(appName);
-        } else {
-            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
-                         "Could not get hostname for multicast discovery.");
-        }
-        UA_free(hostname);
-
-# ifdef UA_ENABLE_MULTITHREADING
-        UA_Discovery_multicastListenStop(server);
-# else
-        // send out last package with TTL = 0
-        UA_Discovery_multicastIterate(server, NULL, UA_FALSE);
-# endif
-    }
-
+    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
+        stopMulticastDiscoveryServer(server);
 #endif
 
     return UA_STATUSCODE_GOOD;

+ 147 - 83
src/server/ua_services_discovery_multicast.c

@@ -25,13 +25,135 @@
 # define CLOSESOCKET(S) close(S)
 #endif
 
+#ifdef UA_ENABLE_MULTITHREADING
+
+static void *
+multicastWorkerLoop(UA_Server *server) {
+    struct timeval next_sleep = {.tv_sec = 0, .tv_usec = 0};
+    volatile UA_Boolean *running = &server->mdnsRunning;
+    fd_set fds;
+
+    while(*running) {
+        FD_ZERO(&fds);
+        FD_SET(server->mdnsSocket, &fds);
+        select(server->mdnsSocket + 1, &fds, 0, 0, &next_sleep);
+
+        if(!*running)
+            break;
+
+        unsigned short retVal =
+            mdnsd_step(server->mdnsDaemon, server->mdnsSocket,
+                       FD_ISSET(server->mdnsSocket, &fds), true, &next_sleep);
+        if (retVal == 1) {
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Multicast error: Can not read from socket. %s", strerror(errno));
+            break;
+        } else if (retVal == 2) {
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Multicast error: Can not write to socket. %s", strerror(errno));
+            break;
+        }
+    }
+    return NULL;
+}
+
+static UA_StatusCode
+multicastListenStart(UA_Server* server) {
+    int err = pthread_create(&server->mdnsThread, NULL,
+                             (void* (*)(void*))multicastWorkerLoop, server);
+    if(err != 0) {
+        UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                     "Multicast error: Can not create multicast thread.");
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+multicastListenStop(UA_Server* server) {
+    mdnsd_shutdown(server->mdnsDaemon);
+    // wake up select
+    write(server->mdnsSocket, "\0", 1);
+    if(pthread_join(server->mdnsThread, NULL)) {
+        UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                     "Multicast error: Can not stop thread.");
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    return UA_STATUSCODE_BADNOTIMPLEMENTED;
+}
+
+# endif /* UA_ENABLE_MULTITHREADING */
+
+static UA_StatusCode
+addMdnsRecordForNetworkLayer(UA_Server *server, const char* appName,
+                             const UA_ServerNetworkLayer* nl) {
+    UA_UInt16 port = 0;
+    char hostname[256]; hostname[0] = '\0';
+    const char *path;
+    char* uri = (char*)UA_malloc(sizeof(char) * nl->discoveryUrl.length + 1);
+    strncpy(uri, (char*) nl->discoveryUrl.data, nl->discoveryUrl.length);
+    uri[nl->discoveryUrl.length] = '\0';
+    UA_StatusCode retval;
+    if ((retval = UA_EndpointUrl_split(uri, hostname, &port, &path)) != UA_STATUSCODE_GOOD) {
+        if (retval == UA_STATUSCODE_BADOUTOFRANGE)
+            UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_NETWORK,
+                           "Server url is invalid", uri);
+        else if (retval == UA_STATUSCODE_BADATTRIBUTEIDINVALID)
+            UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_NETWORK,
+                           "Server url '%s' does not begin with opc.tcp://", uri);
+        UA_free(uri);
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
+    UA_free(uri);
+    UA_Discovery_addRecord(server, appName, hostname, port,
+                           path != NULL && strlen(path) ? path : "", UA_DISCOVERY_TCP, UA_TRUE,
+                           server->config.serverCapabilities, &server->config.serverCapabilitiesSize);
+    return UA_STATUSCODE_GOOD;
+}
+
+void startMulticastDiscoveryServer(UA_Server *server) {
+    char *appName = (char*)UA_alloca(server->config.mdnsServerName.length +1);
+    memcpy(appName, server->config.mdnsServerName.data, server->config.mdnsServerName.length);
+    appName[server->config.mdnsServerName.length] = '\0';
+
+    for(size_t i = 0; i < server->config.networkLayersSize; i++)
+        addMdnsRecordForNetworkLayer(server, appName, &server->config.networkLayers[i]);
+
+    /* find any other server on the net */
+    UA_Discovery_multicastQuery(server);
+
+# ifdef UA_ENABLE_MULTITHREADING
+    multicastListenStart(server);
+# endif
+}
+
+void stopMulticastDiscoveryServer(UA_Server *server) {
+    char hostname[256];
+    if(gethostname(hostname, 255) == 0) {
+        char *appName = (char*)UA_alloca(server->config.mdnsServerName.length + 1);
+        memcpy(appName, server->config.mdnsServerName.data, server->config.mdnsServerName.length);
+        appName[server->config.mdnsServerName.length] = '\0';
+        UA_Discovery_removeRecord(server,appName, hostname, 4840, UA_TRUE);
+    } else {
+        UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                     "Could not get hostname for multicast discovery.");
+    }
+
+# ifdef UA_ENABLE_MULTITHREADING
+    multicastListenStop(server);
+# else
+    // send out last package with TTL = 0
+    iterateMulticastDiscoveryServer(server, NULL, UA_FALSE);
+# endif
+}
+
 /* All filter criteria must be fulfilled */
 static UA_Boolean
 filterServerRecord(size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter,
                    serverOnNetwork_list_entry* current) {
-    for(size_t i = 0; i < request->serverCapabilityFilterSize; i++) {
+    for(size_t i = 0; i < serverCapabilityFilterSize; i++) {
         for(size_t j = 0; j < current->serverOnNetwork.serverCapabilitiesSize; j++)
-            if(!UA_String_equal(&request->serverCapabilityFilter[i],
+            if(!UA_String_equal(&serverCapabilityFilter[i],
                                 &current->serverOnNetwork.serverCapabilities[j]))
                 return false;
     }
@@ -74,7 +196,7 @@ void Service_FindServersOnNetwork(UA_Server *server, UA_Session *session,
     /* Allocate the array for the response */
     response->servers = (UA_ServerOnNetwork*)UA_malloc(sizeof(UA_ServerOnNetwork)*filteredCount);
     if(!response->servers) {
-        response->serversSize = -1;
+        response->serversSize = 0;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
     }
     response->serversSize = filteredCount;
@@ -120,22 +242,24 @@ UA_Discovery_update_MdnsForDiscoveryUrl(UA_Server *server, const char *serverNam
             UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
                            "Could not remove mDNS record for hostname %s.", serverName);
         }
-    } else {
-        UA_String *capabilities = NULL;
-        size_t capabilitiesSize = 0;
-        if(mdnsConfig) {
-            capabilities = mdnsConfig->serverCapabilities;
-            capabilitiesSize = mdnsConfig->serverCapabilitiesSize;
-        }
-        UA_StatusCode addRetval =
-                UA_Discovery_addRecord(server, serverName, hostname,
-                                       (unsigned short) port, path,
-                                       UA_DISCOVERY_TCP, updateTxt,
-                                       capabilities, &capabilitiesSize);
-        if(addRetval != UA_STATUSCODE_GOOD) {
-            UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
-                           "Could not add mDNS record for hostname %s.", serverName);
-        }
+        return;
+    }
+    
+    UA_String *capabilities = NULL;
+    size_t capabilitiesSize = 0;
+    if(mdnsConfig) {
+        capabilities = mdnsConfig->serverCapabilities;
+        capabilitiesSize = mdnsConfig->serverCapabilitiesSize;
+    }
+
+    UA_StatusCode addRetval =
+        UA_Discovery_addRecord(server, serverName, hostname,
+                               (unsigned short) port, path,
+                               UA_DISCOVERY_TCP, updateTxt,
+                               capabilities, &capabilitiesSize);
+    if(addRetval != UA_STATUSCODE_GOOD) {
+        UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
+                       "Could not add mDNS record for hostname %s.", serverName);
     }
 }
 
@@ -194,7 +318,7 @@ discovery_createMulticastSocket(void) {
 }
 
 UA_StatusCode
-UA_Discovery_multicastInit(UA_Server* server) {
+initMulticastDiscoveryServer(UA_Server* server) {
     server->mdnsDaemon = mdnsd_new(QCLASS_IN, 1000);
     if((server->mdnsSocket = discovery_createMulticastSocket()) == 0) {
         UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
@@ -205,7 +329,7 @@ UA_Discovery_multicastInit(UA_Server* server) {
     return UA_STATUSCODE_GOOD;
 }
 
-void UA_Discovery_multicastDestroy(UA_Server* server) {
+void destroyMulticastDiscoveryServer(UA_Server* server) {
     mdnsd_shutdown(server->mdnsDaemon);
     mdnsd_free(server->mdnsDaemon);
 }
@@ -289,7 +413,6 @@ discovery_multicastQueryAnswer(mdns_answer_t *a, void *arg) {
     return 0;
 }
 
-/* Send a multicast probe to find any other OPC UA server on the network through mDNS. */
 UA_StatusCode
 UA_Discovery_multicastQuery(UA_Server* server) {
     mdnsd_query(server->mdnsDaemon, "_opcua-tcp._tcp.local.",
@@ -451,8 +574,8 @@ UA_Discovery_removeRecord(UA_Server* server, const char* servername, const char*
 }
 
 UA_StatusCode
-UA_Discovery_multicastIterate(UA_Server* server, UA_DateTime *nextRepeat,
-                              UA_Boolean processIn) {
+iterateMulticastDiscoveryServer(UA_Server* server, UA_DateTime *nextRepeat,
+                                UA_Boolean processIn) {
     struct timeval next_sleep = { 0, 0 };
     unsigned short retVal = mdnsd_step(server->mdnsDaemon, server->mdnsSocket,
                                        processIn, true, &next_sleep);
@@ -475,63 +598,4 @@ UA_Discovery_multicastIterate(UA_Server* server, UA_DateTime *nextRepeat,
     return UA_STATUSCODE_GOOD;
 }
 
-#ifdef UA_ENABLE_MULTITHREADING
-
-static void *
-multicastWorkerLoop(UA_Server *server) {
-    struct timeval next_sleep = {.tv_sec = 0, .tv_usec = 0};
-    volatile UA_Boolean *running = &server->mdnsRunning;
-    fd_set fds;
-
-    while(*running) {
-        FD_ZERO(&fds);
-        FD_SET(server->mdnsSocket, &fds);
-        select(server->mdnsSocket + 1, &fds, 0, 0, &next_sleep);
-
-        if(!*running)
-            break;
-
-        unsigned short retVal =
-            mdnsd_step(server->mdnsDaemon, server->mdnsSocket,
-                       FD_ISSET(server->mdnsSocket, &fds), true, &next_sleep);
-        if (retVal == 1) {
-            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
-                         "Multicast error: Can not read from socket. %s", strerror(errno));
-            break;
-        } else if (retVal == 2) {
-            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
-                         "Multicast error: Can not write to socket. %s", strerror(errno));
-            break;
-        }
-    }
-    return NULL;
-}
-
-UA_StatusCode
-UA_Discovery_multicastListenStart(UA_Server* server) {
-    int err = pthread_create(&server->mdnsThread, NULL,
-                             (void* (*)(void*))multicastWorkerLoop, server);
-    if(err != 0) {
-        UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
-                     "Multicast error: Can not create multicast thread.");
-        return UA_STATUSCODE_BADUNEXPECTEDERROR;
-    }
-    return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode
-UA_Discovery_multicastListenStop(UA_Server* server) {
-    mdnsd_shutdown(server->mdnsDaemon);
-    // wake up select
-    write(server->mdnsSocket, "\0", 1);
-    if(pthread_join(server->mdnsThread, NULL)) {
-        UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
-                     "Multicast error: Can not stop thread.");
-        return UA_STATUSCODE_BADUNEXPECTEDERROR;
-    }
-    return UA_STATUSCODE_BADNOTIMPLEMENTED;
-}
-
-# endif /* UA_ENABLE_MULTITHREADING */
-
 #endif /* defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST) */