ua_server.c 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378
  1. #include "ua_types.h"
  2. #include "ua_server_internal.h"
  3. #include "ua_securechannel_manager.h"
  4. #include "ua_session_manager.h"
  5. #include "ua_util.h"
  6. #include "ua_services.h"
  7. #include "ua_nodeids.h"
  8. #ifdef UA_ENABLE_DISCOVERY
  9. #include "ua_client.h"
  10. #include "ua_config_standard.h"
  11. #endif
  12. #ifdef UA_ENABLE_GENERATE_NAMESPACE0
  13. #include "ua_namespaceinit_generated.h"
  14. #endif
  15. #ifdef UA_ENABLE_SUBSCRIPTIONS
  16. #include "ua_subscription.h"
  17. #endif
  18. #if defined(UA_ENABLE_MULTITHREADING) && !defined(NDEBUG)
  19. UA_THREAD_LOCAL bool rcu_locked = false;
  20. #endif
  21. #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
  22. UA_THREAD_LOCAL UA_Session* methodCallSession = NULL;
  23. #endif
  24. static const UA_NodeId nodeIdHasSubType = {
  25. .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  26. .identifier.numeric = UA_NS0ID_HASSUBTYPE};
  27. static const UA_NodeId nodeIdHasTypeDefinition = {
  28. .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  29. .identifier.numeric = UA_NS0ID_HASTYPEDEFINITION};
  30. static const UA_NodeId nodeIdHasComponent = {
  31. .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  32. .identifier.numeric = UA_NS0ID_HASCOMPONENT};
  33. static const UA_NodeId nodeIdHasProperty = {
  34. .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  35. .identifier.numeric = UA_NS0ID_HASPROPERTY};
  36. static const UA_NodeId nodeIdOrganizes = {
  37. .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  38. .identifier.numeric = UA_NS0ID_ORGANIZES};
  39. static const UA_NodeId nodeIdFolderType = {
  40. .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  41. .identifier.numeric = UA_NS0ID_FOLDERTYPE};
  42. static const UA_ExpandedNodeId expandedNodeIdBaseDataVariabletype = {
  43. .nodeId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  44. .identifier.numeric = UA_NS0ID_BASEDATAVARIABLETYPE},
  45. .namespaceUri = {.length = 0, .data = NULL}, .serverIndex = 0};
  46. #ifndef UA_ENABLE_GENERATE_NAMESPACE0
  47. static const UA_NodeId nodeIdNonHierarchicalReferences = {
  48. .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
  49. .identifier.numeric = UA_NS0ID_NONHIERARCHICALREFERENCES};
  50. #endif
  51. /**********************/
  52. /* Namespace Handling */
  53. /**********************/
  54. UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
  55. /* Override const attribute to get string (dirty hack) */
  56. const UA_String nameString = (UA_String){.length = strlen(name),
  57. .data = (UA_Byte*)(uintptr_t)name};
  58. /* Check if the namespace already exists in the server's namespace array */
  59. for(UA_UInt16 i=0;i<server->namespacesSize;i++) {
  60. if(UA_String_equal(&nameString, &server->namespaces[i]))
  61. return i;
  62. }
  63. /* Add a new namespace to the namsepace array */
  64. server->namespaces = UA_realloc(server->namespaces,
  65. sizeof(UA_String) * (server->namespacesSize + 1));
  66. UA_String_copy(&nameString, &server->namespaces[server->namespacesSize]);
  67. server->namespacesSize++;
  68. return (UA_UInt16)(server->namespacesSize - 1);
  69. }
  70. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  71. static void UA_ExternalNamespace_init(UA_ExternalNamespace *ens) {
  72. ens->index = 0;
  73. UA_String_init(&ens->url);
  74. }
  75. static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
  76. UA_String_deleteMembers(&ens->url);
  77. ens->externalNodeStore.destroy(ens->externalNodeStore.ensHandle);
  78. }
  79. static void UA_Server_deleteExternalNamespaces(UA_Server *server) {
  80. for(UA_UInt32 i = 0; i < server->externalNamespacesSize; i++)
  81. UA_ExternalNamespace_deleteMembers(&server->externalNamespaces[i]);
  82. if(server->externalNamespacesSize > 0) {
  83. UA_free(server->externalNamespaces);
  84. server->externalNamespaces = NULL;
  85. server->externalNamespacesSize = 0;
  86. }
  87. }
  88. UA_StatusCode UA_EXPORT
  89. UA_Server_addExternalNamespace(UA_Server *server, const UA_String *url,
  90. UA_ExternalNodeStore *nodeStore,
  91. UA_UInt16 *assignedNamespaceIndex) {
  92. if(!nodeStore)
  93. return UA_STATUSCODE_BADARGUMENTSMISSING;
  94. char urlString[256];
  95. if(url.length >= 256)
  96. return UA_STATUSCODE_BADINTERNALERROR;
  97. memcpy(urlString, url.data, url.length);
  98. urlString[url.length] = 0;
  99. size_t size = server->externalNamespacesSize;
  100. server->externalNamespaces =
  101. UA_realloc(server->externalNamespaces, sizeof(UA_ExternalNamespace) * (size + 1));
  102. server->externalNamespaces[size].externalNodeStore = *nodeStore;
  103. server->externalNamespaces[size].index = (UA_UInt16)server->namespacesSize;
  104. *assignedNamespaceIndex = (UA_UInt16)server->namespacesSize;
  105. UA_String_copy(url, &server->externalNamespaces[size].url);
  106. server->externalNamespacesSize++;
  107. addNamespaceInternal(server, urlString);
  108. return UA_STATUSCODE_GOOD;
  109. }
  110. #endif /* UA_ENABLE_EXTERNAL_NAMESPACES*/
  111. UA_StatusCode
  112. UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
  113. UA_NodeIteratorCallback callback, void *handle) {
  114. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  115. UA_RCU_LOCK();
  116. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
  117. if(!parent) {
  118. UA_RCU_UNLOCK();
  119. return UA_STATUSCODE_BADNODEIDINVALID;
  120. }
  121. for(size_t i = 0; i < parent->referencesSize; i++) {
  122. UA_ReferenceNode *ref = &parent->references[i];
  123. retval |= callback(ref->targetId.nodeId, ref->isInverse,
  124. ref->referenceTypeId, handle);
  125. }
  126. UA_RCU_UNLOCK();
  127. return retval;
  128. }
  129. static UA_StatusCode
  130. addReferenceInternal(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
  131. const UA_ExpandedNodeId targetId, UA_Boolean isForward) {
  132. UA_AddReferencesItem item;
  133. UA_AddReferencesItem_init(&item);
  134. item.sourceNodeId = sourceId;
  135. item.referenceTypeId = refTypeId;
  136. item.isForward = isForward;
  137. item.targetNodeId = targetId;
  138. UA_RCU_LOCK();
  139. UA_StatusCode retval = Service_AddReferences_single(server, &adminSession, &item);
  140. UA_RCU_UNLOCK();
  141. return retval;
  142. }
  143. static UA_AddNodesResult
  144. addNodeInternal(UA_Server *server, UA_Node *node, const UA_NodeId parentNodeId,
  145. const UA_NodeId referenceTypeId) {
  146. UA_AddNodesResult res;
  147. UA_AddNodesResult_init(&res);
  148. UA_RCU_LOCK();
  149. Service_AddNodes_existing(server, &adminSession, node, &parentNodeId,
  150. &referenceTypeId, &UA_NODEID_NULL, NULL, &res);
  151. UA_RCU_UNLOCK();
  152. return res;
  153. }
  154. static UA_AddNodesResult
  155. addNodeInternalWithType(UA_Server *server, UA_Node *node, const UA_NodeId parentNodeId,
  156. const UA_NodeId referenceTypeId, const UA_NodeId typeIdentifier) {
  157. UA_AddNodesResult res;
  158. UA_AddNodesResult_init(&res);
  159. UA_RCU_LOCK();
  160. Service_AddNodes_existing(server, &adminSession, node, &parentNodeId,
  161. &referenceTypeId, &typeIdentifier, NULL, &res);
  162. UA_RCU_UNLOCK();
  163. return res;
  164. }
  165. /**********/
  166. /* Server */
  167. /**********/
  168. /* The server needs to be stopped before it can be deleted */
  169. void UA_Server_delete(UA_Server *server) {
  170. // Delete the timed work
  171. UA_Server_deleteAllRepeatedJobs(server);
  172. // Delete all internal data
  173. UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
  174. UA_SessionManager_deleteMembers(&server->sessionManager);
  175. UA_RCU_LOCK();
  176. UA_NodeStore_delete(server->nodestore);
  177. UA_RCU_UNLOCK();
  178. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  179. UA_Server_deleteExternalNamespaces(server);
  180. #endif
  181. UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
  182. UA_Array_delete(server->endpointDescriptions, server->endpointDescriptionsSize,
  183. &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
  184. #ifdef UA_ENABLE_DISCOVERY
  185. registeredServer_list_entry *current, *temp;
  186. LIST_FOREACH_SAFE(current, &server->registeredServers, pointers, temp) {
  187. LIST_REMOVE(current, pointers);
  188. UA_RegisteredServer_deleteMembers(&current->registeredServer);
  189. UA_free(current);
  190. }
  191. #endif
  192. #ifdef UA_ENABLE_MULTITHREADING
  193. pthread_cond_destroy(&server->dispatchQueue_condition);
  194. #endif
  195. UA_free(server);
  196. }
  197. /* Recurring cleanup. Removing unused and timed-out channels and sessions */
  198. static void UA_Server_cleanup(UA_Server *server, void *_) {
  199. UA_DateTime nowMonotonic = UA_DateTime_nowMonotonic();
  200. UA_SessionManager_cleanupTimedOut(&server->sessionManager, nowMonotonic);
  201. UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, nowMonotonic);
  202. #ifdef UA_ENABLE_DISCOVERY
  203. UA_Discovery_cleanupTimedOut(server, nowMonotonic);
  204. #endif
  205. }
  206. static UA_StatusCode
  207. readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
  208. const UA_NumericRange *range, UA_DataValue *value) {
  209. if(range) {
  210. value->hasStatus = true;
  211. value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
  212. return UA_STATUSCODE_GOOD;
  213. }
  214. UA_Server *server = (UA_Server*)handle;
  215. UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
  216. status->startTime = server->startTime;
  217. status->currentTime = UA_DateTime_now();
  218. status->state = UA_SERVERSTATE_RUNNING;
  219. status->secondsTillShutdown = 0;
  220. value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
  221. value->value.arrayLength = 0;
  222. value->value.data = status;
  223. value->value.arrayDimensionsSize = 0;
  224. value->value.arrayDimensions = NULL;
  225. value->hasValue = true;
  226. if(sourceTimeStamp) {
  227. value->hasSourceTimestamp = true;
  228. value->sourceTimestamp = UA_DateTime_now();
  229. }
  230. return UA_STATUSCODE_GOOD;
  231. }
  232. /** TODO: rework the code duplication in the getter methods **/
  233. static UA_StatusCode
  234. readServiceLevel(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
  235. const UA_NumericRange *range, UA_DataValue *value) {
  236. if(range) {
  237. value->hasStatus = true;
  238. value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
  239. return UA_STATUSCODE_GOOD;
  240. }
  241. value->value.type = &UA_TYPES[UA_TYPES_BYTE];
  242. value->value.arrayLength = 0;
  243. UA_Byte *byte = UA_Byte_new();
  244. *byte = 255;
  245. value->value.data = byte;
  246. value->value.arrayDimensionsSize = 0;
  247. value->value.arrayDimensions = NULL;
  248. value->hasValue = true;
  249. if(sourceTimeStamp) {
  250. value->hasSourceTimestamp = true;
  251. value->sourceTimestamp = UA_DateTime_now();
  252. }
  253. return UA_STATUSCODE_GOOD;
  254. }
  255. /** TODO: rework the code duplication in the getter methods **/
  256. static UA_StatusCode
  257. readAuditing(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
  258. const UA_NumericRange *range, UA_DataValue *value) {
  259. if(range) {
  260. value->hasStatus = true;
  261. value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
  262. return UA_STATUSCODE_GOOD;
  263. }
  264. value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  265. value->value.arrayLength = 0;
  266. UA_Boolean *boolean = UA_Boolean_new();
  267. *boolean = false;
  268. value->value.data = boolean;
  269. value->value.arrayDimensionsSize = 0;
  270. value->value.arrayDimensions = NULL;
  271. value->hasValue = true;
  272. if(sourceTimeStamp) {
  273. value->hasSourceTimestamp = true;
  274. value->sourceTimestamp = UA_DateTime_now();
  275. }
  276. return UA_STATUSCODE_GOOD;
  277. }
  278. static UA_StatusCode
  279. readNamespaces(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimestamp,
  280. const UA_NumericRange *range, UA_DataValue *value) {
  281. if(range) {
  282. value->hasStatus = true;
  283. value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
  284. return UA_STATUSCODE_GOOD;
  285. }
  286. UA_Server *server = (UA_Server*)handle;
  287. UA_StatusCode retval;
  288. retval = UA_Variant_setArrayCopy(&value->value, server->namespaces,
  289. server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
  290. if(retval != UA_STATUSCODE_GOOD)
  291. return retval;
  292. value->hasValue = true;
  293. if(sourceTimestamp) {
  294. value->hasSourceTimestamp = true;
  295. value->sourceTimestamp = UA_DateTime_now();
  296. }
  297. return UA_STATUSCODE_GOOD;
  298. }
  299. static UA_StatusCode
  300. readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
  301. const UA_NumericRange *range, UA_DataValue *value) {
  302. if(range) {
  303. value->hasStatus = true;
  304. value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
  305. return UA_STATUSCODE_GOOD;
  306. }
  307. UA_DateTime currentTime = UA_DateTime_now();
  308. UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, &currentTime, &UA_TYPES[UA_TYPES_DATETIME]);
  309. if(retval != UA_STATUSCODE_GOOD)
  310. return retval;
  311. value->hasValue = true;
  312. if(sourceTimeStamp) {
  313. value->hasSourceTimestamp = true;
  314. value->sourceTimestamp = currentTime;
  315. }
  316. return UA_STATUSCODE_GOOD;
  317. }
  318. static void copyNames(UA_Node *node, char *name) {
  319. node->browseName = UA_QUALIFIEDNAME_ALLOC(0, name);
  320. node->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", name);
  321. node->description = UA_LOCALIZEDTEXT_ALLOC("en_US", name);
  322. }
  323. static void
  324. addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid, UA_UInt32 parent) {
  325. UA_DataTypeNode *datatype = UA_NodeStore_newDataTypeNode();
  326. copyNames((UA_Node*)datatype, name);
  327. datatype->nodeId.identifier.numeric = datatypeid;
  328. addNodeInternal(server, (UA_Node*)datatype, UA_NODEID_NUMERIC(0, parent), nodeIdOrganizes);
  329. }
  330. static void
  331. addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid,
  332. UA_UInt32 parent, UA_UInt32 parentreference) {
  333. UA_ObjectTypeNode *objecttype = UA_NodeStore_newObjectTypeNode();
  334. copyNames((UA_Node*)objecttype, name);
  335. objecttype->nodeId.identifier.numeric = objecttypeid;
  336. addNodeInternal(server, (UA_Node*)objecttype, UA_NODEID_NUMERIC(0, parent),
  337. UA_NODEID_NUMERIC(0, parentreference));
  338. }
  339. static UA_VariableTypeNode*
  340. createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
  341. UA_UInt32 parent, UA_Boolean abstract) {
  342. UA_VariableTypeNode *variabletype = UA_NodeStore_newVariableTypeNode();
  343. copyNames((UA_Node*)variabletype, name);
  344. variabletype->nodeId.identifier.numeric = variabletypeid;
  345. variabletype->isAbstract = abstract;
  346. variabletype->value.variant.value.type = &UA_TYPES[UA_TYPES_VARIANT];
  347. return variabletype;
  348. }
  349. static void
  350. addVariableTypeNode_organized(UA_Server *server, char* name, UA_UInt32 variabletypeid,
  351. UA_UInt32 parent, UA_Boolean abstract) {
  352. UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
  353. addNodeInternal(server, (UA_Node*)variabletype, UA_NODEID_NUMERIC(0, parent), nodeIdOrganizes);
  354. }
  355. static void
  356. addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletypeid,
  357. UA_UInt32 parent, UA_Boolean abstract) {
  358. UA_VariableTypeNode *variabletype =
  359. createVariableTypeNode(server, name, variabletypeid, parent, abstract);
  360. addNodeInternal(server, (UA_Node*)variabletype, UA_NODEID_NUMERIC(0, parent), nodeIdHasSubType);
  361. }
  362. #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
  363. static UA_StatusCode
  364. GetMonitoredItems(void *handle, const UA_NodeId objectId, size_t inputSize,
  365. const UA_Variant *input, size_t outputSize, UA_Variant *output) {
  366. UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data));
  367. UA_Session* session = methodCallSession;
  368. UA_Subscription* subscription = UA_Session_getSubscriptionByID(session, subscriptionId);
  369. if(!subscription)
  370. return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
  371. UA_UInt32 sizeOfOutput = 0;
  372. UA_MonitoredItem* monitoredItem;
  373. LIST_FOREACH(monitoredItem, &subscription->MonitoredItems, listEntry) {
  374. sizeOfOutput++;
  375. }
  376. if(sizeOfOutput==0)
  377. return UA_STATUSCODE_GOOD;
  378. UA_UInt32* clientHandles = UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
  379. UA_UInt32* serverHandles = UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
  380. UA_UInt32 i = 0;
  381. LIST_FOREACH(monitoredItem, &subscription->MonitoredItems, listEntry) {
  382. clientHandles[i] = monitoredItem->clientHandle;
  383. serverHandles[i] = monitoredItem->itemId;
  384. i++;
  385. }
  386. UA_Variant_setArray(&output[0], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
  387. UA_Variant_setArray(&output[1], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
  388. return UA_STATUSCODE_GOOD;
  389. }
  390. #endif
  391. UA_Server * UA_Server_new(const UA_ServerConfig config) {
  392. UA_Server *server = UA_calloc(1, sizeof(UA_Server));
  393. if(!server)
  394. return NULL;
  395. server->config = config;
  396. server->nodestore = UA_NodeStore_new();
  397. LIST_INIT(&server->repeatedJobs);
  398. #ifdef UA_ENABLE_MULTITHREADING
  399. rcu_init();
  400. cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
  401. cds_lfs_init(&server->mainLoopJobs);
  402. #endif
  403. /* uncomment for non-reproducible server runs */
  404. //UA_random_seed(UA_DateTime_now());
  405. /* ns0 and ns1 */
  406. server->namespaces = UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
  407. server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
  408. UA_String_copy(&server->config.applicationDescription.applicationUri, &server->namespaces[1]);
  409. server->namespacesSize = 2;
  410. /* Create endpoints w/o endpointurl. It is added from the networklayers at startup */
  411. server->endpointDescriptions = UA_Array_new(server->config.networkLayersSize,
  412. &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
  413. server->endpointDescriptionsSize = server->config.networkLayersSize;
  414. for(size_t i = 0; i < server->config.networkLayersSize; i++) {
  415. UA_EndpointDescription *endpoint = &server->endpointDescriptions[i];
  416. endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
  417. endpoint->securityPolicyUri =
  418. UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
  419. endpoint->transportProfileUri =
  420. UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
  421. size_t policies = 0;
  422. if(server->config.enableAnonymousLogin)
  423. policies++;
  424. if(server->config.enableUsernamePasswordLogin)
  425. policies++;
  426. endpoint->userIdentityTokensSize = policies;
  427. endpoint->userIdentityTokens = UA_Array_new(policies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
  428. size_t currentIndex = 0;
  429. if(server->config.enableAnonymousLogin) {
  430. UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
  431. endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
  432. endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY);
  433. currentIndex++;
  434. }
  435. if(server->config.enableUsernamePasswordLogin) {
  436. UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
  437. endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_USERNAME;
  438. endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
  439. }
  440. /* The standard says "the HostName specified in the Server Certificate is the
  441. same as the HostName contained in the endpointUrl provided in the
  442. EndpointDescription */
  443. UA_String_copy(&server->config.serverCertificate, &endpoint->serverCertificate);
  444. UA_ApplicationDescription_copy(&server->config.applicationDescription, &endpoint->server);
  445. /* copy the discovery url only once the networlayer has been started */
  446. // UA_String_copy(&server->config.networkLayers[i].discoveryUrl, &endpoint->endpointUrl);
  447. }
  448. UA_SecureChannelManager_init(&server->secureChannelManager, server);
  449. UA_SessionManager_init(&server->sessionManager, server);
  450. UA_Job cleanup = {.type = UA_JOBTYPE_METHODCALL,
  451. .job.methodCall = {.method = UA_Server_cleanup, .data = NULL} };
  452. UA_Server_addRepeatedJob(server, cleanup, 10000, NULL);
  453. #ifdef UA_ENABLE_DISCOVERY
  454. // Discovery service
  455. LIST_INIT(&server->registeredServers);
  456. server->registeredServersSize = 0;
  457. #endif
  458. server->startTime = UA_DateTime_now();
  459. /**************/
  460. /* References */
  461. /**************/
  462. #ifndef UA_ENABLE_GENERATE_NAMESPACE0
  463. /* Bootstrap reference hierarchy by manually inserting "references" and "hassubtype" */
  464. UA_ReferenceTypeNode *references = UA_NodeStore_newReferenceTypeNode();
  465. copyNames((UA_Node*)references, "References");
  466. references->nodeId.identifier.numeric = UA_NS0ID_REFERENCES;
  467. references->isAbstract = true;
  468. references->symmetric = true;
  469. references->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "References");
  470. /* The reference to root is later inserted */
  471. UA_RCU_LOCK();
  472. UA_NodeStore_insert(server->nodestore, (UA_Node*)references);
  473. UA_RCU_UNLOCK();
  474. UA_ReferenceTypeNode *hassubtype = UA_NodeStore_newReferenceTypeNode();
  475. copyNames((UA_Node*)hassubtype, "HasSubtype");
  476. hassubtype->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "HasSupertype");
  477. hassubtype->nodeId.identifier.numeric = UA_NS0ID_HASSUBTYPE;
  478. hassubtype->isAbstract = false;
  479. hassubtype->symmetric = false;
  480. /* The reference to root is later inserted */
  481. UA_RCU_LOCK();
  482. UA_NodeStore_insert(server->nodestore, (UA_Node*)hassubtype);
  483. UA_RCU_UNLOCK();
  484. /* Continue adding reference types with normal "addnode" */
  485. UA_ReferenceTypeNode *hierarchicalreferences = UA_NodeStore_newReferenceTypeNode();
  486. copyNames((UA_Node*)hierarchicalreferences, "HierarchicalReferences");
  487. hierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_HIERARCHICALREFERENCES;
  488. hierarchicalreferences->isAbstract = true;
  489. hierarchicalreferences->symmetric = false;
  490. addNodeInternal(server, (UA_Node*)hierarchicalreferences,
  491. UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCES), nodeIdHasSubType);
  492. UA_ReferenceTypeNode *nonhierarchicalreferences = UA_NodeStore_newReferenceTypeNode();
  493. copyNames((UA_Node*)nonhierarchicalreferences, "NonHierarchicalReferences");
  494. nonhierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_NONHIERARCHICALREFERENCES;
  495. nonhierarchicalreferences->isAbstract = true;
  496. nonhierarchicalreferences->symmetric = false;
  497. addNodeInternal(server, (UA_Node*)nonhierarchicalreferences,
  498. UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCES), nodeIdHasSubType);
  499. UA_ReferenceTypeNode *haschild = UA_NodeStore_newReferenceTypeNode();
  500. copyNames((UA_Node*)haschild, "HasChild");
  501. haschild->nodeId.identifier.numeric = UA_NS0ID_HASCHILD;
  502. haschild->isAbstract = false;
  503. haschild->symmetric = false;
  504. addNodeInternal(server, (UA_Node*)haschild,
  505. UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), nodeIdHasSubType);
  506. UA_ReferenceTypeNode *organizes = UA_NodeStore_newReferenceTypeNode();
  507. copyNames((UA_Node*)organizes, "Organizes");
  508. organizes->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OrganizedBy");
  509. organizes->nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
  510. organizes->isAbstract = false;
  511. organizes->symmetric = false;
  512. addNodeInternal(server, (UA_Node*)organizes,
  513. UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), nodeIdHasSubType);
  514. UA_ReferenceTypeNode *haseventsource = UA_NodeStore_newReferenceTypeNode();
  515. copyNames((UA_Node*)haseventsource, "HasEventSource");
  516. haseventsource->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "EventSourceOf");
  517. haseventsource->nodeId.identifier.numeric = UA_NS0ID_HASEVENTSOURCE;
  518. haseventsource->isAbstract = false;
  519. haseventsource->symmetric = false;
  520. addNodeInternal(server, (UA_Node*)haseventsource,
  521. UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), nodeIdHasSubType);
  522. UA_ReferenceTypeNode *hasmodellingrule = UA_NodeStore_newReferenceTypeNode();
  523. copyNames((UA_Node*)hasmodellingrule, "HasModellingRule");
  524. hasmodellingrule->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "ModellingRuleOf");
  525. hasmodellingrule->nodeId.identifier.numeric = UA_NS0ID_HASMODELLINGRULE;
  526. hasmodellingrule->isAbstract = false;
  527. hasmodellingrule->symmetric = false;
  528. addNodeInternal(server, (UA_Node*)hasmodellingrule, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  529. UA_ReferenceTypeNode *hasencoding = UA_NodeStore_newReferenceTypeNode();
  530. copyNames((UA_Node*)hasencoding, "HasEncoding");
  531. hasencoding->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "EncodingOf");
  532. hasencoding->nodeId.identifier.numeric = UA_NS0ID_HASENCODING;
  533. hasencoding->isAbstract = false;
  534. hasencoding->symmetric = false;
  535. addNodeInternal(server, (UA_Node*)hasencoding, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  536. UA_ReferenceTypeNode *hasdescription = UA_NodeStore_newReferenceTypeNode();
  537. copyNames((UA_Node*)hasdescription, "HasDescription");
  538. hasdescription->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "DescriptionOf");
  539. hasdescription->nodeId.identifier.numeric = UA_NS0ID_HASDESCRIPTION;
  540. hasdescription->isAbstract = false;
  541. hasdescription->symmetric = false;
  542. addNodeInternal(server, (UA_Node*)hasdescription, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  543. UA_ReferenceTypeNode *hastypedefinition = UA_NodeStore_newReferenceTypeNode();
  544. copyNames((UA_Node*)hastypedefinition, "HasTypeDefinition");
  545. hastypedefinition->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "TypeDefinitionOf");
  546. hastypedefinition->nodeId.identifier.numeric = UA_NS0ID_HASTYPEDEFINITION;
  547. hastypedefinition->isAbstract = false;
  548. hastypedefinition->symmetric = false;
  549. addNodeInternal(server, (UA_Node*)hastypedefinition, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  550. UA_ReferenceTypeNode *generatesevent = UA_NodeStore_newReferenceTypeNode();
  551. copyNames((UA_Node*)generatesevent, "GeneratesEvent");
  552. generatesevent->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "GeneratedBy");
  553. generatesevent->nodeId.identifier.numeric = UA_NS0ID_GENERATESEVENT;
  554. generatesevent->isAbstract = false;
  555. generatesevent->symmetric = false;
  556. addNodeInternal(server, (UA_Node*)generatesevent, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  557. UA_ReferenceTypeNode *aggregates = UA_NodeStore_newReferenceTypeNode();
  558. copyNames((UA_Node*)aggregates, "Aggregates");
  559. // Todo: Is there an inverse name?
  560. aggregates->nodeId.identifier.numeric = UA_NS0ID_AGGREGATES;
  561. aggregates->isAbstract = false;
  562. aggregates->symmetric = false;
  563. addNodeInternal(server, (UA_Node*)aggregates, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType);
  564. // complete bootstrap of hassubtype
  565. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType,
  566. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), true);
  567. UA_ReferenceTypeNode *hasproperty = UA_NodeStore_newReferenceTypeNode();
  568. copyNames((UA_Node*)hasproperty, "HasProperty");
  569. hasproperty->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "PropertyOf");
  570. hasproperty->nodeId.identifier.numeric = UA_NS0ID_HASPROPERTY;
  571. hasproperty->isAbstract = false;
  572. hasproperty->symmetric = false;
  573. addNodeInternal(server, (UA_Node*)hasproperty,
  574. UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
  575. UA_ReferenceTypeNode *hascomponent = UA_NodeStore_newReferenceTypeNode();
  576. copyNames((UA_Node*)hascomponent, "HasComponent");
  577. hascomponent->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "ComponentOf");
  578. hascomponent->nodeId.identifier.numeric = UA_NS0ID_HASCOMPONENT;
  579. hascomponent->isAbstract = false;
  580. hascomponent->symmetric = false;
  581. addNodeInternal(server, (UA_Node*)hascomponent, UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
  582. UA_ReferenceTypeNode *hasnotifier = UA_NodeStore_newReferenceTypeNode();
  583. copyNames((UA_Node*)hasnotifier, "HasNotifier");
  584. hasnotifier->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "NotifierOf");
  585. hasnotifier->nodeId.identifier.numeric = UA_NS0ID_HASNOTIFIER;
  586. hasnotifier->isAbstract = false;
  587. hasnotifier->symmetric = false;
  588. addNodeInternal(server, (UA_Node*)hasnotifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE), nodeIdHasSubType);
  589. UA_ReferenceTypeNode *hasorderedcomponent = UA_NodeStore_newReferenceTypeNode();
  590. copyNames((UA_Node*)hasorderedcomponent, "HasOrderedComponent");
  591. hasorderedcomponent->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OrderedComponentOf");
  592. hasorderedcomponent->nodeId.identifier.numeric = UA_NS0ID_HASORDEREDCOMPONENT;
  593. hasorderedcomponent->isAbstract = false;
  594. hasorderedcomponent->symmetric = false;
  595. addNodeInternal(server, (UA_Node*)hasorderedcomponent, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), nodeIdHasSubType);
  596. UA_ReferenceTypeNode *hasmodelparent = UA_NodeStore_newReferenceTypeNode();
  597. copyNames((UA_Node*)hasmodelparent, "HasModelParent");
  598. hasmodelparent->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "ModelParentOf");
  599. hasmodelparent->nodeId.identifier.numeric = UA_NS0ID_HASMODELPARENT;
  600. hasmodelparent->isAbstract = false;
  601. hasmodelparent->symmetric = false;
  602. addNodeInternal(server, (UA_Node*)hasmodelparent, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  603. UA_ReferenceTypeNode *fromstate = UA_NodeStore_newReferenceTypeNode();
  604. copyNames((UA_Node*)fromstate, "FromState");
  605. fromstate->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "ToTransition");
  606. fromstate->nodeId.identifier.numeric = UA_NS0ID_FROMSTATE;
  607. fromstate->isAbstract = false;
  608. fromstate->symmetric = false;
  609. addNodeInternal(server, (UA_Node*)fromstate, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  610. UA_ReferenceTypeNode *tostate = UA_NodeStore_newReferenceTypeNode();
  611. copyNames((UA_Node*)tostate, "ToState");
  612. tostate->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "FromTransition");
  613. tostate->nodeId.identifier.numeric = UA_NS0ID_TOSTATE;
  614. tostate->isAbstract = false;
  615. tostate->symmetric = false;
  616. addNodeInternal(server, (UA_Node*)tostate, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  617. UA_ReferenceTypeNode *hascause = UA_NodeStore_newReferenceTypeNode();
  618. copyNames((UA_Node*)hascause, "HasCause");
  619. hascause->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "MayBeCausedBy");
  620. hascause->nodeId.identifier.numeric = UA_NS0ID_HASCAUSE;
  621. hascause->isAbstract = false;
  622. hascause->symmetric = false;
  623. addNodeInternal(server, (UA_Node*)hascause, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  624. UA_ReferenceTypeNode *haseffect = UA_NodeStore_newReferenceTypeNode();
  625. copyNames((UA_Node*)haseffect, "HasEffect");
  626. haseffect->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "MayBeEffectedBy");
  627. haseffect->nodeId.identifier.numeric = UA_NS0ID_HASEFFECT;
  628. haseffect->isAbstract = false;
  629. haseffect->symmetric = false;
  630. addNodeInternal(server, (UA_Node*)haseffect, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
  631. UA_ReferenceTypeNode *hashistoricalconfiguration = UA_NodeStore_newReferenceTypeNode();
  632. copyNames((UA_Node*)hashistoricalconfiguration, "HasHistoricalConfiguration");
  633. hashistoricalconfiguration->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "HistoricalConfigurationOf");
  634. hashistoricalconfiguration->nodeId.identifier.numeric = UA_NS0ID_HASHISTORICALCONFIGURATION;
  635. hashistoricalconfiguration->isAbstract = false;
  636. hashistoricalconfiguration->symmetric = false;
  637. addNodeInternal(server, (UA_Node*)hashistoricalconfiguration, UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
  638. /********************/
  639. /* Object Hierarchy */
  640. /********************/
  641. /* Bootstrap object hierarchy by manually inserting "root" and "baseobjecttype" */
  642. UA_ObjectNode *root = UA_NodeStore_newObjectNode();
  643. copyNames((UA_Node*)root, "Root");
  644. root->nodeId.identifier.numeric = UA_NS0ID_ROOTFOLDER;
  645. UA_ObjectTypeNode *baseobjtype = UA_NodeStore_newObjectTypeNode();
  646. copyNames((UA_Node*)baseobjtype, "BaseObjectType");
  647. baseobjtype->nodeId.identifier.numeric = UA_NS0ID_BASEOBJECTTYPE;
  648. UA_RCU_LOCK();
  649. UA_NodeStore_insert(server->nodestore, (UA_Node*)root);
  650. UA_NodeStore_insert(server->nodestore, (UA_Node*)baseobjtype);
  651. UA_RCU_UNLOCK();
  652. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER), nodeIdHasTypeDefinition,
  653. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), true);
  654. addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
  655. UA_ObjectNode *objects = UA_NodeStore_newObjectNode();
  656. copyNames((UA_Node*)objects, "Objects");
  657. objects->nodeId.identifier.numeric = UA_NS0ID_OBJECTSFOLDER;
  658. addNodeInternalWithType(server, (UA_Node*)objects, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
  659. nodeIdOrganizes, nodeIdFolderType);
  660. UA_ObjectNode *types = UA_NodeStore_newObjectNode();
  661. copyNames((UA_Node*)types, "Types");
  662. types->nodeId.identifier.numeric = UA_NS0ID_TYPESFOLDER;
  663. addNodeInternalWithType(server, (UA_Node*)types, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
  664. nodeIdOrganizes, nodeIdFolderType);
  665. UA_ObjectNode *views = UA_NodeStore_newObjectNode();
  666. copyNames((UA_Node*)views, "Views");
  667. views->nodeId.identifier.numeric = UA_NS0ID_VIEWSFOLDER;
  668. addNodeInternalWithType(server, (UA_Node*)views, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
  669. nodeIdOrganizes, nodeIdFolderType);
  670. UA_ObjectNode *referencetypes = UA_NodeStore_newObjectNode();
  671. copyNames((UA_Node*)referencetypes, "ReferenceTypes");
  672. referencetypes->nodeId.identifier.numeric = UA_NS0ID_REFERENCETYPESFOLDER;
  673. addNodeInternalWithType(server, (UA_Node*)referencetypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
  674. nodeIdOrganizes, nodeIdFolderType);
  675. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), nodeIdOrganizes,
  676. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES), true);
  677. /**********************/
  678. /* Basic Object Types */
  679. /**********************/
  680. UA_ObjectNode *objecttypes = UA_NodeStore_newObjectNode();
  681. copyNames((UA_Node*)objecttypes, "ObjectTypes");
  682. objecttypes->nodeId.identifier.numeric = UA_NS0ID_OBJECTTYPESFOLDER;
  683. addNodeInternalWithType(server, (UA_Node*)objecttypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
  684. nodeIdOrganizes, nodeIdFolderType);
  685. /* Link in the bootstrapped baseobjecttype */
  686. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTTYPESFOLDER), nodeIdOrganizes,
  687. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), true);
  688. addObjectTypeNode(server, "ServerType", UA_NS0ID_SERVERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
  689. addObjectTypeNode(server, "ServerDiagnosticsType", UA_NS0ID_SERVERDIAGNOSTICSTYPE,
  690. UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
  691. addObjectTypeNode(server, "ServerCapatilitiesType", UA_NS0ID_SERVERCAPABILITIESTYPE,
  692. UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
  693. addObjectTypeNode(server, "ServerStatusType", UA_NS0ID_SERVERSTATUSTYPE, UA_NS0ID_BASEOBJECTTYPE,
  694. UA_NS0ID_HASSUBTYPE);
  695. addObjectTypeNode(server, "BuildInfoType", UA_NS0ID_BUILDINFOTYPE, UA_NS0ID_BASEOBJECTTYPE,
  696. UA_NS0ID_HASSUBTYPE);
  697. /**************/
  698. /* Data Types */
  699. /**************/
  700. UA_ObjectNode *datatypes = UA_NodeStore_newObjectNode();
  701. copyNames((UA_Node*)datatypes, "DataTypes");
  702. datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
  703. addNodeInternalWithType(server, (UA_Node*)datatypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
  704. nodeIdOrganizes, nodeIdFolderType);
  705. addDataTypeNode(server, "BaseDataType", UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER);
  706. addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, UA_NS0ID_BASEDATATYPE);
  707. addDataTypeNode(server, "Number", UA_NS0ID_NUMBER, UA_NS0ID_BASEDATATYPE);
  708. addDataTypeNode(server, "Float", UA_NS0ID_FLOAT, UA_NS0ID_NUMBER);
  709. addDataTypeNode(server, "Double", UA_NS0ID_DOUBLE, UA_NS0ID_NUMBER);
  710. addDataTypeNode(server, "Integer", UA_NS0ID_INTEGER, UA_NS0ID_NUMBER);
  711. addDataTypeNode(server, "SByte", UA_NS0ID_SBYTE, UA_NS0ID_INTEGER);
  712. addDataTypeNode(server, "Int16", UA_NS0ID_INT16, UA_NS0ID_INTEGER);
  713. addDataTypeNode(server, "Int32", UA_NS0ID_INT32, UA_NS0ID_INTEGER);
  714. addDataTypeNode(server, "Int64", UA_NS0ID_INT64, UA_NS0ID_INTEGER);
  715. addDataTypeNode(server, "UInteger", UA_NS0ID_UINTEGER, UA_NS0ID_INTEGER);
  716. addDataTypeNode(server, "Byte", UA_NS0ID_BYTE, UA_NS0ID_UINTEGER);
  717. addDataTypeNode(server, "UInt16", UA_NS0ID_UINT16, UA_NS0ID_UINTEGER);
  718. addDataTypeNode(server, "UInt32", UA_NS0ID_UINT32, UA_NS0ID_UINTEGER);
  719. addDataTypeNode(server, "UInt64", UA_NS0ID_UINT64, UA_NS0ID_UINTEGER);
  720. addDataTypeNode(server, "String", UA_NS0ID_STRING, UA_NS0ID_BASEDATATYPE);
  721. addDataTypeNode(server, "DateTime", UA_NS0ID_DATETIME, UA_NS0ID_BASEDATATYPE);
  722. addDataTypeNode(server, "Guid", UA_NS0ID_GUID, UA_NS0ID_BASEDATATYPE);
  723. addDataTypeNode(server, "ByteString", UA_NS0ID_BYTESTRING, UA_NS0ID_BASEDATATYPE);
  724. addDataTypeNode(server, "XmlElement", UA_NS0ID_XMLELEMENT, UA_NS0ID_BASEDATATYPE);
  725. addDataTypeNode(server, "NodeId", UA_NS0ID_NODEID, UA_NS0ID_BASEDATATYPE);
  726. addDataTypeNode(server, "ExpandedNodeId", UA_NS0ID_EXPANDEDNODEID, UA_NS0ID_BASEDATATYPE);
  727. addDataTypeNode(server, "StatusCode", UA_NS0ID_STATUSCODE, UA_NS0ID_BASEDATATYPE);
  728. addDataTypeNode(server, "QualifiedName", UA_NS0ID_QUALIFIEDNAME, UA_NS0ID_BASEDATATYPE);
  729. addDataTypeNode(server, "LocalizedText", UA_NS0ID_LOCALIZEDTEXT, UA_NS0ID_BASEDATATYPE);
  730. addDataTypeNode(server, "Structure", UA_NS0ID_STRUCTURE, UA_NS0ID_BASEDATATYPE);
  731. addDataTypeNode(server, "ServerStatusDataType", UA_NS0ID_SERVERSTATUSDATATYPE, UA_NS0ID_STRUCTURE);
  732. addDataTypeNode(server, "BuildInfo", UA_NS0ID_BUILDINFO, UA_NS0ID_STRUCTURE);
  733. addDataTypeNode(server, "DataValue", UA_NS0ID_DATAVALUE, UA_NS0ID_BASEDATATYPE);
  734. addDataTypeNode(server, "DiagnosticInfo", UA_NS0ID_DIAGNOSTICINFO, UA_NS0ID_BASEDATATYPE);
  735. addDataTypeNode(server, "Enumeration", UA_NS0ID_ENUMERATION, UA_NS0ID_BASEDATATYPE);
  736. addDataTypeNode(server, "ServerState", UA_NS0ID_SERVERSTATE, UA_NS0ID_ENUMERATION);
  737. UA_ObjectNode *variabletypes = UA_NodeStore_newObjectNode();
  738. copyNames((UA_Node*)variabletypes, "VariableTypes");
  739. variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
  740. addNodeInternalWithType(server, (UA_Node*)variabletypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
  741. nodeIdOrganizes, nodeIdFolderType);
  742. addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE,
  743. UA_NS0ID_VARIABLETYPESFOLDER, true);
  744. addVariableTypeNode_subtype(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
  745. UA_NS0ID_BASEVARIABLETYPE, false);
  746. addVariableTypeNode_subtype(server, "PropertyType", UA_NS0ID_PROPERTYTYPE,
  747. UA_NS0ID_BASEVARIABLETYPE, false);
  748. /***************/
  749. /* Event Types */
  750. /***************/
  751. UA_ObjectNode *eventtypes = UA_NodeStore_newObjectNode();
  752. copyNames((UA_Node*)eventtypes, "EventTypes");
  753. eventtypes->nodeId.identifier.numeric = UA_NS0ID_EVENTTYPESFOLDER;
  754. addNodeInternalWithType(server, (UA_Node*)eventtypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
  755. nodeIdOrganizes, nodeIdFolderType);
  756. #endif
  757. #ifdef UA_ENABLE_GENERATE_NAMESPACE0
  758. /* load the generated namespace externally */
  759. ua_namespaceinit_generated(server);
  760. #endif
  761. /*********************/
  762. /* The Server Object */
  763. /*********************/
  764. UA_ObjectNode *servernode = UA_NodeStore_newObjectNode();
  765. copyNames((UA_Node*)servernode, "Server");
  766. servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
  767. addNodeInternalWithType(server, (UA_Node*)servernode, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
  768. nodeIdOrganizes, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE));
  769. UA_VariableNode *namespaceArray = UA_NodeStore_newVariableNode();
  770. copyNames((UA_Node*)namespaceArray, "NamespaceArray");
  771. namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
  772. namespaceArray->valueSource = UA_VALUESOURCE_DATASOURCE;
  773. namespaceArray->value.dataSource = (UA_DataSource) {.handle = server, .read = readNamespaces,
  774. .write = NULL};
  775. namespaceArray->valueRank = 1;
  776. namespaceArray->minimumSamplingInterval = 1.0;
  777. addNodeInternal(server, (UA_Node*)namespaceArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
  778. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
  779. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  780. UA_VariableNode *serverArray = UA_NodeStore_newVariableNode();
  781. copyNames((UA_Node*)serverArray, "ServerArray");
  782. serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
  783. UA_Variant_setArrayCopy(&serverArray->value.variant.value,
  784. &server->config.applicationDescription.applicationUri, 1,
  785. &UA_TYPES[UA_TYPES_STRING]);
  786. serverArray->valueRank = 1;
  787. serverArray->minimumSamplingInterval = 1.0;
  788. addNodeInternal(server, (UA_Node*)serverArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
  789. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), nodeIdHasTypeDefinition,
  790. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  791. UA_ObjectNode *servercapablities = UA_NodeStore_newObjectNode();
  792. copyNames((UA_Node*)servercapablities, "ServerCapabilities");
  793. servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
  794. addNodeInternal(server, (UA_Node*)servercapablities, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
  795. nodeIdHasComponent);
  796. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasTypeDefinition,
  797. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE), true);
  798. UA_VariableNode *localeIdArray = UA_NodeStore_newVariableNode();
  799. copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
  800. localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
  801. localeIdArray->value.variant.value.data = UA_Array_new(1, &UA_TYPES[UA_TYPES_STRING]);
  802. localeIdArray->value.variant.value.arrayLength = 1;
  803. localeIdArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
  804. *(UA_String *)localeIdArray->value.variant.value.data = UA_STRING_ALLOC("en");
  805. localeIdArray->valueRank = 1;
  806. localeIdArray->minimumSamplingInterval = 1.0;
  807. addNodeInternal(server, (UA_Node*)localeIdArray,
  808. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  809. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY),
  810. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  811. UA_VariableNode *maxBrowseContinuationPoints = UA_NodeStore_newVariableNode();
  812. copyNames((UA_Node*)maxBrowseContinuationPoints, "MaxBrowseContinuationPoints");
  813. maxBrowseContinuationPoints->nodeId.identifier.numeric =
  814. UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS;
  815. maxBrowseContinuationPoints->value.variant.value.data = UA_UInt16_new();
  816. *((UA_UInt16*)maxBrowseContinuationPoints->value.variant.value.data) = MAXCONTINUATIONPOINTS;
  817. maxBrowseContinuationPoints->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT16];
  818. addNodeInternal(server, (UA_Node*)maxBrowseContinuationPoints,
  819. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  820. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS),
  821. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  822. /** ServerProfileArray **/
  823. #define MAX_PROFILEARRAY 16 //a *magic* limit to the number of supported profiles
  824. #define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING_ALLOC(x)
  825. UA_String profileArray[MAX_PROFILEARRAY];
  826. UA_UInt16 profileArraySize = 0;
  827. ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NanoEmbeddedDevice");
  828. #ifdef UA_ENABLE_SERVICESET_NODEMANAGEMENT
  829. ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement");
  830. #endif
  831. #ifdef UA_ENABLE_SERVICESET_METHOD
  832. ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods");
  833. #endif
  834. #ifdef UA_ENABLE_SUBSCRIPTIONS
  835. ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/EmbeddedDataChangeSubscription");
  836. #endif
  837. UA_VariableNode *serverProfileArray = UA_NodeStore_newVariableNode();
  838. copyNames((UA_Node*)serverProfileArray, "ServerProfileArray");
  839. serverProfileArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY;
  840. serverProfileArray->value.variant.value.arrayLength = profileArraySize;
  841. serverProfileArray->value.variant.value.data = UA_Array_new(profileArraySize, &UA_TYPES[UA_TYPES_STRING]);
  842. serverProfileArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
  843. for(UA_UInt16 i=0;i<profileArraySize;i++)
  844. ((UA_String *)serverProfileArray->value.variant.value.data)[i] = profileArray[i];
  845. serverProfileArray->valueRank = 1;
  846. serverProfileArray->minimumSamplingInterval = 1.0;
  847. addNodeInternal(server, (UA_Node*)serverProfileArray,
  848. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  849. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY),
  850. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  851. UA_VariableNode *softwareCertificates = UA_NodeStore_newVariableNode();
  852. copyNames((UA_Node*)softwareCertificates, "SoftwareCertificates");
  853. softwareCertificates->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_SOFTWARECERTIFICATES;
  854. softwareCertificates->value.variant.value.type = &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE];
  855. addNodeInternal(server, (UA_Node*)softwareCertificates,
  856. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  857. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_SOFTWARECERTIFICATES),
  858. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  859. UA_VariableNode *maxQueryContinuationPoints = UA_NodeStore_newVariableNode();
  860. copyNames((UA_Node*)maxQueryContinuationPoints, "MaxQueryContinuationPoints");
  861. maxQueryContinuationPoints->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS;
  862. maxQueryContinuationPoints->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT16];
  863. maxQueryContinuationPoints->value.variant.value.data = UA_UInt16_new();
  864. //FIXME
  865. *((UA_UInt16*)maxQueryContinuationPoints->value.variant.value.data) = 0;
  866. addNodeInternal(server, (UA_Node*)maxQueryContinuationPoints,
  867. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  868. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS),
  869. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  870. UA_VariableNode *maxHistoryContinuationPoints = UA_NodeStore_newVariableNode();
  871. copyNames((UA_Node*)maxHistoryContinuationPoints, "MaxHistoryContinuationPoints");
  872. maxHistoryContinuationPoints->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS;
  873. maxHistoryContinuationPoints->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT16];
  874. maxHistoryContinuationPoints->value.variant.value.data = UA_UInt16_new();
  875. //FIXME
  876. *((UA_UInt16*)maxHistoryContinuationPoints->value.variant.value.data) = 0;
  877. addNodeInternal(server, (UA_Node*)maxHistoryContinuationPoints,
  878. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  879. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS),
  880. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  881. UA_VariableNode *minSupportedSampleRate = UA_NodeStore_newVariableNode();
  882. copyNames((UA_Node*)minSupportedSampleRate, "MinSupportedSampleRate");
  883. minSupportedSampleRate->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE;
  884. minSupportedSampleRate->value.variant.value.type = &UA_TYPES[UA_TYPES_DOUBLE];
  885. minSupportedSampleRate->value.variant.value.data = UA_Double_new();
  886. //FIXME
  887. *((UA_Double*)minSupportedSampleRate->value.variant.value.data) = 0.0;
  888. addNodeInternal(server, (UA_Node*)minSupportedSampleRate,
  889. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  890. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE),
  891. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  892. UA_ObjectNode *modellingRules = UA_NodeStore_newObjectNode();
  893. copyNames((UA_Node*)modellingRules, "ModellingRules");
  894. modellingRules->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES;
  895. addNodeInternal(server, (UA_Node*)modellingRules,
  896. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  897. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES),
  898. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), true);
  899. UA_ObjectNode *aggregateFunctions = UA_NodeStore_newObjectNode();
  900. copyNames((UA_Node*)aggregateFunctions, "AggregateFunctions");
  901. aggregateFunctions->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_AGGREGATEFUNCTIONS;
  902. addNodeInternal(server, (UA_Node*)aggregateFunctions,
  903. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
  904. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_AGGREGATEFUNCTIONS),
  905. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), true);
  906. UA_ObjectNode *serverdiagnostics = UA_NodeStore_newObjectNode();
  907. copyNames((UA_Node*)serverdiagnostics, "ServerDiagnostics");
  908. serverdiagnostics->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS;
  909. addNodeInternal(server, (UA_Node*)serverdiagnostics,
  910. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
  911. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
  912. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE), true);
  913. UA_VariableNode *enabledFlag = UA_NodeStore_newVariableNode();
  914. copyNames((UA_Node*)enabledFlag, "EnabledFlag");
  915. enabledFlag->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG;
  916. enabledFlag->value.variant.value.data = UA_Boolean_new(); //initialized as false
  917. enabledFlag->value.variant.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
  918. enabledFlag->valueRank = 1;
  919. enabledFlag->minimumSamplingInterval = 1.0;
  920. addNodeInternal(server, (UA_Node*)enabledFlag,
  921. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), nodeIdHasProperty);
  922. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
  923. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  924. UA_VariableNode *serverstatus = UA_NodeStore_newVariableNode();
  925. copyNames((UA_Node*)serverstatus, "ServerStatus");
  926. serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
  927. serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
  928. serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus, .write = NULL};
  929. addNodeInternal(server, (UA_Node*)serverstatus, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
  930. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasTypeDefinition,
  931. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE), true);
  932. UA_VariableNode *starttime = UA_NodeStore_newVariableNode();
  933. copyNames((UA_Node*)starttime, "StartTime");
  934. starttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
  935. starttime->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
  936. starttime->value.variant.value.data = &server->startTime;
  937. starttime->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
  938. addNodeInternal(server, (UA_Node*)starttime, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
  939. nodeIdHasComponent);
  940. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
  941. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  942. UA_VariableNode *currenttime = UA_NodeStore_newVariableNode();
  943. copyNames((UA_Node*)currenttime, "CurrentTime");
  944. currenttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
  945. currenttime->valueSource = UA_VALUESOURCE_DATASOURCE;
  946. currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
  947. .write = NULL};
  948. addNodeInternal(server, (UA_Node*)currenttime,
  949. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
  950. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
  951. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  952. UA_VariableNode *state = UA_NodeStore_newVariableNode();
  953. UA_ServerState *stateEnum = UA_ServerState_new();
  954. *stateEnum = UA_SERVERSTATE_RUNNING;
  955. copyNames((UA_Node*)state, "State");
  956. state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
  957. state->value.variant.value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
  958. state->value.variant.value.arrayLength = 0;
  959. state->value.variant.value.data = stateEnum; // points into the other object.
  960. addNodeInternal(server, (UA_Node*)state, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
  961. nodeIdHasComponent);
  962. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE),
  963. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  964. UA_VariableNode *buildinfo = UA_NodeStore_newVariableNode();
  965. copyNames((UA_Node*)buildinfo, "BuildInfo");
  966. buildinfo->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO);
  967. UA_Variant_setScalarCopy(&buildinfo->value.variant.value,
  968. &server->config.buildInfo,
  969. &UA_TYPES[UA_TYPES_BUILDINFO]);
  970. addNodeInternal(server, (UA_Node*)buildinfo,
  971. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
  972. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
  973. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE), true);
  974. UA_VariableNode *producturi = UA_NodeStore_newVariableNode();
  975. copyNames((UA_Node*)producturi, "ProductUri");
  976. producturi->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI);
  977. UA_Variant_setScalarCopy(&producturi->value.variant.value, &server->config.buildInfo.productUri,
  978. &UA_TYPES[UA_TYPES_STRING]);
  979. producturi->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
  980. addNodeInternal(server, (UA_Node*)producturi,
  981. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
  982. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
  983. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  984. UA_VariableNode *manufacturername = UA_NodeStore_newVariableNode();
  985. copyNames((UA_Node*)manufacturername, "ManufacturerName");
  986. manufacturername->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME);
  987. UA_Variant_setScalarCopy(&manufacturername->value.variant.value,
  988. &server->config.buildInfo.manufacturerName,
  989. &UA_TYPES[UA_TYPES_STRING]);
  990. addNodeInternal(server, (UA_Node*)manufacturername,
  991. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
  992. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
  993. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  994. UA_VariableNode *productname = UA_NodeStore_newVariableNode();
  995. copyNames((UA_Node*)productname, "ProductName");
  996. productname->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME);
  997. UA_Variant_setScalarCopy(&productname->value.variant.value, &server->config.buildInfo.productName,
  998. &UA_TYPES[UA_TYPES_STRING]);
  999. addNodeInternal(server, (UA_Node*)productname,
  1000. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
  1001. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
  1002. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  1003. UA_VariableNode *softwareversion = UA_NodeStore_newVariableNode();
  1004. copyNames((UA_Node*)softwareversion, "SoftwareVersion");
  1005. softwareversion->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION);
  1006. UA_Variant_setScalarCopy(&softwareversion->value.variant.value, &server->config.buildInfo.softwareVersion,
  1007. &UA_TYPES[UA_TYPES_STRING]);
  1008. addNodeInternal(server, (UA_Node*)softwareversion,
  1009. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
  1010. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
  1011. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  1012. UA_VariableNode *buildnumber = UA_NodeStore_newVariableNode();
  1013. copyNames((UA_Node*)buildnumber, "BuildNumber");
  1014. buildnumber->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER);
  1015. UA_Variant_setScalarCopy(&buildnumber->value.variant.value, &server->config.buildInfo.buildNumber,
  1016. &UA_TYPES[UA_TYPES_STRING]);
  1017. addNodeInternal(server, (UA_Node*)buildnumber,
  1018. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
  1019. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
  1020. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  1021. UA_VariableNode *builddate = UA_NodeStore_newVariableNode();
  1022. copyNames((UA_Node*)builddate, "BuildDate");
  1023. builddate->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE);
  1024. UA_Variant_setScalarCopy(&builddate->value.variant.value, &server->config.buildInfo.buildDate,
  1025. &UA_TYPES[UA_TYPES_DATETIME]);
  1026. addNodeInternal(server, (UA_Node*)builddate,
  1027. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
  1028. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
  1029. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  1030. UA_VariableNode *secondstillshutdown = UA_NodeStore_newVariableNode();
  1031. copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
  1032. secondstillshutdown->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN);
  1033. secondstillshutdown->value.variant.value.data = UA_UInt32_new();
  1034. secondstillshutdown->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT32];
  1035. addNodeInternal(server, (UA_Node*)secondstillshutdown,
  1036. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
  1037. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
  1038. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  1039. UA_VariableNode *shutdownreason = UA_NodeStore_newVariableNode();
  1040. copyNames((UA_Node*)shutdownreason, "ShutdownReason");
  1041. shutdownreason->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON);
  1042. shutdownreason->value.variant.value.data = UA_LocalizedText_new();
  1043. shutdownreason->value.variant.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
  1044. addNodeInternal(server, (UA_Node*)shutdownreason,
  1045. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
  1046. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),
  1047. nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, true);
  1048. UA_VariableNode *servicelevel = UA_NodeStore_newVariableNode();
  1049. copyNames((UA_Node*)servicelevel, "ServiceLevel");
  1050. servicelevel->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVICELEVEL);
  1051. servicelevel->valueSource = UA_VALUESOURCE_DATASOURCE;
  1052. servicelevel->value.dataSource = (UA_DataSource) {.handle = server, .read = readServiceLevel, .write = NULL};
  1053. addNodeInternal(server, (UA_Node*)servicelevel,
  1054. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
  1055. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVICELEVEL),
  1056. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  1057. UA_VariableNode *auditing = UA_NodeStore_newVariableNode();
  1058. copyNames((UA_Node*)auditing, "Auditing");
  1059. auditing->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_AUDITING);
  1060. auditing->valueSource = UA_VALUESOURCE_DATASOURCE;
  1061. auditing->value.dataSource = (UA_DataSource) {.handle = server, .read = readAuditing, .write = NULL};
  1062. addNodeInternal(server, (UA_Node*)auditing,
  1063. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
  1064. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_AUDITING),
  1065. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  1066. UA_ObjectNode *vendorServerInfo = UA_NodeStore_newObjectNode();
  1067. copyNames((UA_Node*)vendorServerInfo, "VendorServerInfo");
  1068. vendorServerInfo->nodeId.identifier.numeric = UA_NS0ID_SERVER_VENDORSERVERINFO;
  1069. addNodeInternal(server, (UA_Node*)vendorServerInfo,
  1070. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
  1071. /*
  1072. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_VENDORSERVERINFO),
  1073. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_VENDORSERVERINFOTYPE), true);
  1074. */
  1075. UA_ObjectNode *serverRedundancy = UA_NodeStore_newObjectNode();
  1076. copyNames((UA_Node*)serverRedundancy, "ServerRedundancy");
  1077. serverRedundancy->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERREDUNDANCY;
  1078. addNodeInternal(server, (UA_Node*)serverRedundancy,
  1079. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
  1080. /*
  1081. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY),
  1082. nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERREDUNDANCYTYPE), true);
  1083. */
  1084. UA_VariableNode *redundancySupport = UA_NodeStore_newVariableNode();
  1085. copyNames((UA_Node*)redundancySupport, "RedundancySupport");
  1086. redundancySupport->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT);
  1087. //FIXME: enum is needed for type letting it uninitialized for now
  1088. redundancySupport->value.variant.value.data = UA_Int32_new();
  1089. redundancySupport->value.variant.value.type = &UA_TYPES[UA_TYPES_INT32];
  1090. addNodeInternal(server, (UA_Node*)redundancySupport, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY),
  1091. nodeIdHasComponent);
  1092. addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT), nodeIdHasTypeDefinition,
  1093. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), true);
  1094. #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
  1095. UA_Argument inputArguments;
  1096. UA_Argument_init(&inputArguments);
  1097. inputArguments.dataType = UA_TYPES[UA_TYPES_UINT32].typeId;
  1098. inputArguments.name = UA_STRING("SubscriptionId");
  1099. inputArguments.valueRank = -1; /* scalar argument */
  1100. UA_Argument outputArguments[2];
  1101. UA_Argument_init(&outputArguments[0]);
  1102. outputArguments[0].dataType = UA_TYPES[UA_TYPES_UINT32].typeId;
  1103. outputArguments[0].name = UA_STRING("ServerHandles");
  1104. outputArguments[0].valueRank = 1;
  1105. UA_Argument_init(&outputArguments[1]);
  1106. outputArguments[1].dataType = UA_TYPES[UA_TYPES_UINT32].typeId;
  1107. outputArguments[1].name = UA_STRING("ClientHandles");
  1108. outputArguments[1].valueRank = 1;
  1109. UA_MethodAttributes addmethodattributes;
  1110. UA_MethodAttributes_init(&addmethodattributes);
  1111. addmethodattributes.displayName = UA_LOCALIZEDTEXT("", "GetMonitoredItems");
  1112. addmethodattributes.executable = true;
  1113. addmethodattributes.userExecutable = true;
  1114. UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS),
  1115. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
  1116. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
  1117. UA_QUALIFIEDNAME(0, "GetMonitoredItems"), addmethodattributes,
  1118. GetMonitoredItems, /* callback of the method node */
  1119. NULL, /* handle passed with the callback */
  1120. 1, &inputArguments,
  1121. 2, outputArguments,
  1122. NULL);
  1123. #endif
  1124. return server;
  1125. }
  1126. #ifdef UA_ENABLE_DISCOVERY
  1127. static UA_StatusCode register_server_with_discovery_server(UA_Server *server, const char* discoveryServerUrl, const UA_Boolean isUnregister, const char* semaphoreFilePath) {
  1128. UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
  1129. UA_StatusCode retval = UA_Client_connect(client, discoveryServerUrl);
  1130. if(retval != UA_STATUSCODE_GOOD) {
  1131. UA_Client_delete(client);
  1132. return retval;
  1133. }
  1134. UA_RegisterServerRequest request;
  1135. UA_RegisterServerRequest_init(&request);
  1136. request.requestHeader.timestamp = UA_DateTime_now();
  1137. request.requestHeader.timeoutHint = 10000;
  1138. request.server.isOnline = !isUnregister;
  1139. // copy all the required data from applicationDescription to request
  1140. retval |= UA_String_copy(&server->config.applicationDescription.applicationUri, &request.server.serverUri);
  1141. retval |= UA_String_copy(&server->config.applicationDescription.productUri, &request.server.productUri);
  1142. request.server.serverNamesSize = 1;
  1143. request.server.serverNames = UA_malloc(sizeof(UA_LocalizedText));
  1144. if (!request.server.serverNames) {
  1145. UA_Client_disconnect(client);
  1146. UA_Client_delete(client);
  1147. return UA_STATUSCODE_BADOUTOFMEMORY;
  1148. }
  1149. retval |= UA_LocalizedText_copy(&server->config.applicationDescription.applicationName, &request.server.serverNames[0]);
  1150. request.server.serverType = server->config.applicationDescription.applicationType;
  1151. retval |= UA_String_copy(&server->config.applicationDescription.gatewayServerUri, &request.server.gatewayServerUri);
  1152. // TODO where do we get the discoveryProfileUri for application data?
  1153. request.server.discoveryUrls = UA_malloc(sizeof(UA_String) * server->config.applicationDescription.discoveryUrlsSize);
  1154. if (!request.server.serverNames) {
  1155. UA_RegisteredServer_deleteMembers(&request.server);
  1156. UA_Client_disconnect(client);
  1157. UA_Client_delete(client);
  1158. return UA_STATUSCODE_BADOUTOFMEMORY;
  1159. }
  1160. for (size_t i = 0; i<server->config.applicationDescription.discoveryUrlsSize; i++) {
  1161. retval |= UA_String_copy(&server->config.applicationDescription.discoveryUrls[i], &request.server.discoveryUrls[i]);
  1162. }
  1163. /* add the discoveryUrls from the networklayers */
  1164. UA_String *disc = UA_realloc(request.server.discoveryUrls, sizeof(UA_String) *
  1165. (request.server.discoveryUrlsSize + server->config.networkLayersSize));
  1166. if(!disc) {
  1167. UA_RegisteredServer_deleteMembers(&request.server);
  1168. UA_Client_disconnect(client);
  1169. UA_Client_delete(client);
  1170. return UA_STATUSCODE_BADOUTOFMEMORY;
  1171. }
  1172. size_t existing = request.server.discoveryUrlsSize;
  1173. request.server.discoveryUrls = disc;
  1174. request.server.discoveryUrlsSize += server->config.networkLayersSize;
  1175. // TODO: Add nl only if discoveryUrl not already present
  1176. for(size_t i = 0; i < server->config.networkLayersSize; i++) {
  1177. UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
  1178. UA_String_copy(&nl->discoveryUrl, &request.server.discoveryUrls[existing + i]);
  1179. }
  1180. if (semaphoreFilePath) {
  1181. request.server.semaphoreFilePath = UA_String_fromChars(semaphoreFilePath);
  1182. }
  1183. // now send the request
  1184. UA_RegisterServerResponse response;
  1185. UA_RegisterServerResponse_init(&response);
  1186. __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST],
  1187. &response, &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE]);
  1188. UA_RegisterServerRequest_deleteMembers(&request);
  1189. if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
  1190. UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_CLIENT,
  1191. "RegisterServer failed with statuscode 0x%08x", response.responseHeader.serviceResult);
  1192. UA_RegisterServerResponse_deleteMembers(&response);
  1193. UA_Client_disconnect(client);
  1194. UA_Client_delete(client);
  1195. return response.responseHeader.serviceResult;
  1196. }
  1197. UA_Client_disconnect(client);
  1198. UA_Client_delete(client);
  1199. return UA_STATUSCODE_GOOD;
  1200. }
  1201. UA_StatusCode UA_Server_register_discovery(UA_Server *server, const char* discoveryServerUrl, const char* semaphoreFilePath) {
  1202. return register_server_with_discovery_server(server, discoveryServerUrl, UA_FALSE, semaphoreFilePath);
  1203. }
  1204. UA_StatusCode UA_Server_unregister_discovery(UA_Server *server, const char* discoveryServerUrl) {
  1205. return register_server_with_discovery_server(server, discoveryServerUrl, UA_TRUE, NULL);
  1206. }
  1207. #endif