ua_server.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. #include "ua_securechannel_manager.h"
  7. #include "ua_session_manager.h"
  8. #include "ua_util.h"
  9. #include "ua_services.h"
  10. #include "ua_nodeids.h"
  11. #ifdef UA_ENABLE_GENERATE_NAMESPACE0
  12. #include "ua_namespaceinit_generated.h"
  13. #endif
  14. #if defined(UA_ENABLE_MULTITHREADING) && !defined(NDEBUG)
  15. UA_THREAD_LOCAL bool rcu_locked = false;
  16. #endif
  17. /**********************/
  18. /* Namespace Handling */
  19. /**********************/
  20. UA_UInt16 addNamespace(UA_Server *server, const UA_String name) {
  21. /* Check if the namespace already exists in the server's namespace array */
  22. for(UA_UInt16 i = 0; i < server->namespacesSize; ++i) {
  23. if(UA_String_equal(&name, &server->namespaces[i]))
  24. return i;
  25. }
  26. /* Make the array bigger */
  27. UA_String *newNS = (UA_String*)UA_realloc(server->namespaces,
  28. sizeof(UA_String) * (server->namespacesSize + 1));
  29. if(!newNS)
  30. return 0;
  31. server->namespaces = newNS;
  32. /* Copy the namespace string */
  33. UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]);
  34. if(retval != UA_STATUSCODE_GOOD)
  35. return 0;
  36. /* Announce the change (otherwise, the array appears unchanged) */
  37. ++server->namespacesSize;
  38. return (UA_UInt16)(server->namespacesSize - 1);
  39. }
  40. UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
  41. /* Override const attribute to get string (dirty hack) */
  42. UA_String nameString;
  43. nameString.length = strlen(name);
  44. nameString.data = (UA_Byte*)(uintptr_t)name;
  45. return addNamespace(server, nameString);
  46. }
  47. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  48. static void
  49. UA_ExternalNamespace_init(UA_ExternalNamespace *ens) {
  50. ens->index = 0;
  51. UA_String_init(&ens->url);
  52. }
  53. static void
  54. UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
  55. UA_String_deleteMembers(&ens->url);
  56. ens->externalNodeStore.destroy(ens->externalNodeStore.ensHandle);
  57. }
  58. static void
  59. UA_Server_deleteExternalNamespaces(UA_Server *server) {
  60. for(UA_UInt32 i = 0; i < server->externalNamespacesSize; ++i)
  61. UA_ExternalNamespace_deleteMembers(&server->externalNamespaces[i]);
  62. if(server->externalNamespacesSize > 0) {
  63. UA_free(server->externalNamespaces);
  64. server->externalNamespaces = NULL;
  65. server->externalNamespacesSize = 0;
  66. }
  67. }
  68. UA_StatusCode UA_EXPORT
  69. UA_Server_addExternalNamespace(UA_Server *server, const UA_String *url,
  70. UA_ExternalNodeStore *nodeStore,
  71. UA_UInt16 *assignedNamespaceIndex) {
  72. if(!nodeStore)
  73. return UA_STATUSCODE_BADARGUMENTSMISSING;
  74. size_t size = server->externalNamespacesSize;
  75. server->externalNamespaces =
  76. UA_realloc(server->externalNamespaces, sizeof(UA_ExternalNamespace) * (size + 1));
  77. server->externalNamespaces[size].externalNodeStore = *nodeStore;
  78. server->externalNamespaces[size].index = (UA_UInt16)server->namespacesSize;
  79. *assignedNamespaceIndex = (UA_UInt16)server->namespacesSize;
  80. UA_String_copy(url, &server->externalNamespaces[size].url);
  81. ++server->externalNamespacesSize;
  82. UA_Server_addNamespace(server, urlString);
  83. return UA_STATUSCODE_GOOD;
  84. }
  85. #endif /* UA_ENABLE_EXTERNAL_NAMESPACES*/
  86. UA_StatusCode
  87. UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
  88. UA_NodeIteratorCallback callback, void *handle) {
  89. UA_RCU_LOCK();
  90. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
  91. if(!parent) {
  92. UA_RCU_UNLOCK();
  93. return UA_STATUSCODE_BADNODEIDINVALID;
  94. }
  95. /* TODO: We need to do an ugly copy of the references array since users may
  96. * delete references from within the callback. In single-threaded mode this
  97. * changes the same node we point at here. In multi-threaded mode, this
  98. * creates a new copy as nodes are truly immutable. */
  99. UA_ReferenceNode *refs = NULL;
  100. size_t refssize = parent->referencesSize;
  101. UA_StatusCode retval = UA_Array_copy(parent->references, parent->referencesSize,
  102. (void**)&refs, &UA_TYPES[UA_TYPES_REFERENCENODE]);
  103. if(retval != UA_STATUSCODE_GOOD) {
  104. UA_RCU_UNLOCK();
  105. return retval;
  106. }
  107. for(size_t i = parent->referencesSize; i > 0; --i) {
  108. UA_ReferenceNode *ref = &refs[i-1];
  109. retval |= callback(ref->targetId.nodeId, ref->isInverse,
  110. ref->referenceTypeId, handle);
  111. }
  112. UA_RCU_UNLOCK();
  113. UA_Array_delete(refs, refssize, &UA_TYPES[UA_TYPES_REFERENCENODE]);
  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 the timed work
  122. UA_RepeatedJobsList_deleteMembers(&server->repeatedJobs);
  123. // Delete all internal data
  124. UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
  125. UA_SessionManager_deleteMembers(&server->sessionManager);
  126. UA_RCU_LOCK();
  127. UA_NodeStore_delete(server->nodestore);
  128. UA_RCU_UNLOCK();
  129. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  130. UA_Server_deleteExternalNamespaces(server);
  131. #endif
  132. UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
  133. UA_Array_delete(server->endpointDescriptions, server->endpointDescriptionsSize,
  134. &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
  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. if(server->periodicServerRegisterJob)
  143. UA_free(server->periodicServerRegisterJob);
  144. # ifdef UA_ENABLE_DISCOVERY_MULTICAST
  145. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER)
  146. UA_Discovery_multicastDestroy(server);
  147. serverOnNetwork_list_entry *son, *son_tmp;
  148. LIST_FOREACH_SAFE(son, &server->serverOnNetwork, pointers, son_tmp) {
  149. LIST_REMOVE(son, pointers);
  150. UA_ServerOnNetwork_deleteMembers(&son->serverOnNetwork);
  151. if(son->pathTmp)
  152. UA_free(son->pathTmp);
  153. UA_free(son);
  154. }
  155. for(size_t i = 0; i < SERVER_ON_NETWORK_HASH_PRIME; i++) {
  156. serverOnNetwork_hash_entry* currHash = server->serverOnNetworkHash[i];
  157. while(currHash) {
  158. serverOnNetwork_hash_entry* nextHash = currHash->next;
  159. UA_free(currHash);
  160. currHash = nextHash;
  161. }
  162. }
  163. # endif
  164. #endif
  165. #ifdef UA_ENABLE_MULTITHREADING
  166. pthread_cond_destroy(&server->dispatchQueue_condition);
  167. pthread_mutex_destroy(&server->dispatchQueue_mutex);
  168. #endif
  169. UA_free(server);
  170. }
  171. /* Recurring cleanup. Removing unused and timed-out channels and sessions */
  172. static void UA_Server_cleanup(UA_Server *server, void *_) {
  173. UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic();
  174. UA_SessionManager_cleanupTimedOut(&server->sessionManager, nowMonotonic);
  175. UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, nowMonotonic);
  176. #ifdef UA_ENABLE_DISCOVERY
  177. UA_Discovery_cleanupTimedOut(server, nowMonotonic);
  178. #endif
  179. }
  180. /* Create endpoints w/o endpointurl. It is added from the networklayers at startup */
  181. static void
  182. addEndpointDefinitions(UA_Server *server) {
  183. server->endpointDescriptions =
  184. (UA_EndpointDescription*)UA_Array_new(server->config.networkLayersSize,
  185. &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
  186. server->endpointDescriptionsSize = server->config.networkLayersSize;
  187. for(size_t i = 0; i < server->config.networkLayersSize; ++i) {
  188. UA_EndpointDescription *endpoint = &server->endpointDescriptions[i];
  189. endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
  190. endpoint->securityPolicyUri =
  191. UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
  192. endpoint->transportProfileUri =
  193. UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
  194. size_t policies = 0;
  195. if(server->config.accessControl.enableAnonymousLogin)
  196. ++policies;
  197. if(server->config.accessControl.enableUsernamePasswordLogin)
  198. ++policies;
  199. endpoint->userIdentityTokensSize = policies;
  200. endpoint->userIdentityTokens =
  201. (UA_UserTokenPolicy*)UA_Array_new(policies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
  202. size_t currentIndex = 0;
  203. if(server->config.accessControl.enableAnonymousLogin) {
  204. UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
  205. endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
  206. endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY);
  207. ++currentIndex;
  208. }
  209. if(server->config.accessControl.enableUsernamePasswordLogin) {
  210. UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
  211. endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_USERNAME;
  212. endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
  213. }
  214. /* The standard says "the HostName specified in the Server Certificate is the
  215. same as the HostName contained in the endpointUrl provided in the
  216. EndpointDescription */
  217. UA_String_copy(&server->config.serverCertificate, &endpoint->serverCertificate);
  218. UA_ApplicationDescription_copy(&server->config.applicationDescription, &endpoint->server);
  219. /* copy the discovery url only once the networlayer has been started */
  220. // UA_String_copy(&server->config.networkLayers[i].discoveryUrl, &endpoint->endpointUrl);
  221. }
  222. }
  223. UA_Server *
  224. UA_Server_new(const UA_ServerConfig config) {
  225. UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));
  226. if(!server)
  227. return NULL;
  228. server->config = config;
  229. server->startTime = UA_DateTime_now();
  230. server->nodestore = UA_NodeStore_new();
  231. /* Set a seed for non-cyptographic randomness */
  232. #ifndef UA_ENABLE_DETERMINISTIC_RNG
  233. UA_random_seed((UA_UInt64)UA_DateTime_now());
  234. #endif
  235. /* Initialize the handling of repeated jobs */
  236. #ifdef UA_ENABLE_MULTITHREADING
  237. UA_RepeatedJobsList_init(&server->repeatedJobs,
  238. (UA_RepeatedJobsListProcessCallback)UA_Server_dispatchJob,
  239. server);
  240. #else
  241. UA_RepeatedJobsList_init(&server->repeatedJobs,
  242. (UA_RepeatedJobsListProcessCallback)UA_Server_processJob,
  243. server);
  244. #endif
  245. /* Initialized the linked list for delayed callbacks */
  246. #ifndef UA_ENABLE_MULTITHREADING
  247. SLIST_INIT(&server->delayedCallbacks);
  248. #endif
  249. /* Initialized the dispatch queue for worker threads */
  250. #ifdef UA_ENABLE_MULTITHREADING
  251. rcu_init();
  252. cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
  253. cds_lfs_init(&server->mainLoopJobs);
  254. #endif
  255. /* Create Namespaces 0 and 1 */
  256. server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
  257. server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
  258. UA_String_copy(&server->config.applicationDescription.applicationUri, &server->namespaces[1]);
  259. server->namespacesSize = 2;
  260. /* Create Endpoint Definitions */
  261. addEndpointDefinitions(server);
  262. /* Initialized SecureChannel and Session managers */
  263. UA_SecureChannelManager_init(&server->secureChannelManager, server);
  264. UA_SessionManager_init(&server->sessionManager, server);
  265. /* Add a regular job for cleanup and maintenance */
  266. UA_Job cleanup;
  267. cleanup.type = UA_JOBTYPE_METHODCALL;
  268. cleanup.job.methodCall.data = NULL;
  269. cleanup.job.methodCall.method = UA_Server_cleanup;
  270. UA_Server_addRepeatedJob(server, cleanup, 10000, NULL);
  271. /* Initialized discovery database */
  272. #ifdef UA_ENABLE_DISCOVERY
  273. LIST_INIT(&server->registeredServers);
  274. server->registeredServersSize = 0;
  275. server->periodicServerRegisterJob = NULL;
  276. server->registerServerCallback = NULL;
  277. server->registerServerCallbackData = NULL;
  278. #endif
  279. /* Initialize multicast discovery */
  280. #if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
  281. server->mdnsDaemon = NULL;
  282. server->mdnsSocket = 0;
  283. server->mdnsMainSrvAdded = UA_FALSE;
  284. if(server->config.applicationDescription.applicationType == UA_APPLICATIONTYPE_DISCOVERYSERVER) {
  285. UA_Discovery_multicastInit(server);
  286. }
  287. LIST_INIT(&server->serverOnNetwork);
  288. server->serverOnNetworkSize = 0;
  289. server->serverOnNetworkRecordIdCounter = 0;
  290. server->serverOnNetworkRecordIdLastReset = UA_DateTime_now();
  291. memset(server->serverOnNetworkHash, 0,
  292. sizeof(struct serverOnNetwork_hash_entry*) * SERVER_ON_NETWORK_HASH_PRIME);
  293. server->serverOnNetworkCallback = NULL;
  294. server->serverOnNetworkCallbackData = NULL;
  295. #endif
  296. /* Initialize Namespace 0 */
  297. #ifndef UA_ENABLE_GENERATE_NAMESPACE0
  298. UA_Server_createNS0(server);
  299. #else
  300. ua_namespaceinit_generated(server);
  301. #endif
  302. return server;
  303. }
  304. /*****************/
  305. /* Repeated Jobs */
  306. /*****************/
  307. UA_StatusCode
  308. UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
  309. UA_UInt32 interval, UA_Guid *jobId) {
  310. return UA_RepeatedJobsList_addRepeatedJob(&server->repeatedJobs, job, interval, jobId);
  311. }
  312. UA_StatusCode
  313. UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId) {
  314. return UA_RepeatedJobsList_removeRepeatedJob(&server->repeatedJobs, jobId);
  315. }