ua_server.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. #include "ua_types.h"
  5. #include "ua_server_internal.h"
  6. #ifdef UA_ENABLE_GENERATE_NAMESPACE0
  7. #include "ua_namespaceinit_generated.h"
  8. #endif
  9. /**********************/
  10. /* Namespace Handling */
  11. /**********************/
  12. UA_UInt16 addNamespace(UA_Server *server, const UA_String name) {
  13. /* Check if the namespace already exists in the server's namespace array */
  14. for(UA_UInt16 i = 0; i < server->namespacesSize; ++i) {
  15. if(UA_String_equal(&name, &server->namespaces[i]))
  16. return i;
  17. }
  18. /* Make the array bigger */
  19. UA_String *newNS = (UA_String*)UA_realloc(server->namespaces,
  20. sizeof(UA_String) * (server->namespacesSize + 1));
  21. if(!newNS)
  22. return 0;
  23. server->namespaces = newNS;
  24. /* Copy the namespace string */
  25. UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]);
  26. if(retval != UA_STATUSCODE_GOOD)
  27. return 0;
  28. /* Announce the change (otherwise, the array appears unchanged) */
  29. ++server->namespacesSize;
  30. return (UA_UInt16)(server->namespacesSize - 1);
  31. }
  32. UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
  33. /* Override const attribute to get string (dirty hack) */
  34. UA_String nameString;
  35. nameString.length = strlen(name);
  36. nameString.data = (UA_Byte*)(uintptr_t)name;
  37. return addNamespace(server, nameString);
  38. }
  39. UA_StatusCode
  40. UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
  41. UA_NodeIteratorCallback callback, void *handle) {
  42. const UA_Node *parent =
  43. server->config.nodestore.getNode(server->config.nodestore.context,
  44. &parentNodeId);
  45. if(!parent)
  46. return UA_STATUSCODE_BADNODEIDINVALID;
  47. /* TODO: We need to do an ugly copy of the references array since users may
  48. * delete references from within the callback. In single-threaded mode this
  49. * changes the same node we point at here. In multi-threaded mode, this
  50. * creates a new copy as nodes are truly immutable. */
  51. UA_ReferenceNode *refs = NULL;
  52. size_t refssize = parent->referencesSize;
  53. UA_StatusCode retval = UA_Array_copy(parent->references, parent->referencesSize,
  54. (void**)&refs, &UA_TYPES[UA_TYPES_REFERENCENODE]);
  55. if(retval != UA_STATUSCODE_GOOD) {
  56. server->config.nodestore.releaseNode(server->config.nodestore.context, parent);
  57. return retval;
  58. }
  59. for(size_t i = parent->referencesSize; i > 0; --i) {
  60. UA_ReferenceNode *ref = &refs[i - 1];
  61. retval |= callback(ref->targetId.nodeId, ref->isInverse,
  62. ref->referenceTypeId, handle);
  63. }
  64. server->config.nodestore.releaseNode(server->config.nodestore.context, parent);
  65. UA_Array_delete(refs, refssize, &UA_TYPES[UA_TYPES_REFERENCENODE]);
  66. return retval;
  67. }
  68. /********************/
  69. /* Server Lifecycle */
  70. /********************/
  71. /* The server needs to be stopped before it can be deleted */
  72. void UA_Server_delete(UA_Server *server) {
  73. /* Delete all internal data */
  74. UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
  75. UA_SessionManager_deleteMembers(&server->sessionManager);
  76. UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
  77. #ifdef UA_ENABLE_DISCOVERY
  78. registeredServer_list_entry *rs, *rs_tmp;
  79. LIST_FOREACH_SAFE(rs, &server->registeredServers, pointers, rs_tmp) {
  80. LIST_REMOVE(rs, pointers);
  81. UA_RegisteredServer_deleteMembers(&rs->registeredServer);
  82. UA_free(rs);
  83. }
  84. periodicServerRegisterCallback_entry *ps, *ps_tmp;
  85. LIST_FOREACH_SAFE(ps, &server->periodicServerRegisterCallbacks, pointers, ps_tmp) {
  86. LIST_REMOVE(ps, pointers);
  87. UA_free(ps->callback);
  88. UA_free(ps);
  89. }
  90. # ifdef UA_ENABLE_DISCOVERY_MULTICAST
  91. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
  92. destroyMulticastDiscoveryServer(server);
  93. serverOnNetwork_list_entry *son, *son_tmp;
  94. LIST_FOREACH_SAFE(son, &server->serverOnNetwork, pointers, son_tmp) {
  95. LIST_REMOVE(son, pointers);
  96. UA_ServerOnNetwork_deleteMembers(&son->serverOnNetwork);
  97. if(son->pathTmp)
  98. UA_free(son->pathTmp);
  99. UA_free(son);
  100. }
  101. for(size_t i = 0; i < SERVER_ON_NETWORK_HASH_PRIME; i++) {
  102. serverOnNetwork_hash_entry* currHash = server->serverOnNetworkHash[i];
  103. while(currHash) {
  104. serverOnNetwork_hash_entry* nextHash = currHash->next;
  105. UA_free(currHash);
  106. currHash = nextHash;
  107. }
  108. }
  109. # endif
  110. #endif
  111. #ifdef UA_ENABLE_MULTITHREADING
  112. pthread_cond_destroy(&server->dispatchQueue_condition);
  113. pthread_mutex_destroy(&server->dispatchQueue_mutex);
  114. #endif
  115. /* Delete the timed work */
  116. UA_Timer_deleteMembers(&server->timer);
  117. /* Delete the server itself */
  118. UA_free(server);
  119. }
  120. /* Recurring cleanup. Removing unused and timed-out channels and sessions */
  121. static void
  122. UA_Server_cleanup(UA_Server *server, void *_) {
  123. UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic();
  124. UA_SessionManager_cleanupTimedOut(&server->sessionManager, nowMonotonic);
  125. UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, nowMonotonic);
  126. #ifdef UA_ENABLE_DISCOVERY
  127. UA_Discovery_cleanupTimedOut(server, nowMonotonic);
  128. #endif
  129. }
  130. /********************/
  131. /* Server Lifecycle */
  132. /********************/
  133. UA_Server *
  134. UA_Server_new(const UA_ServerConfig *config) {
  135. UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));
  136. if(!server)
  137. return NULL;
  138. if(config->endpointsSize == 0) {
  139. UA_LOG_FATAL(config->logger,
  140. UA_LOGCATEGORY_SERVER,
  141. "There has to be at least one endpoint.");
  142. UA_free(server);
  143. return NULL;
  144. }
  145. server->config = *config;
  146. server->startTime = UA_DateTime_now();
  147. /* Set a seed for non-cyptographic randomness */
  148. #ifndef UA_ENABLE_DETERMINISTIC_RNG
  149. UA_random_seed((UA_UInt64)UA_DateTime_now());
  150. #endif
  151. /* Initialize the handling of repeated callbacks */
  152. UA_Timer_init(&server->timer);
  153. /* Initialized the linked list for delayed callbacks */
  154. #ifndef UA_ENABLE_MULTITHREADING
  155. SLIST_INIT(&server->delayedCallbacks);
  156. #endif
  157. /* Initialized the dispatch queue for worker threads */
  158. #ifdef UA_ENABLE_MULTITHREADING
  159. cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
  160. #endif
  161. /* Create Namespaces 0 and 1 */
  162. server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
  163. server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
  164. UA_String_copy(&server->config.applicationDescription.applicationUri, &server->namespaces[1]);
  165. server->namespacesSize = 2;
  166. /* Initialized SecureChannel and Session managers */
  167. UA_SecureChannelManager_init(&server->secureChannelManager, server);
  168. UA_SessionManager_init(&server->sessionManager, server);
  169. /* Add a regular callback for cleanup and maintenance */
  170. UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_Server_cleanup, NULL,
  171. 10000, NULL);
  172. /* Initialized discovery database */
  173. #ifdef UA_ENABLE_DISCOVERY
  174. LIST_INIT(&server->registeredServers);
  175. server->registeredServersSize = 0;
  176. LIST_INIT(&server->periodicServerRegisterCallbacks);
  177. server->registerServerCallback = NULL;
  178. server->registerServerCallbackData = NULL;
  179. #endif
  180. /* Initialize multicast discovery */
  181. #if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
  182. server->mdnsDaemon = NULL;
  183. server->mdnsSocket = 0;
  184. server->mdnsMainSrvAdded = UA_FALSE;
  185. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
  186. initMulticastDiscoveryServer(server);
  187. LIST_INIT(&server->serverOnNetwork);
  188. server->serverOnNetworkSize = 0;
  189. server->serverOnNetworkRecordIdCounter = 0;
  190. server->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
  191. memset(server->serverOnNetworkHash, 0,
  192. sizeof(struct serverOnNetwork_hash_entry*) * SERVER_ON_NETWORK_HASH_PRIME);
  193. server->serverOnNetworkCallback = NULL;
  194. server->serverOnNetworkCallbackData = NULL;
  195. #endif
  196. /* Initialize namespace 0*/
  197. UA_StatusCode retVal = UA_Server_initNS0(server);
  198. if (retVal != UA_STATUSCODE_GOOD) {
  199. UA_LOG_ERROR(config->logger,
  200. UA_LOGCATEGORY_SERVER,
  201. "Initialization of Namespace 0 failed with %s. See previous outputs for any error messages.",
  202. UA_StatusCode_name(retVal));
  203. UA_Server_delete(server);
  204. return NULL;
  205. }
  206. return server;
  207. }
  208. /*****************/
  209. /* Repeated Jobs */
  210. /*****************/
  211. UA_StatusCode
  212. UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
  213. void *data, UA_UInt32 interval,
  214. UA_UInt64 *callbackId) {
  215. return UA_Timer_addRepeatedCallback(&server->timer, (UA_TimerCallback)callback,
  216. data, interval, callbackId);
  217. }
  218. UA_StatusCode
  219. UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
  220. UA_UInt32 interval) {
  221. return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId, interval);
  222. }
  223. UA_StatusCode
  224. UA_Server_removeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId) {
  225. return UA_Timer_removeRepeatedCallback(&server->timer, callbackId);
  226. }