ua_server.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
  6. * Copyright 2014-2017 (c) Florian Palm
  7. * Copyright 2015-2016 (c) Sten Grüner
  8. * Copyright 2015-2016 (c) Chris Iatrou
  9. * Copyright 2015 (c) LEvertz
  10. * Copyright 2015-2016 (c) Oleksiy Vasylyev
  11. * Copyright 2016 (c) Julian Grothoff
  12. * Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
  13. * Copyright 2016 (c) Lorenz Haas
  14. * Copyright 2017 (c) frax2222
  15. * Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
  16. * Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
  17. */
  18. #include "ua_types.h"
  19. #include "ua_server_internal.h"
  20. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  21. #include "ua_pubsub_ns0.h"
  22. #endif
  23. #ifdef UA_ENABLE_SUBSCRIPTIONS
  24. #include "ua_subscription.h"
  25. #endif
  26. #ifdef UA_ENABLE_VALGRIND_INTERACTIVE
  27. #include <valgrind/memcheck.h>
  28. #endif
  29. /**********************/
  30. /* Namespace Handling */
  31. /**********************/
  32. UA_UInt16 addNamespace(UA_Server *server, const UA_String name) {
  33. /* Check if the namespace already exists in the server's namespace array */
  34. for(UA_UInt16 i = 0; i < server->namespacesSize; ++i) {
  35. if(UA_String_equal(&name, &server->namespaces[i]))
  36. return i;
  37. }
  38. /* Make the array bigger */
  39. UA_String *newNS = (UA_String*)UA_realloc(server->namespaces,
  40. sizeof(UA_String) * (server->namespacesSize + 1));
  41. if(!newNS)
  42. return 0;
  43. server->namespaces = newNS;
  44. /* Copy the namespace string */
  45. UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]);
  46. if(retval != UA_STATUSCODE_GOOD)
  47. return 0;
  48. /* Announce the change (otherwise, the array appears unchanged) */
  49. ++server->namespacesSize;
  50. return (UA_UInt16)(server->namespacesSize - 1);
  51. }
  52. UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
  53. /* Override const attribute to get string (dirty hack) */
  54. UA_String nameString;
  55. nameString.length = strlen(name);
  56. nameString.data = (UA_Byte*)(uintptr_t)name;
  57. return addNamespace(server, nameString);
  58. }
  59. UA_ServerConfig*
  60. UA_Server_getConfig(UA_Server *server)
  61. {
  62. if(!server)
  63. return NULL;
  64. else
  65. return &server->config;
  66. }
  67. UA_StatusCode
  68. UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
  69. size_t* foundIndex) {
  70. for(size_t idx = 0; idx < server->namespacesSize; idx++)
  71. {
  72. if(UA_String_equal(&server->namespaces[idx], &namespaceUri) == true)
  73. {
  74. (*foundIndex) = idx;
  75. return UA_STATUSCODE_GOOD;
  76. }
  77. }
  78. return UA_STATUSCODE_BADNOTFOUND;
  79. }
  80. UA_StatusCode
  81. UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
  82. UA_NodeIteratorCallback callback, void *handle) {
  83. const UA_Node *parent =
  84. server->config.nodestore.getNode(server->config.nodestore.context,
  85. &parentNodeId);
  86. if(!parent)
  87. return UA_STATUSCODE_BADNODEIDINVALID;
  88. /* TODO: We need to do an ugly copy of the references array since users may
  89. * delete references from within the callback. In single-threaded mode this
  90. * changes the same node we point at here. In multi-threaded mode, this
  91. * creates a new copy as nodes are truly immutable.
  92. * The callback could remove a node via the regular public API.
  93. * This can remove a member of the nodes-array we iterate over...
  94. * */
  95. UA_Node *parentCopy = UA_Node_copy_alloc(parent);
  96. if(!parentCopy) {
  97. server->config.nodestore.releaseNode(server->config.nodestore.context, parent);
  98. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  99. }
  100. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  101. for(size_t i = parentCopy->referencesSize; i > 0; --i) {
  102. UA_NodeReferenceKind *ref = &parentCopy->references[i - 1];
  103. for(size_t j = 0; j<ref->targetIdsSize; j++) {
  104. retval = callback(ref->targetIds[j].nodeId, ref->isInverse,
  105. ref->referenceTypeId, handle);
  106. if(retval != UA_STATUSCODE_GOOD)
  107. goto cleanup;
  108. }
  109. }
  110. cleanup:
  111. UA_Node_deleteMembers(parentCopy);
  112. UA_free(parentCopy);
  113. server->config.nodestore.releaseNode(server->config.nodestore.context, parent);
  114. return retval;
  115. }
  116. /********************/
  117. /* Server Lifecycle */
  118. /********************/
  119. /* The server needs to be stopped before it can be deleted */
  120. void UA_Server_delete(UA_Server *server) {
  121. /* Delete all internal data */
  122. UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
  123. UA_SessionManager_deleteMembers(&server->sessionManager);
  124. UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
  125. #ifdef UA_ENABLE_SUBSCRIPTIONS
  126. UA_MonitoredItem *mon, *mon_tmp;
  127. LIST_FOREACH_SAFE(mon, &server->localMonitoredItems, listEntry, mon_tmp) {
  128. LIST_REMOVE(mon, listEntry);
  129. UA_MonitoredItem_delete(server, mon);
  130. }
  131. #endif
  132. #ifdef UA_ENABLE_PUBSUB
  133. UA_PubSubManager_delete(server, &server->pubSubManager);
  134. #endif
  135. #ifdef UA_ENABLE_DISCOVERY
  136. registeredServer_list_entry *rs, *rs_tmp;
  137. LIST_FOREACH_SAFE(rs, &server->registeredServers, pointers, rs_tmp) {
  138. LIST_REMOVE(rs, pointers);
  139. UA_RegisteredServer_deleteMembers(&rs->registeredServer);
  140. UA_free(rs);
  141. }
  142. periodicServerRegisterCallback_entry *ps, *ps_tmp;
  143. LIST_FOREACH_SAFE(ps, &server->periodicServerRegisterCallbacks, pointers, ps_tmp) {
  144. LIST_REMOVE(ps, pointers);
  145. UA_free(ps->callback);
  146. UA_free(ps);
  147. }
  148. # ifdef UA_ENABLE_DISCOVERY_MULTICAST
  149. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
  150. destroyMulticastDiscoveryServer(server);
  151. serverOnNetwork_list_entry *son, *son_tmp;
  152. LIST_FOREACH_SAFE(son, &server->serverOnNetwork, pointers, son_tmp) {
  153. LIST_REMOVE(son, pointers);
  154. UA_ServerOnNetwork_deleteMembers(&son->serverOnNetwork);
  155. if(son->pathTmp)
  156. UA_free(son->pathTmp);
  157. UA_free(son);
  158. }
  159. for(size_t i = 0; i < SERVER_ON_NETWORK_HASH_PRIME; i++) {
  160. serverOnNetwork_hash_entry* currHash = server->serverOnNetworkHash[i];
  161. while(currHash) {
  162. serverOnNetwork_hash_entry* nextHash = currHash->next;
  163. UA_free(currHash);
  164. currHash = nextHash;
  165. }
  166. }
  167. mdnsHostnameToIp_list_entry *mhi, *mhi_tmp;
  168. LIST_FOREACH_SAFE(mhi, &server->mdnsHostnameToIp, pointers, mhi_tmp) {
  169. LIST_REMOVE(mhi, pointers);
  170. UA_String_deleteMembers(&mhi->mdnsHostname);
  171. UA_free(mhi);
  172. }
  173. for(size_t i = 0; i < MDNS_HOSTNAME_TO_IP_HASH_PRIME; i++) {
  174. mdnsHostnameToIp_hash_entry* currHash = server->mdnsHostnameToIpHash[i];
  175. while(currHash) {
  176. mdnsHostnameToIp_hash_entry* nextHash = currHash->next;
  177. UA_free(currHash);
  178. currHash = nextHash;
  179. }
  180. }
  181. # endif
  182. #endif
  183. /* Clean up the Admin Session */
  184. UA_Session_deleteMembersCleanup(&server->adminSession, server);
  185. /* Clean up the work queue */
  186. UA_WorkQueue_cleanup(&server->workQueue);
  187. /* Delete the timed work */
  188. UA_Timer_deleteMembers(&server->timer);
  189. /* Delete the server itself */
  190. UA_free(server);
  191. }
  192. /* Recurring cleanup. Removing unused and timed-out channels and sessions */
  193. static void
  194. UA_Server_cleanup(UA_Server *server, void *_) {
  195. UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic();
  196. UA_SessionManager_cleanupTimedOut(&server->sessionManager, nowMonotonic);
  197. UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, nowMonotonic);
  198. #ifdef UA_ENABLE_DISCOVERY
  199. UA_Discovery_cleanupTimedOut(server, nowMonotonic);
  200. #endif
  201. }
  202. /********************/
  203. /* Server Lifecycle */
  204. /********************/
  205. UA_Server *
  206. UA_Server_new(const UA_ServerConfig *config) {
  207. /* A config is required */
  208. if(!config)
  209. return NULL;
  210. /* Allocate the server */
  211. UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));
  212. if(!server)
  213. return NULL;
  214. /* Set the config */
  215. server->config = *config;
  216. /* Init start time to zero, the actual start time will be sampled in
  217. * UA_Server_run_startup() */
  218. server->startTime = 0;
  219. /* Set a seed for non-cyptographic randomness */
  220. #ifndef UA_ENABLE_DETERMINISTIC_RNG
  221. UA_random_seed((UA_UInt64)UA_DateTime_now());
  222. #endif
  223. /* Initialize the handling of repeated callbacks */
  224. UA_Timer_init(&server->timer);
  225. UA_WorkQueue_init(&server->workQueue);
  226. /* Initialize the adminSession */
  227. UA_Session_init(&server->adminSession);
  228. server->adminSession.sessionId.identifierType = UA_NODEIDTYPE_GUID;
  229. server->adminSession.sessionId.identifier.guid.data1 = 1;
  230. server->adminSession.validTill = UA_INT64_MAX;
  231. /* Create Namespaces 0 and 1 */
  232. server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
  233. server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
  234. UA_String_copy(&server->config.applicationDescription.applicationUri, &server->namespaces[1]);
  235. server->namespacesSize = 2;
  236. /* Initialized SecureChannel and Session managers */
  237. UA_SecureChannelManager_init(&server->secureChannelManager, server);
  238. UA_SessionManager_init(&server->sessionManager, server);
  239. /* Add a regular callback for cleanup and maintenance */
  240. UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_Server_cleanup, NULL,
  241. 10000, NULL);
  242. /* Initialized discovery database */
  243. #ifdef UA_ENABLE_DISCOVERY
  244. LIST_INIT(&server->registeredServers);
  245. server->registeredServersSize = 0;
  246. LIST_INIT(&server->periodicServerRegisterCallbacks);
  247. server->registerServerCallback = NULL;
  248. server->registerServerCallbackData = NULL;
  249. #endif
  250. /* Initialize multicast discovery */
  251. #if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
  252. server->mdnsDaemon = NULL;
  253. server->mdnsSocket = UA_INVALID_SOCKET;
  254. server->mdnsMainSrvAdded = UA_FALSE;
  255. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
  256. initMulticastDiscoveryServer(server);
  257. LIST_INIT(&server->serverOnNetwork);
  258. server->serverOnNetworkSize = 0;
  259. server->serverOnNetworkRecordIdCounter = 0;
  260. server->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
  261. memset(server->serverOnNetworkHash, 0,
  262. sizeof(struct serverOnNetwork_hash_entry*) * SERVER_ON_NETWORK_HASH_PRIME);
  263. LIST_INIT(&server->mdnsHostnameToIp);
  264. memset(server->mdnsHostnameToIpHash, 0,
  265. sizeof(struct mdnsHostnameToIp_hash_entry*) * MDNS_HOSTNAME_TO_IP_HASH_PRIME);
  266. server->serverOnNetworkCallback = NULL;
  267. server->serverOnNetworkCallbackData = NULL;
  268. #endif
  269. /* Initialize namespace 0*/
  270. UA_StatusCode retVal = UA_Server_initNS0(server);
  271. if(retVal != UA_STATUSCODE_GOOD) {
  272. UA_LOG_ERROR(config->logger, UA_LOGCATEGORY_SERVER,
  273. "Namespace 0 could not be bootstrapped with error %s. "
  274. "Shutting down the server.",
  275. UA_StatusCode_name(retVal));
  276. UA_Server_delete(server);
  277. return NULL;
  278. }
  279. /* Build PubSub information model */
  280. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  281. UA_Server_initPubSubNS0(server);
  282. #endif
  283. return server;
  284. }
  285. /*****************/
  286. /* Repeated Jobs */
  287. /*****************/
  288. UA_StatusCode
  289. UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
  290. void *data, UA_UInt32 interval,
  291. UA_UInt64 *callbackId) {
  292. return UA_Timer_addRepeatedCallback(&server->timer,
  293. (UA_ApplicationCallback)callback,
  294. server, data, interval, callbackId);
  295. }
  296. UA_StatusCode
  297. UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
  298. UA_UInt32 interval) {
  299. return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval);
  300. }
  301. UA_StatusCode
  302. UA_Server_removeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId) {
  303. return UA_Timer_removeRepeatedCallback(&server->timer, callbackId);
  304. }
  305. UA_StatusCode UA_EXPORT
  306. UA_Server_updateCertificate(UA_Server *server,
  307. const UA_ByteString *oldCertificate,
  308. const UA_ByteString *newCertificate,
  309. const UA_ByteString *newPrivateKey,
  310. UA_Boolean closeSessions,
  311. UA_Boolean closeSecureChannels) {
  312. if (server == NULL || oldCertificate == NULL
  313. || newCertificate == NULL || newPrivateKey == NULL) {
  314. return UA_STATUSCODE_BADINTERNALERROR;
  315. }
  316. if (closeSessions) {
  317. UA_SessionManager *sm = &server->sessionManager;
  318. session_list_entry *current;
  319. LIST_FOREACH(current, &sm->sessions, pointers) {
  320. if (UA_ByteString_equal(oldCertificate,
  321. &current->session.header.channel->securityPolicy->localCertificate)) {
  322. UA_SessionManager_removeSession(sm, &current->session.header.authenticationToken);
  323. }
  324. }
  325. }
  326. if (closeSecureChannels) {
  327. UA_SecureChannelManager *cm = &server->secureChannelManager;
  328. channel_entry *entry;
  329. TAILQ_FOREACH(entry, &cm->channels, pointers) {
  330. if(UA_ByteString_equal(&entry->channel.securityPolicy->localCertificate, oldCertificate)){
  331. UA_SecureChannelManager_close(cm, entry->channel.securityToken.channelId);
  332. }
  333. }
  334. }
  335. size_t index = 0;
  336. while (index < server->config.endpointsSize) {
  337. UA_EndpointDescription *ed = &server->config.endpoints[index].endpointDescription;
  338. if (UA_ByteString_equal(&ed->serverCertificate, oldCertificate)) {
  339. UA_String_deleteMembers(&ed->serverCertificate);
  340. UA_String_copy(newCertificate, &ed->serverCertificate);
  341. UA_SecurityPolicy *sp = &server->config.endpoints[index].securityPolicy;
  342. sp->updateCertificateAndPrivateKey(sp, *newCertificate, *newPrivateKey);
  343. }
  344. index++;
  345. }
  346. return UA_STATUSCODE_GOOD;
  347. }
  348. /********************/
  349. /* Main Server Loop */
  350. /********************/
  351. #define UA_MAXTIMEOUT 50 /* Max timeout in ms between main-loop iterations */
  352. /* Start: Spin up the workers and the network layer and sample the server's
  353. * start time.
  354. * Iterate: Process repeated callbacks and events in the network layer. This
  355. * part can be driven from an external main-loop in an event-driven
  356. * single-threaded architecture.
  357. * Stop: Stop workers, finish all callbacks, stop the network layer, clean up */
  358. UA_StatusCode
  359. UA_Server_run_startup(UA_Server *server) {
  360. UA_Variant var;
  361. UA_StatusCode result = UA_STATUSCODE_GOOD;
  362. /* At least one endpoint has to be configured */
  363. if(server->config.endpointsSize == 0) {
  364. UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
  365. "There has to be at least one endpoint.");
  366. }
  367. /* Sample the start time and set it to the Server object */
  368. server->startTime = UA_DateTime_now();
  369. UA_Variant_init(&var);
  370. UA_Variant_setScalar(&var, &server->startTime, &UA_TYPES[UA_TYPES_DATETIME]);
  371. UA_Server_writeValue(server,
  372. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
  373. var);
  374. /* Start the networklayers */
  375. for(size_t i = 0; i < server->config.networkLayersSize; ++i) {
  376. UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
  377. result |= nl->start(nl, &server->config.customHostname);
  378. }
  379. /* Spin up the worker threads */
  380. #ifdef UA_ENABLE_MULTITHREADING
  381. UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
  382. "Spinning up %u worker thread(s)", server->config.nThreads);
  383. UA_WorkQueue_start(&server->workQueue, server->config.nThreads);
  384. #endif
  385. /* Start the multicast discovery server */
  386. #ifdef UA_ENABLE_DISCOVERY_MULTICAST
  387. if(server->config.applicationDescription.applicationType ==
  388. UA_APPLICATIONTYPE_DISCOVERYSERVER)
  389. startMulticastDiscoveryServer(server);
  390. #endif
  391. return result;
  392. }
  393. static void
  394. serverExecuteRepeatedCallback(UA_Server *server, UA_ApplicationCallback cb,
  395. void *callbackApplication, void *data) {
  396. #ifndef UA_ENABLE_MULTITHREADING
  397. cb(callbackApplication, data);
  398. #else
  399. UA_WorkQueue_enqueue(&server->workQueue, cb, callbackApplication, data);
  400. #endif
  401. }
  402. UA_UInt16
  403. UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) {
  404. /* Process repeated work */
  405. UA_DateTime now = UA_DateTime_nowMonotonic();
  406. UA_DateTime nextRepeated = UA_Timer_process(&server->timer, now,
  407. (UA_TimerExecutionCallback)serverExecuteRepeatedCallback, server);
  408. UA_DateTime latest = now + (UA_MAXTIMEOUT * UA_DATETIME_MSEC);
  409. if(nextRepeated > latest)
  410. nextRepeated = latest;
  411. UA_UInt16 timeout = 0;
  412. /* round always to upper value to avoid timeout to be set to 0
  413. * if(nextRepeated - now) < (UA_DATETIME_MSEC/2) */
  414. if(waitInternal)
  415. timeout = (UA_UInt16)(((nextRepeated - now) + (UA_DATETIME_MSEC - 1)) / UA_DATETIME_MSEC);
  416. /* Listen on the networklayer */
  417. for(size_t i = 0; i < server->config.networkLayersSize; ++i) {
  418. UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
  419. nl->listen(nl, server, timeout);
  420. }
  421. #if defined(UA_ENABLE_DISCOVERY_MULTICAST) && !defined(UA_ENABLE_MULTITHREADING)
  422. if(server->config.applicationDescription.applicationType ==
  423. UA_APPLICATIONTYPE_DISCOVERYSERVER) {
  424. // TODO multicastNextRepeat does not consider new input data (requests)
  425. // on the socket. It will be handled on the next call. if needed, we
  426. // need to use select with timeout on the multicast socket
  427. // server->mdnsSocket (see example in mdnsd library) on higher level.
  428. UA_DateTime multicastNextRepeat = 0;
  429. UA_StatusCode hasNext =
  430. iterateMulticastDiscoveryServer(server, &multicastNextRepeat, UA_TRUE);
  431. if(hasNext == UA_STATUSCODE_GOOD && multicastNextRepeat < nextRepeated)
  432. nextRepeated = multicastNextRepeat;
  433. }
  434. #endif
  435. #ifndef UA_ENABLE_MULTITHREADING
  436. UA_WorkQueue_manuallyProcessDelayed(&server->workQueue);
  437. #endif
  438. now = UA_DateTime_nowMonotonic();
  439. timeout = 0;
  440. if(nextRepeated > now)
  441. timeout = (UA_UInt16)((nextRepeated - now) / UA_DATETIME_MSEC);
  442. return timeout;
  443. }
  444. UA_StatusCode
  445. UA_Server_run_shutdown(UA_Server *server) {
  446. /* Stop the netowrk layer */
  447. for(size_t i = 0; i < server->config.networkLayersSize; ++i) {
  448. UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
  449. nl->stop(nl, server);
  450. }
  451. #ifdef UA_ENABLE_MULTITHREADING
  452. /* Shut down the workers */
  453. UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
  454. "Shutting down %u worker thread(s)",
  455. (UA_UInt32)server->workQueue.workersSize);
  456. UA_WorkQueue_stop(&server->workQueue);
  457. #endif
  458. #ifdef UA_ENABLE_DISCOVERY_MULTICAST
  459. /* Stop multicast discovery */
  460. if(server->config.applicationDescription.applicationType ==
  461. UA_APPLICATIONTYPE_DISCOVERYSERVER)
  462. stopMulticastDiscoveryServer(server);
  463. #endif
  464. /* Execute all delayed callbacks */
  465. UA_WorkQueue_cleanup(&server->workQueue);
  466. return UA_STATUSCODE_GOOD;
  467. }
  468. UA_StatusCode
  469. UA_Server_run(UA_Server *server, volatile UA_Boolean *running) {
  470. UA_StatusCode retval = UA_Server_run_startup(server);
  471. if(retval != UA_STATUSCODE_GOOD)
  472. return retval;
  473. #ifdef UA_ENABLE_VALGRIND_INTERACTIVE
  474. size_t loopCount = 0;
  475. #endif
  476. while(*running) {
  477. #ifdef UA_ENABLE_VALGRIND_INTERACTIVE
  478. if(loopCount == 0) {
  479. VALGRIND_DO_LEAK_CHECK;
  480. }
  481. ++loopCount;
  482. loopCount %= UA_VALGRIND_INTERACTIVE_INTERVAL;
  483. #endif
  484. UA_Server_run_iterate(server, true);
  485. }
  486. return UA_Server_run_shutdown(server);
  487. }