Bläddra i källkod

Stack: Add additional config flag to enable mDNS and fix UaExpert not showing LDS Server

Stefan Profanter 5 år sedan
förälder
incheckning
d419a00a6b

+ 17 - 7
examples/discovery/server_lds.c

@@ -25,20 +25,30 @@ int main(void) {
     UA_ServerConfig *config = UA_Server_getConfig(server);
     UA_ServerConfig_setDefault(config);
 
-    // NOTE:
-    // A server instance defined as DISCOVERYSERVER will not be shown in UaExpert.
-    // See also:
-	// https://forum.unified-automation.com/topic1987.html
-
+	// This is an LDS server only. Set the application type to DISCOVERYSERVER.
+	// NOTE: This will cause UaExpert to not show this instance in the server list.
+	// See also: https://forum.unified-automation.com/topic1987.html
     config->applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER;
     UA_String_clear(&config->applicationDescription.applicationUri);
     config->applicationDescription.applicationUri =
             UA_String_fromChars("urn:open62541.example.local_discovery_server");
+
+    // Enable the mDNS announce and response functionality
+    config->discovery.mdnsEnable = true;
+
     config->discovery.mdns.mdnsServerName = UA_String_fromChars("LDS");
+
     // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
+    // For a LDS server, you should only indicate the LDS capability.
+    // If this instance is an LDS and at the same time a normal OPC UA server, you also have to indicate
+    // the additional capabilities.
+    // NOTE: UaExpert does not show LDS-only servers in the list.
+    // See also: https://forum.unified-automation.com/topic1987.html
+
+    // E.g. here we only set LDS, and you will not see it in UaExpert
     config->discovery.mdns.serverCapabilitiesSize = 1;
-    UA_String *caps = UA_String_new();
-    *caps = UA_String_fromChars("LDS");
+    UA_String *caps = (UA_String *) UA_Array_new(1, &UA_TYPES[UA_TYPES_STRING]);
+    caps[0] = UA_String_fromChars("LDS");
     config->discovery.mdns.serverCapabilities = caps;
 
     /* timeout in seconds when to automatically remove a registered server from

+ 25 - 7
examples/discovery/server_multicast.c

@@ -106,7 +106,7 @@ UA_EndpointDescription *getRegisterEndpointFromServer(const char *discoveryServe
     }
     UA_Array_delete(endpointArray, endpointArraySize,
                     &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
-
+	UA_Client_delete(client);
     return returnEndpoint;
 }
 
@@ -236,16 +236,33 @@ int main(int argc, char **argv) {
     // use port 0 to dynamically assign port
     UA_ServerConfig_setMinimal(config, 0, NULL);
 
-    // To enable mDNS discovery, set application type to discovery server.
-    config->applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER;
+	// An LDS server normally has the application type to DISCOVERYSERVER.
+	// Since this instance implements LDS and other OPC UA services, we set the type to SERVER.
+	// NOTE: Using DISCOVERYSERVER will cause UaExpert to not show this instance in the server list.
+	// See also: https://forum.unified-automation.com/topic1987.html
+
+    config->applicationDescription.applicationType = UA_APPLICATIONTYPE_SERVER;
     UA_String_clear(&config->applicationDescription.applicationUri);
     config->applicationDescription.applicationUri =
         UA_String_fromChars("urn:open62541.example.server_multicast");
+
+	// Enable the mDNS announce and response functionality
+	config->discovery.mdnsEnable = true;
+
     config->discovery.mdns.mdnsServerName = UA_String_fromChars("Sample Multicast Server");
-    // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
-    //config.serverCapabilitiesSize = 1;
-    //UA_String caps = UA_String_fromChars("LDS");
-    //config.serverCapabilities = ∩︀
+
+	// See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
+	// For a LDS server, you should only indicate the LDS capability.
+	// If this instance is an LDS and at the same time a normal OPC UA server, you also have to indicate
+	// the additional capabilities.
+	// NOTE: UaExpert does not show LDS-only servers in the list.
+	// See also: https://forum.unified-automation.com/topic1987.html
+
+	config->discovery.mdns.serverCapabilitiesSize = 2;
+	UA_String *caps = (UA_String *) UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
+	caps[0] = UA_String_fromChars("LDS");
+	caps[1] = UA_String_fromChars("NA");
+	config->discovery.mdns.serverCapabilities = caps;
 
     // Start the server and call iterate to wait for the multicast discovery of the LDS
     UA_StatusCode retval = UA_Server_run_startup(server);
@@ -297,6 +314,7 @@ int main(int argc, char **argv) {
     char *endpointUrl = (char*)UA_malloc(endpointRegister->endpointUrl.length + 1);
     memcpy(endpointUrl, endpointRegister->endpointUrl.data, endpointRegister->endpointUrl.length);
     endpointUrl[endpointRegister->endpointUrl.length] = 0;
+    UA_EndpointDescription_delete(endpointRegister);
     retval = UA_Server_addPeriodicServerRegisterCallback(server, clientRegister, endpointUrl,
                                                          10 * 60 * 1000, 500, NULL);
     if(retval != UA_STATUSCODE_GOOD) {

+ 3 - 0
include/open62541/server_config.h

@@ -71,6 +71,9 @@ typedef struct {
 	 * state of the semaphore file. */
 	UA_UInt32 cleanupTimeout;
 
+	/* Enable mDNS announce and response to queries */
+	bool mdnsEnable;
+
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
 	UA_MdnsDiscoveryConfiguration mdns;
 #endif

+ 2 - 2
src/server/ua_discovery_manager.c

@@ -94,7 +94,7 @@ UA_DiscoveryManager_init(UA_DiscoveryManager *dm, UA_Server *server) {
     dm->mdnsDaemon = NULL;
     dm->mdnsSocket = UA_INVALID_SOCKET;
     dm->mdnsMainSrvAdded = false;
-    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
+    if(server->config.discovery.mdnsEnable)
         initMulticastDiscoveryServer(dm, server);
 
     LIST_INIT(&dm->serverOnNetwork);
@@ -125,7 +125,7 @@ UA_DiscoveryManager_deleteMembers(UA_DiscoveryManager *dm, UA_Server *server) {
     }
 
 # ifdef UA_ENABLE_DISCOVERY_MULTICAST
-    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
+    if(server->config.discovery.mdnsEnable)
         destroyMulticastDiscoveryServer(dm);
 
     serverOnNetwork_list_entry *son, *son_tmp;

+ 2 - 2
src/server/ua_discovery_manager.h

@@ -123,7 +123,7 @@ void mdns_record_received(const struct resource *r, void *data);
 
 void mdns_create_txt(UA_Server *server, const char *fullServiceDomain,
                      const char *path, const UA_String *capabilites,
-                     const size_t *capabilitiesSize,
+                     const size_t capabilitiesSize,
                      void (*conflict)(char *host, int type, void *arg));
 
 void mdns_set_address_record(UA_Server *server,
@@ -156,7 +156,7 @@ UA_Discovery_addRecord(UA_Server *server, const UA_String *servername,
                        const UA_String *hostname, UA_UInt16 port,
                        const UA_String *path, const UA_DiscoveryProtocol protocol,
                        UA_Boolean createTxt, const UA_String* capabilites,
-                       size_t *capabilitiesSize);
+                       const size_t capabilitiesSize);
 UA_StatusCode
 UA_Discovery_removeRecord(UA_Server *server, const UA_String *servername,
                           const UA_String *hostname, UA_UInt16 port,

+ 3 - 6
src/server/ua_server.c

@@ -436,8 +436,7 @@ UA_Server_run_startup(UA_Server *server) {
 
     /* Start the multicast discovery server */
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
-    if(server->config.applicationDescription.applicationType ==
-       UA_APPLICATIONTYPE_DISCOVERYSERVER)
+    if(server->config.discovery.mdnsEnable)
         startMulticastDiscoveryServer(server);
 #endif
 
@@ -480,8 +479,7 @@ UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) {
     }
 
 #if defined(UA_ENABLE_DISCOVERY_MULTICAST) && !defined(UA_ENABLE_MULTITHREADING)
-    if(server->config.applicationDescription.applicationType ==
-       UA_APPLICATIONTYPE_DISCOVERYSERVER) {
+    if(server->config.discovery.mdnsEnable) {
         // 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
@@ -523,8 +521,7 @@ UA_Server_run_shutdown(UA_Server *server) {
 
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
     /* Stop multicast discovery */
-    if(server->config.applicationDescription.applicationType ==
-       UA_APPLICATIONTYPE_DISCOVERYSERVER)
+    if(server->config.discovery.mdnsEnable)
         stopMulticastDiscoveryServer(server);
 #endif
 

+ 2 - 0
src/server/ua_server_discovery.c

@@ -61,6 +61,7 @@ register_server_with_discovery_server(UA_Server *server,
         request.server.discoveryUrls[config_discurls + i] = nl->discoveryUrl;
     }
 
+#ifdef UA_ENABLE_DISCOVERY_MULTICAST
     request.discoveryConfigurationSize = 1;
     request.discoveryConfiguration = UA_ExtensionObject_new();
     UA_ExtensionObject_init(&request.discoveryConfiguration[0]);
@@ -68,6 +69,7 @@ register_server_with_discovery_server(UA_Server *server,
     request.discoveryConfiguration[0].encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
     request.discoveryConfiguration[0].content.decoded.type = &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION];
     request.discoveryConfiguration[0].content.decoded.data = &server->config.discovery.mdns;
+#endif
 
     // First try with RegisterServer2, if that isn't implemented, use RegisterServer
     UA_RegisterServer2Response response;

+ 3 - 3
src/server/ua_server_discovery_mdns.c

@@ -507,7 +507,7 @@ mdns_record_received(const struct resource *r, void *data) {
 
 void
 mdns_create_txt(UA_Server *server, const char *fullServiceDomain, const char *path,
-                const UA_String *capabilites, const size_t *capabilitiesSize,
+                const UA_String *capabilites, const size_t capabilitiesSize,
                 void (*conflict)(char *host, int type, void *arg)) {
     mdns_record_t *r = mdnsd_unique(server->discoveryManager.mdnsDaemon, fullServiceDomain,
                                     QTYPE_TXT, 600, conflict, server);
@@ -538,7 +538,7 @@ mdns_create_txt(UA_Server *server, const char *fullServiceDomain, const char *pa
 
     /* calculate max string length: */
     size_t capsLen = 0;
-    for(size_t i = 0; i < *capabilitiesSize; i++) {
+    for(size_t i = 0; i < capabilitiesSize; i++) {
         /* add comma or last \0 */
         capsLen += capabilites[i].length + 1;
     }
@@ -549,7 +549,7 @@ mdns_create_txt(UA_Server *server, const char *fullServiceDomain, const char *pa
         /* todo: malloc may fail: return a statuscode */
         caps = (char*)UA_malloc(sizeof(char) * capsLen);
         size_t idx = 0;
-        for(size_t i = 0; i < *capabilitiesSize; i++) {
+        for(size_t i = 0; i < capabilitiesSize; i++) {
             memcpy(caps + idx, (const char *) capabilites[i].data, capabilites[i].length);
             idx += capabilites[i].length + 1;
             caps[idx - 1] = ',';

+ 5 - 12
src/server/ua_services_discovery.c

@@ -92,11 +92,6 @@ setApplicationDescriptionFromServer(UA_ApplicationDescription *target, const UA_
     if(result != UA_STATUSCODE_GOOD)
         return result;
 
-    // UaExpert does not list DiscoveryServer, thus set it to Server
-    // See http://forum.unified-automation.com/topic1987.html
-    if(target->applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
-        target->applicationType = UA_APPLICATIONTYPE_SERVER;
-
     /* add the discoveryUrls from the networklayers */
     size_t discSize = sizeof(UA_String) * (target->discoveryUrlsSize + server->config.networkLayersSize);
     UA_String* disc = (UA_String *)UA_realloc(target->discoveryUrls, discSize);
@@ -180,8 +175,8 @@ void Service_FindServers(UA_Server *server, UA_Session *session,
     }
 
     size_t allocSize = foundServersSize;
-    if(foundSelf)
-        allocSize++;
+	if(foundSelf)
+		allocSize++;
 
     /* Nothing to do? */
     if(allocSize == 0)
@@ -198,12 +193,10 @@ void Service_FindServers(UA_Server *server, UA_Session *session,
     /* Copy into the response. TODO: Evaluate return codes */
     size_t pos = 0;
     if(foundSelf) {
-        setApplicationDescriptionFromServer(&response->servers[0], server);
-        pos = 1;
+        setApplicationDescriptionFromServer(&response->servers[pos++], server);
     }
     for(size_t i = 0; i < foundServersSize; i++) {
-        setApplicationDescriptionFromRegisteredServer(request, &response->servers[pos], foundServers[i]);
-        pos++;
+        setApplicationDescriptionFromRegisteredServer(request, &response->servers[pos++], foundServers[i]);
     }
 
 #endif
@@ -386,7 +379,7 @@ process_RegisterServer(UA_Server *server, UA_Session *session,
     }
 
 #ifdef UA_ENABLE_DISCOVERY_MULTICAST
-    if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) {
+    if(server->config.discovery.mdnsEnable) {
         for(size_t i = 0; i < requestServer->discoveryUrlsSize; i++) {
             /* create TXT if is online and first index, delete TXT if is offline and last index */
             UA_Boolean updateTxt = (requestServer->isOnline && i==0) ||

+ 14 - 7
src/server/ua_services_discovery_multicast.c

@@ -88,10 +88,17 @@ addMdnsRecordForNetworkLayer(UA_Server *server, const UA_String *appName,
                        (int)nl->discoveryUrl.length, nl->discoveryUrl.data);
         return retval;
     }
-    UA_Discovery_addRecord(server, appName, &hostname, port,
-                           &path, UA_DISCOVERY_TCP, true,
-                           server->config.discovery.mdns.serverCapabilities,
-                           &server->config.discovery.mdns.serverCapabilitiesSize);
+
+    retval = UA_Discovery_addRecord(server, appName, &hostname, port,
+                                    &path, UA_DISCOVERY_TCP, true,
+									server->config.discovery.mdns.serverCapabilities,
+									server->config.discovery.mdns.serverCapabilitiesSize);
+	if(retval != UA_STATUSCODE_GOOD) {
+		UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_NETWORK,
+					   "Cannot add mDNS Record: %s",
+					   UA_StatusCode_name(retval));
+		return retval;
+	}
     return UA_STATUSCODE_GOOD;
 }
 
@@ -229,7 +236,7 @@ UA_Server_updateMdnsForDiscoveryUrl(UA_Server *server, const UA_String *serverNa
     UA_StatusCode addRetval =
         UA_Discovery_addRecord(server, serverName, &hostname,
                                port, &path, UA_DISCOVERY_TCP, updateTxt,
-                               capabilities, &capabilitiesSize);
+                               capabilities, capabilitiesSize);
     if(addRetval != UA_STATUSCODE_GOOD)
         UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                        "Could not add mDNS record for hostname %.*s.",
@@ -343,12 +350,12 @@ UA_Discovery_addRecord(UA_Server *server, const UA_String *servername,
                        const UA_String *hostname, UA_UInt16 port,
                        const UA_String *path, const UA_DiscoveryProtocol protocol,
                        UA_Boolean createTxt, const UA_String* capabilites,
-                       size_t *capabilitiesSize) {
+                       const size_t capabilitiesSize) {
     // we assume that the hostname is not an IP address, but a valid domain name
     // It is required by the OPC UA spec (see Part 12, DiscoveryURL to DNS SRV mapping)
     // to always use the hostname instead of the IP address
 
-    if(!capabilitiesSize || (*capabilitiesSize > 0 && !capabilites))
+    if(capabilitiesSize > 0 && !capabilites)
         return UA_STATUSCODE_BADINVALIDARGUMENT;
 
     size_t hostnameLen = hostname->length;

+ 2 - 8
tests/fuzz/corpus_generator.c

@@ -187,19 +187,13 @@ registerServer2Request(UA_Client *client) {
 
     initUaRegisterServer(&request.server);
 
-    UA_MdnsDiscoveryConfiguration mdnsConfig;
-    UA_MdnsDiscoveryConfiguration_init(&mdnsConfig);
-
     request.discoveryConfigurationSize = 1;
     request.discoveryConfiguration = UA_ExtensionObject_new();
     UA_ExtensionObject_init(&request.discoveryConfiguration[0]);
+	// Set to NODELETE so that we can just use a pointer to the mdns config
     request.discoveryConfiguration[0].encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
     request.discoveryConfiguration[0].content.decoded.type = &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION];
-    request.discoveryConfiguration[0].content.decoded.data = &mdnsConfig;
-
-    mdnsConfig.mdnsServerName = server->config.mdnsServerName;
-    mdnsConfig.serverCapabilities = server->config.serverCapabilities;
-    mdnsConfig.serverCapabilitiesSize = server->config.serverCapabilitiesSize;
+	request.discoveryConfiguration[0].content.decoded.data = &server->config.discovery.mdns;
 
     // First try with RegisterServer2, if that isn't implemented, use RegisterServer
     UA_RegisterServer2Response response;

+ 9 - 0
tests/server/check_discovery.c

@@ -53,11 +53,14 @@ static void setup_lds(void) {
     UA_LocalizedText_deleteMembers(&config_lds->applicationDescription.applicationName);
     config_lds->applicationDescription.applicationName
         = UA_LOCALIZEDTEXT_ALLOC("en", "LDS Server");
+    config_lds->discovery.mdnsEnable = true;
+#ifdef UA_ENABLE_DISCOVERY_MULTICAST
     config_lds->discovery.mdns.mdnsServerName = UA_String_fromChars("LDS_test");
     config_lds->discovery.mdns.serverCapabilitiesSize = 1;
     UA_String *caps = UA_String_new();
     *caps = UA_String_fromChars("LDS");
     config_lds->discovery.mdns.serverCapabilities = caps;
+#endif
     config_lds->discovery.cleanupTimeout = registerTimeout;
 
     UA_Server_run_startup(server_lds);
@@ -103,7 +106,9 @@ static void setup_register(void) {
     UA_LocalizedText_deleteMembers(&config_register->applicationDescription.applicationName);
     config_register->applicationDescription.applicationName =
         UA_LOCALIZEDTEXT_ALLOC("de", "Anmeldungsserver");
+#ifdef UA_ENABLE_DISCOVERY_MULTICAST
     config_register->discovery.mdns.mdnsServerName = UA_String_fromChars("Register_test");
+#endif
 
     UA_Server_run_startup(server_register);
     THREAD_CREATE(server_thread_register, serverloop_register);
@@ -143,6 +148,8 @@ START_TEST(Server_unregister) {
 }
 END_TEST
 
+#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
+
 #ifndef WIN32
 #define SEMAPHORE_PATH "/tmp/open62541-unit-test-semaphore"
 #else
@@ -180,6 +187,8 @@ START_TEST(Server_unregister_semaphore) {
 }
 END_TEST
 
+#endif /* UA_ENABLE_DISCOVERY_SEMAPHORE */
+
 START_TEST(Server_register_periodic) {
     ck_assert(clientRegisterRepeated == NULL);