ua_server.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  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. /**********************/
  27. /* Namespace Handling */
  28. /**********************/
  29. UA_UInt16 addNamespace(UA_Server *server, const UA_String name) {
  30. /* Check if the namespace already exists in the server's namespace array */
  31. for(UA_UInt16 i = 0; i < server->namespacesSize; ++i) {
  32. if(UA_String_equal(&name, &server->namespaces[i]))
  33. return i;
  34. }
  35. /* Make the array bigger */
  36. UA_String *newNS = (UA_String*)UA_realloc(server->namespaces,
  37. sizeof(UA_String) * (server->namespacesSize + 1));
  38. if(!newNS)
  39. return 0;
  40. server->namespaces = newNS;
  41. /* Copy the namespace string */
  42. UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]);
  43. if(retval != UA_STATUSCODE_GOOD)
  44. return 0;
  45. /* Announce the change (otherwise, the array appears unchanged) */
  46. ++server->namespacesSize;
  47. return (UA_UInt16)(server->namespacesSize - 1);
  48. }
  49. UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
  50. /* Override const attribute to get string (dirty hack) */
  51. UA_String nameString;
  52. nameString.length = strlen(name);
  53. nameString.data = (UA_Byte*)(uintptr_t)name;
  54. return addNamespace(server, nameString);
  55. }
  56. UA_StatusCode
  57. UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
  58. size_t* foundIndex) {
  59. for(size_t idx = 0; idx < server->namespacesSize; idx++)
  60. {
  61. if(UA_String_equal(&server->namespaces[idx], &namespaceUri) == true)
  62. {
  63. (*foundIndex) = idx;
  64. return UA_STATUSCODE_GOOD;
  65. }
  66. }
  67. return UA_STATUSCODE_BADNOTFOUND;
  68. }
  69. UA_StatusCode
  70. UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
  71. UA_NodeIteratorCallback callback, void *handle) {
  72. const UA_Node *parent =
  73. server->config.nodestore.getNode(server->config.nodestore.context,
  74. &parentNodeId);
  75. if(!parent)
  76. return UA_STATUSCODE_BADNODEIDINVALID;
  77. /* TODO: We need to do an ugly copy of the references array since users may
  78. * delete references from within the callback. In single-threaded mode this
  79. * changes the same node we point at here. In multi-threaded mode, this
  80. * creates a new copy as nodes are truly immutable.
  81. * The callback could remove a node via the regular public API.
  82. * This can remove a member of the nodes-array we iterate over...
  83. * */
  84. UA_Node *parentCopy = UA_Node_copy_alloc(parent);
  85. if(!parentCopy) {
  86. server->config.nodestore.releaseNode(server->config.nodestore.context, parent);
  87. return UA_STATUSCODE_BADUNEXPECTEDERROR;
  88. }
  89. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  90. for(size_t i = parentCopy->referencesSize; i > 0; --i) {
  91. UA_NodeReferenceKind *ref = &parentCopy->references[i - 1];
  92. for(size_t j = 0; j<ref->targetIdsSize; j++)
  93. retval |= callback(ref->targetIds[j].nodeId, ref->isInverse,
  94. ref->referenceTypeId, handle);
  95. }
  96. UA_Node_deleteMembers(parentCopy);
  97. UA_free(parentCopy);
  98. server->config.nodestore.releaseNode(server->config.nodestore.context, parent);
  99. return retval;
  100. }
  101. /********************/
  102. /* Server Lifecycle */
  103. /********************/
  104. /* The server needs to be stopped before it can be deleted */
  105. void UA_Server_delete(UA_Server *server) {
  106. /* Delete all internal data */
  107. UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
  108. UA_SessionManager_deleteMembers(&server->sessionManager);
  109. UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
  110. #ifdef UA_ENABLE_SUBSCRIPTIONS
  111. UA_MonitoredItem *mon, *mon_tmp;
  112. LIST_FOREACH_SAFE(mon, &server->localMonitoredItems, listEntry, mon_tmp) {
  113. LIST_REMOVE(mon, listEntry);
  114. UA_MonitoredItem_delete(server, mon);
  115. }
  116. #endif
  117. #ifdef UA_ENABLE_PUBSUB
  118. UA_PubSubManager_delete(server, &server->pubSubManager);
  119. #endif
  120. #ifdef UA_ENABLE_DISCOVERY
  121. registeredServer_list_entry *rs, *rs_tmp;
  122. LIST_FOREACH_SAFE(rs, &server->registeredServers, pointers, rs_tmp) {
  123. LIST_REMOVE(rs, pointers);
  124. UA_RegisteredServer_deleteMembers(&rs->registeredServer);
  125. UA_free(rs);
  126. }
  127. periodicServerRegisterCallback_entry *ps, *ps_tmp;
  128. LIST_FOREACH_SAFE(ps, &server->periodicServerRegisterCallbacks, pointers, ps_tmp) {
  129. LIST_REMOVE(ps, pointers);
  130. UA_free(ps->callback);
  131. UA_free(ps);
  132. }
  133. # ifdef UA_ENABLE_DISCOVERY_MULTICAST
  134. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
  135. destroyMulticastDiscoveryServer(server);
  136. serverOnNetwork_list_entry *son, *son_tmp;
  137. LIST_FOREACH_SAFE(son, &server->serverOnNetwork, pointers, son_tmp) {
  138. LIST_REMOVE(son, pointers);
  139. UA_ServerOnNetwork_deleteMembers(&son->serverOnNetwork);
  140. if(son->pathTmp)
  141. UA_free(son->pathTmp);
  142. UA_free(son);
  143. }
  144. for(size_t i = 0; i < SERVER_ON_NETWORK_HASH_PRIME; i++) {
  145. serverOnNetwork_hash_entry* currHash = server->serverOnNetworkHash[i];
  146. while(currHash) {
  147. serverOnNetwork_hash_entry* nextHash = currHash->next;
  148. UA_free(currHash);
  149. currHash = nextHash;
  150. }
  151. }
  152. # endif
  153. #endif
  154. #ifdef UA_ENABLE_MULTITHREADING
  155. /* Process new delayed callbacks from the cleanup */
  156. UA_Server_cleanupDispatchQueue(server);
  157. pthread_mutex_destroy(&server->dispatchQueue_accessMutex);
  158. pthread_cond_destroy(&server->dispatchQueue_condition);
  159. pthread_mutex_destroy(&server->dispatchQueue_conditionMutex);
  160. #else
  161. /* Process new delayed callbacks from the cleanup */
  162. UA_Server_cleanupDelayedCallbacks(server);
  163. #endif
  164. /* Delete the timed work */
  165. UA_Timer_deleteMembers(&server->timer);
  166. /* Delete the server itself */
  167. UA_free(server);
  168. }
  169. /* Recurring cleanup. Removing unused and timed-out channels and sessions */
  170. static void
  171. UA_Server_cleanup(UA_Server *server, void *_) {
  172. UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic();
  173. UA_SessionManager_cleanupTimedOut(&server->sessionManager, nowMonotonic);
  174. UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, nowMonotonic);
  175. #ifdef UA_ENABLE_DISCOVERY
  176. UA_Discovery_cleanupTimedOut(server, nowMonotonic);
  177. #endif
  178. }
  179. /********************/
  180. /* Server Lifecycle */
  181. /********************/
  182. UA_Server *
  183. UA_Server_new(const UA_ServerConfig *config) {
  184. /* A config is required */
  185. if(!config)
  186. return NULL;
  187. /* At least one endpoint has to be configured */
  188. if(config->endpointsSize == 0) {
  189. UA_LOG_FATAL(config->logger, UA_LOGCATEGORY_SERVER,
  190. "There has to be at least one endpoint.");
  191. return NULL;
  192. }
  193. /* Allocate the server */
  194. UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));
  195. if(!server)
  196. return NULL;
  197. /* Set the config */
  198. server->config = *config;
  199. /* Init start time to zero, the actual start time will be sampled in
  200. * UA_Server_run_startup() */
  201. server->startTime = 0;
  202. /* Set a seed for non-cyptographic randomness */
  203. #ifndef UA_ENABLE_DETERMINISTIC_RNG
  204. UA_random_seed((UA_UInt64)UA_DateTime_now());
  205. #endif
  206. /* Initialize the handling of repeated callbacks */
  207. UA_Timer_init(&server->timer);
  208. /* Initialized the linked list for delayed callbacks */
  209. #ifndef UA_ENABLE_MULTITHREADING
  210. SLIST_INIT(&server->delayedCallbacks);
  211. #endif
  212. /* Initialized the dispatch queue for worker threads */
  213. #ifdef UA_ENABLE_MULTITHREADING
  214. SIMPLEQ_INIT(&server->dispatchQueue);
  215. #endif
  216. /* Create Namespaces 0 and 1 */
  217. server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
  218. server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
  219. UA_String_copy(&server->config.applicationDescription.applicationUri, &server->namespaces[1]);
  220. server->namespacesSize = 2;
  221. /* Initialized SecureChannel and Session managers */
  222. UA_SecureChannelManager_init(&server->secureChannelManager, server);
  223. UA_SessionManager_init(&server->sessionManager, server);
  224. /* Add a regular callback for cleanup and maintenance */
  225. UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_Server_cleanup, NULL,
  226. 10000, NULL);
  227. /* Initialized discovery database */
  228. #ifdef UA_ENABLE_DISCOVERY
  229. LIST_INIT(&server->registeredServers);
  230. server->registeredServersSize = 0;
  231. LIST_INIT(&server->periodicServerRegisterCallbacks);
  232. server->registerServerCallback = NULL;
  233. server->registerServerCallbackData = NULL;
  234. #endif
  235. /* Initialize multicast discovery */
  236. #if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
  237. server->mdnsDaemon = NULL;
  238. server->mdnsSocket = UA_INVALID_SOCKET;
  239. server->mdnsMainSrvAdded = UA_FALSE;
  240. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
  241. initMulticastDiscoveryServer(server);
  242. LIST_INIT(&server->serverOnNetwork);
  243. server->serverOnNetworkSize = 0;
  244. server->serverOnNetworkRecordIdCounter = 0;
  245. server->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
  246. memset(server->serverOnNetworkHash, 0,
  247. sizeof(struct serverOnNetwork_hash_entry*) * SERVER_ON_NETWORK_HASH_PRIME);
  248. server->serverOnNetworkCallback = NULL;
  249. server->serverOnNetworkCallbackData = NULL;
  250. #endif
  251. /* Initialize namespace 0*/
  252. UA_StatusCode retVal = UA_Server_initNS0(server);
  253. if(retVal != UA_STATUSCODE_GOOD) {
  254. UA_LOG_ERROR(config->logger, UA_LOGCATEGORY_SERVER,
  255. "Namespace 0 could not be bootstrapped with error %s. "
  256. "Shutting down the server.",
  257. UA_StatusCode_name(retVal));
  258. UA_Server_delete(server);
  259. return NULL;
  260. }
  261. /* Build PubSub information model */
  262. #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
  263. UA_Server_initPubSubNS0(server);
  264. #endif
  265. return server;
  266. }
  267. /*****************/
  268. /* Repeated Jobs */
  269. /*****************/
  270. UA_StatusCode
  271. UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
  272. void *data, UA_UInt32 interval,
  273. UA_UInt64 *callbackId) {
  274. return UA_Timer_addRepeatedCallback(&server->timer, (UA_TimerCallback)callback,
  275. data, interval, callbackId);
  276. }
  277. UA_StatusCode
  278. UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
  279. UA_UInt32 interval) {
  280. return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval);
  281. }
  282. UA_StatusCode
  283. UA_Server_removeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId) {
  284. return UA_Timer_removeRepeatedCallback(&server->timer, callbackId);
  285. }