ua_server_addressspace.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. #include "ua_server.h"
  2. #include "ua_server_internal.h"
  3. #define UA_SERVER_DELETENODEALIAS(TYPE) \
  4. UA_StatusCode UA_Server_delete##TYPE##Node(UA_Server *server, UA_NodeId nodeId) { \
  5. return UA_Server_deleteNode(server, nodeId); \
  6. }
  7. UA_StatusCode
  8. UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
  9. union nodeUnion {
  10. const UA_Node *delNodeConst;
  11. UA_Node *delNode;
  12. } ptrs;
  13. ptrs.delNodeConst = UA_NodeStore_get(server->nodestore, &nodeId);
  14. if (!ptrs.delNodeConst)
  15. return UA_STATUSCODE_BADNODEIDINVALID;
  16. UA_NodeStore_release(ptrs.delNodeConst);
  17. // Remove the node from the hashmap/slot
  18. UA_NodeStore_remove(server->nodestore, &nodeId);
  19. /*
  20. * FIXME: Delete unreachable child nodes???
  21. */
  22. return UA_STATUSCODE_GOOD;
  23. }
  24. UA_SERVER_DELETENODEALIAS(Object)
  25. UA_SERVER_DELETENODEALIAS(Variable)
  26. UA_SERVER_DELETENODEALIAS(ReferenceType)
  27. UA_SERVER_DELETENODEALIAS(View)
  28. UA_SERVER_DELETENODEALIAS(VariableType)
  29. UA_SERVER_DELETENODEALIAS(DataType)
  30. #ifdef ENABLE_METHODCALLS
  31. UA_SERVER_DELETENODEALIAS(Method)
  32. #endif
  33. UA_StatusCode UA_Server_getNodeCopy(UA_Server *server, UA_NodeId nodeId, void **copyInto) {
  34. const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
  35. UA_Node **copy = (UA_Node **) copyInto;
  36. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  37. if (!node)
  38. return UA_STATUSCODE_BADNODEIDINVALID;
  39. switch(node->nodeClass) {
  40. case UA_NODECLASS_DATATYPE:
  41. *copy = (UA_Node *) UA_VariableNode_new();
  42. retval |= UA_DataTypeNode_copy((const UA_DataTypeNode *) node, (UA_DataTypeNode *) *copy);
  43. break;
  44. case UA_NODECLASS_METHOD:
  45. *copy = (UA_Node *) UA_MethodNode_new();
  46. retval |= UA_MethodNode_copy((const UA_MethodNode *) node, (UA_MethodNode *) *copy);
  47. break;
  48. case UA_NODECLASS_OBJECT:
  49. *copy = (UA_Node *) UA_ObjectNode_new();
  50. retval |= UA_ObjectNode_copy((const UA_ObjectNode *) node, (UA_ObjectNode *) *copy);
  51. break;
  52. case UA_NODECLASS_OBJECTTYPE:
  53. *copy = (UA_Node *) UA_ObjectTypeNode_new();
  54. retval |= UA_ObjectTypeNode_copy((const UA_ObjectTypeNode *) node, (UA_ObjectTypeNode *) *copy);
  55. break;
  56. case UA_NODECLASS_REFERENCETYPE:
  57. *copy = (UA_Node *) UA_ReferenceTypeNode_new();
  58. retval |= UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode *) node, (UA_ReferenceTypeNode *) *copy);
  59. break;
  60. case UA_NODECLASS_VARIABLE:
  61. *copy = (UA_Node *) UA_VariableNode_new();
  62. retval |= UA_VariableNode_copy((const UA_VariableNode *) node, (UA_VariableNode *) *copy);
  63. break;
  64. case UA_NODECLASS_VARIABLETYPE:
  65. *copy = (UA_Node *) UA_VariableTypeNode_new();
  66. retval |= UA_VariableTypeNode_copy((const UA_VariableTypeNode *) node, (UA_VariableTypeNode *) *copy);
  67. break;
  68. case UA_NODECLASS_VIEW:
  69. *copy = (UA_Node *) UA_ViewNode_new();
  70. retval |= UA_ViewNode_copy((const UA_ViewNode *) node, (UA_ViewNode *) *copy);
  71. break;
  72. default:
  73. break;
  74. }
  75. UA_NodeStore_release(node);
  76. return retval;
  77. }
  78. UA_StatusCode UA_Server_deleteNodeCopy(UA_Server *server, void **nodeptr) {
  79. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  80. UA_Node **node = (UA_Node **) nodeptr;
  81. if (!(*node))
  82. return UA_STATUSCODE_BADNODEIDINVALID;
  83. switch((*node)->nodeClass) {
  84. case UA_NODECLASS_DATATYPE:
  85. UA_DataTypeNode_delete((UA_DataTypeNode *) *node);
  86. break;
  87. case UA_NODECLASS_METHOD:
  88. UA_MethodNode_delete((UA_MethodNode *) *node);
  89. break;
  90. case UA_NODECLASS_OBJECT:
  91. UA_ObjectNode_delete((UA_ObjectNode *) *node);
  92. break;
  93. case UA_NODECLASS_OBJECTTYPE:
  94. UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) *node);
  95. break;
  96. case UA_NODECLASS_REFERENCETYPE:
  97. UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) *node);
  98. break;
  99. case UA_NODECLASS_VARIABLE:
  100. UA_VariableNode_delete((UA_VariableNode *) *node);
  101. break;
  102. case UA_NODECLASS_VARIABLETYPE:
  103. UA_VariableTypeNode_delete((UA_VariableTypeNode *) *node);
  104. break;
  105. case UA_NODECLASS_VIEW:
  106. UA_ViewNode_delete((UA_ViewNode *) *node);
  107. break;
  108. default:
  109. break;
  110. }
  111. return retval;
  112. }
  113. UA_StatusCode
  114. UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, UA_NodeIteratorCallback callback) {
  115. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  116. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
  117. if (!parent)
  118. return UA_STATUSCODE_BADNODEIDINVALID;
  119. for(int i=0; i<parent->referencesSize; i++) {
  120. UA_ReferenceNode *ref = &parent->references[i];
  121. retval |= callback(ref->targetId.nodeId, ref->isInverse, ref->referenceTypeId);
  122. }
  123. UA_NodeStore_release(parent);
  124. return retval;
  125. }
  126. UA_StatusCode
  127. UA_Server_addVariableNode(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
  128. UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId,
  129. const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  130. UA_Variant *value, UA_NodeId *createdNodeId) {
  131. UA_VariableNode *node = UA_VariableNode_new();
  132. UA_StatusCode retval;
  133. node->value.variant = *value; // copy content
  134. UA_NodeId_copy(&nodeId, &node->nodeId);
  135. UA_QualifiedName_copy(&browseName, &node->browseName);
  136. UA_LocalizedText_copy(&displayName, &node->displayName);
  137. UA_LocalizedText_copy(&description, &node->description);
  138. node->writeMask = writeMask;
  139. node->userWriteMask = userWriteMask;
  140. UA_ExpandedNodeId parentId;
  141. UA_ExpandedNodeId_init(&parentId);
  142. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  143. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  144. parentId, referenceTypeId);
  145. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
  146. UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
  147. if(res.statusCode != UA_STATUSCODE_GOOD) {
  148. UA_Variant_init(&node->value.variant);
  149. UA_VariableNode_delete(node);
  150. } else
  151. UA_free(value);
  152. retval = res.statusCode;
  153. if (createdNodeId != UA_NULL)
  154. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  155. UA_AddNodesResult_deleteMembers(&res);
  156. return retval ;
  157. }
  158. UA_StatusCode
  159. UA_Server_addObjectNode(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
  160. UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId,
  161. const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask,
  162. UA_UInt32 writeMask, const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId) {
  163. UA_ObjectNode *node = UA_ObjectNode_new();
  164. UA_StatusCode retval;
  165. UA_NodeId_copy(&nodeId, &node->nodeId);
  166. UA_QualifiedName_copy(&browseName, &node->browseName);
  167. UA_LocalizedText_copy(&displayName, &node->displayName);
  168. UA_LocalizedText_copy(&description, &node->description);
  169. node->writeMask = writeMask;
  170. node->userWriteMask = userWriteMask;
  171. UA_ExpandedNodeId parentId; // we need an expandednodeid
  172. UA_ExpandedNodeId_init(&parentId);
  173. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  174. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  175. parentId, referenceTypeId);
  176. if(res.statusCode != UA_STATUSCODE_GOOD)
  177. UA_ObjectNode_delete(node);
  178. retval = res.statusCode;
  179. if (createdNodeId != UA_NULL)
  180. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  181. UA_AddNodesResult_deleteMembers(&res);
  182. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  183. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  184. }
  185. return retval;
  186. }
  187. UA_StatusCode
  188. UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
  189. const UA_QualifiedName browseName, UA_NodeId nodeId,
  190. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  191. UA_NodeId *createdNodeId) {
  192. UA_VariableNode *node = UA_VariableNode_new();
  193. UA_StatusCode retval;
  194. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  195. node->value.dataSource = dataSource;
  196. UA_NodeId_copy(&nodeId, &node->nodeId);
  197. UA_QualifiedName_copy(&browseName, &node->browseName);
  198. UA_String_copy(&browseName.name, &node->displayName.text);
  199. UA_ExpandedNodeId parentId; // dummy exapndednodeid
  200. UA_ExpandedNodeId_init(&parentId);
  201. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  202. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  203. parentId, referenceTypeId);
  204. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
  205. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
  206. if(res.statusCode != UA_STATUSCODE_GOOD)
  207. UA_VariableNode_delete(node);
  208. retval = res.statusCode;
  209. if (createdNodeId != UA_NULL)
  210. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  211. UA_AddNodesResult_deleteMembers(&res);
  212. return retval;
  213. }
  214. UA_StatusCode
  215. UA_Server_addVariableTypeNode(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
  216. UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId,
  217. const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  218. UA_Variant *value, UA_Int32 valueRank, UA_Boolean isAbstract, UA_NodeId *createdNodeId) {
  219. UA_VariableTypeNode *node = UA_VariableTypeNode_new();
  220. UA_StatusCode retval;
  221. node->value.variant = *value; // copy content
  222. UA_NodeId_copy(&nodeId, &node->nodeId);
  223. UA_QualifiedName_copy(&browseName, &node->browseName);
  224. UA_LocalizedText_copy(&displayName, &node->displayName);
  225. UA_LocalizedText_copy(&description, &node->description);
  226. node->writeMask = writeMask;
  227. node->userWriteMask = userWriteMask;
  228. UA_ExpandedNodeId parentId;
  229. UA_ExpandedNodeId_init(&parentId);
  230. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  231. node->isAbstract = isAbstract;
  232. node->valueRank = valueRank;
  233. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  234. parentId, referenceTypeId);
  235. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
  236. UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
  237. if(res.statusCode != UA_STATUSCODE_GOOD) {
  238. UA_Variant_init(&node->value.variant);
  239. UA_VariableTypeNode_delete(node);
  240. } else
  241. UA_free(value);
  242. retval = res.statusCode;
  243. if (createdNodeId != UA_NULL)
  244. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  245. UA_AddNodesResult_deleteMembers(&res);
  246. return retval ;
  247. }
  248. UA_StatusCode
  249. UA_Server_addDataTypeNode(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
  250. UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId,
  251. const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  252. UA_ExpandedNodeId typeDefinition, UA_Boolean isAbstract, UA_NodeId *createdNodeId) {
  253. UA_DataTypeNode *node = UA_DataTypeNode_new();
  254. UA_StatusCode retval;
  255. UA_NodeId_copy(&nodeId, &node->nodeId);
  256. UA_QualifiedName_copy(&browseName, &node->browseName);
  257. UA_LocalizedText_copy(&displayName, &node->displayName);
  258. UA_LocalizedText_copy(&description, &node->description);
  259. node->writeMask = writeMask;
  260. node->userWriteMask = userWriteMask;
  261. UA_ExpandedNodeId parentId; // we need an expandednodeid
  262. UA_ExpandedNodeId_init(&parentId);
  263. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  264. node->isAbstract = isAbstract;
  265. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  266. parentId, referenceTypeId);
  267. if(res.statusCode != UA_STATUSCODE_GOOD)
  268. UA_DataTypeNode_delete(node);
  269. retval = res.statusCode;
  270. if (createdNodeId != UA_NULL)
  271. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  272. UA_AddNodesResult_deleteMembers(&res);
  273. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  274. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  275. }
  276. return retval;
  277. }
  278. UA_StatusCode
  279. UA_Server_addViewNode(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
  280. UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId,
  281. const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  282. UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId) {
  283. UA_ViewNode *node = UA_ViewNode_new();
  284. UA_StatusCode retval;
  285. UA_NodeId_copy(&nodeId, &node->nodeId);
  286. UA_QualifiedName_copy(&browseName, &node->browseName);
  287. UA_LocalizedText_copy(&displayName, &node->displayName);
  288. UA_LocalizedText_copy(&description, &node->description);
  289. node->writeMask = writeMask;
  290. node->userWriteMask = userWriteMask;
  291. UA_ExpandedNodeId parentId; // we need an expandednodeid
  292. UA_ExpandedNodeId_init(&parentId);
  293. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  294. node->containsNoLoops = UA_TRUE;
  295. node->eventNotifier = 0;
  296. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  297. parentId, referenceTypeId);
  298. if(res.statusCode != UA_STATUSCODE_GOOD)
  299. UA_ViewNode_delete(node);
  300. retval = res.statusCode;
  301. if (createdNodeId != UA_NULL)
  302. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  303. UA_AddNodesResult_deleteMembers(&res);
  304. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  305. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  306. }
  307. return retval;
  308. }
  309. UA_StatusCode UA_Server_addReferenceTypeNode (UA_Server *server, UA_NodeId nodeId, UA_QualifiedName browseName,
  310. UA_LocalizedText displayName, UA_LocalizedText description, UA_NodeId parentNodeId,
  311. UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  312. UA_ExpandedNodeId typeDefinition, UA_LocalizedText inverseName,
  313. UA_NodeId *createdNodeId ){
  314. UA_ReferenceTypeNode *node = UA_ReferenceTypeNode_new();
  315. UA_StatusCode retval;
  316. UA_NodeId_copy(&nodeId, &node->nodeId);
  317. UA_QualifiedName_copy(&browseName, &node->browseName);
  318. UA_LocalizedText_copy(&displayName, &node->displayName);
  319. UA_LocalizedText_copy(&description, &node->description);
  320. node->writeMask = writeMask;
  321. node->userWriteMask = userWriteMask;
  322. UA_ExpandedNodeId parentId; // we need an expandednodeid
  323. UA_ExpandedNodeId_init(&parentId);
  324. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  325. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  326. parentId, referenceTypeId);
  327. if(res.statusCode != UA_STATUSCODE_GOOD)
  328. UA_ReferenceTypeNode_delete(node);
  329. retval = res.statusCode;
  330. if (createdNodeId != UA_NULL)
  331. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  332. UA_AddNodesResult_deleteMembers(&res);
  333. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  334. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  335. }
  336. return retval;
  337. }
  338. UA_StatusCode UA_Server_addObjectTypeNode ( UA_Server *server, UA_NodeId nodeId, UA_QualifiedName browseName,
  339. UA_LocalizedText displayName, UA_LocalizedText description, UA_NodeId parentNodeId,
  340. UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  341. UA_ExpandedNodeId typeDefinition, UA_Boolean isAbstract,
  342. UA_NodeId *createdNodeId ){
  343. UA_ObjectTypeNode *node = UA_ObjectTypeNode_new();
  344. UA_StatusCode retval;
  345. UA_NodeId_copy(&nodeId, &node->nodeId);
  346. UA_QualifiedName_copy(&browseName, &node->browseName);
  347. UA_LocalizedText_copy(&displayName, &node->displayName);
  348. UA_LocalizedText_copy(&description, &node->description);
  349. node->writeMask = writeMask;
  350. node->userWriteMask = userWriteMask;
  351. UA_ExpandedNodeId parentId; // we need an expandednodeid
  352. UA_ExpandedNodeId_init(&parentId);
  353. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  354. node->isAbstract = isAbstract;
  355. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  356. parentId, referenceTypeId);
  357. if(res.statusCode != UA_STATUSCODE_GOOD)
  358. UA_ObjectTypeNode_delete(node);
  359. retval = res.statusCode;
  360. if (createdNodeId != UA_NULL)
  361. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  362. UA_AddNodesResult_deleteMembers(&res);
  363. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  364. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  365. }
  366. return retval;
  367. }
  368. /* Userspace Version of addOneWayReferenceWithSession*/
  369. UA_StatusCode
  370. UA_Server_AddMonodirectionalReference(UA_Server *server, UA_NodeId sourceNodeId, UA_ExpandedNodeId targetNodeId,
  371. UA_NodeId referenceTypeId, UA_Boolean isforward) {
  372. UA_AddReferencesItem ref;
  373. UA_AddReferencesItem_init(&ref);
  374. UA_StatusCode retval = UA_NodeId_copy(&sourceNodeId, &ref.sourceNodeId);
  375. retval |= UA_ExpandedNodeId_copy(&targetNodeId, &ref.targetNodeId);
  376. retval |= UA_NodeId_copy(&referenceTypeId, &ref.referenceTypeId);
  377. if(retval != UA_STATUSCODE_GOOD)
  378. goto cleanup;
  379. const UA_Node *target = UA_NodeStore_get(server->nodestore, &ref.targetNodeId.nodeId);
  380. if(!target) {
  381. retval = UA_STATUSCODE_BADNODEIDINVALID;
  382. goto cleanup;
  383. }
  384. if(isforward == UA_TRUE)
  385. ref.isForward = UA_TRUE;
  386. ref.targetNodeClass = target->nodeClass;
  387. UA_NodeStore_release(target);
  388. retval = addOneWayReferenceWithSession(server, (UA_Session *) UA_NULL, &ref);
  389. cleanup:
  390. UA_AddReferencesItem_deleteMembers(&ref);
  391. return retval;
  392. }
  393. /* Adds a one-way reference to the local nodestore */
  394. UA_StatusCode
  395. addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
  396. const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
  397. if(!node)
  398. return UA_STATUSCODE_BADINTERNALERROR;
  399. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  400. #ifndef UA_MULTITHREADING
  401. size_t i = node->referencesSize;
  402. if(node->referencesSize < 0)
  403. i = 0;
  404. size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
  405. UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
  406. if(!new_refs)
  407. retval = UA_STATUSCODE_BADOUTOFMEMORY;
  408. else {
  409. UA_ReferenceNode_init(&new_refs[i]);
  410. retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId);
  411. new_refs[i].isInverse = !item->isForward;
  412. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId);
  413. /* hack. be careful! possible only in the single-threaded case. */
  414. UA_Node *mutable_node = (UA_Node*)(uintptr_t)node;
  415. mutable_node->references = new_refs;
  416. if(retval != UA_STATUSCODE_GOOD) {
  417. UA_NodeId_deleteMembers(&new_refs[node->referencesSize].referenceTypeId);
  418. UA_ExpandedNodeId_deleteMembers(&new_refs[node->referencesSize].targetId);
  419. } else
  420. mutable_node->referencesSize = i+1;
  421. }
  422. UA_NodeStore_release(node);
  423. return retval;
  424. #else
  425. UA_Node *newNode = UA_NULL;
  426. void (*deleteNode)(UA_Node*) = UA_NULL;
  427. switch(node->nodeClass) {
  428. case UA_NODECLASS_OBJECT:
  429. newNode = (UA_Node*)UA_ObjectNode_new();
  430. UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode*)newNode);
  431. deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete;
  432. break;
  433. case UA_NODECLASS_VARIABLE:
  434. newNode = (UA_Node*)UA_VariableNode_new();
  435. UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode*)newNode);
  436. deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete;
  437. break;
  438. case UA_NODECLASS_METHOD:
  439. newNode = (UA_Node*)UA_MethodNode_new();
  440. UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode*)newNode);
  441. deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete;
  442. break;
  443. case UA_NODECLASS_OBJECTTYPE:
  444. newNode = (UA_Node*)UA_ObjectTypeNode_new();
  445. UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode*)newNode);
  446. deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete;
  447. break;
  448. case UA_NODECLASS_VARIABLETYPE:
  449. newNode = (UA_Node*)UA_VariableTypeNode_new();
  450. UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode*)newNode);
  451. deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete;
  452. break;
  453. case UA_NODECLASS_REFERENCETYPE:
  454. newNode = (UA_Node*)UA_ReferenceTypeNode_new();
  455. UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode*)newNode);
  456. deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete;
  457. break;
  458. case UA_NODECLASS_DATATYPE:
  459. newNode = (UA_Node*)UA_DataTypeNode_new();
  460. UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode*)newNode);
  461. deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete;
  462. break;
  463. case UA_NODECLASS_VIEW:
  464. newNode = (UA_Node*)UA_ViewNode_new();
  465. UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode*)newNode);
  466. deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
  467. break;
  468. default:
  469. return UA_STATUSCODE_BADINTERNALERROR;
  470. }
  471. UA_Int32 count = node->referencesSize;
  472. if(count < 0)
  473. count = 0;
  474. UA_ReferenceNode *old_refs = newNode->references;
  475. UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1));
  476. if(!new_refs) {
  477. deleteNode(newNode);
  478. UA_NodeStore_release(node);
  479. return UA_STATUSCODE_BADOUTOFMEMORY;
  480. }
  481. // insert the new reference
  482. UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
  483. UA_ReferenceNode_init(&new_refs[count]);
  484. retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
  485. new_refs[count].isInverse = !item->isForward;
  486. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
  487. if(retval != UA_STATUSCODE_GOOD) {
  488. UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count);
  489. newNode->references = UA_NULL;
  490. newNode->referencesSize = 0;
  491. deleteNode(newNode);
  492. UA_NodeStore_release(node);
  493. return UA_STATUSCODE_BADOUTOFMEMORY;
  494. }
  495. UA_free(old_refs);
  496. newNode->references = new_refs;
  497. newNode->referencesSize = ++count;
  498. retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
  499. UA_NodeStore_release(node);
  500. if(retval == UA_STATUSCODE_BADINTERNALERROR) {
  501. /* presumably because the node was replaced and an old version was updated at the same time.
  502. just try again */
  503. deleteNode(newNode);
  504. return addOneWayReferenceWithSession(server, session, item);
  505. }
  506. return retval;
  507. #endif
  508. }
  509. /* userland version of addReferenceWithSession */
  510. UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
  511. const UA_ExpandedNodeId targetId) {
  512. UA_AddReferencesItem item;
  513. UA_AddReferencesItem_init(&item);
  514. item.sourceNodeId = sourceId;
  515. item.referenceTypeId = refTypeId;
  516. item.isForward = UA_TRUE;
  517. item.targetNodeId = targetId;
  518. return UA_Server_addReferenceWithSession(server, &adminSession, &item);
  519. }
  520. UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
  521. const UA_AddReferencesItem *item) {
  522. if(item->targetServerUri.length > 0)
  523. return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
  524. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  525. #ifdef UA_EXTERNAL_NAMESPACES
  526. UA_ExternalNodeStore *ensFirst = UA_NULL;
  527. UA_ExternalNodeStore *ensSecond = UA_NULL;
  528. for(size_t j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
  529. if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
  530. ensFirst = &server->externalNamespaces[j].externalNodeStore;
  531. if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)
  532. ensSecond = &server->externalNamespaces[j].externalNodeStore;
  533. }
  534. if(ensFirst) {
  535. // todo: use external nodestore
  536. } else
  537. #endif
  538. retval = addOneWayReferenceWithSession(server, session, item);
  539. if(retval)
  540. return retval;
  541. UA_AddReferencesItem secondItem;
  542. secondItem = *item;
  543. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  544. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  545. secondItem.isForward = !item->isForward;
  546. #ifdef UA_EXTERNAL_NAMESPACES
  547. if(ensSecond) {
  548. // todo: use external nodestore
  549. } else
  550. #endif
  551. retval = addOneWayReferenceWithSession (server, session, &secondItem);
  552. // todo: remove reference if the second direction failed
  553. return retval;
  554. }
  555. /* userland version of addNodeWithSession */
  556. UA_AddNodesResult
  557. UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
  558. const UA_NodeId referenceTypeId) {
  559. return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
  560. }
  561. UA_AddNodesResult
  562. UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
  563. const UA_ExpandedNodeId parentNodeId, const UA_NodeId referenceTypeId) {
  564. UA_AddNodesResult result;
  565. UA_AddNodesResult_init(&result);
  566. if(node->nodeId.namespaceIndex >= server->namespacesSize) {
  567. result.statusCode = UA_STATUSCODE_BADNODEIDINVALID;
  568. return result;
  569. }
  570. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId.nodeId);
  571. if(!parent) {
  572. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  573. return result;
  574. }
  575. const UA_ReferenceTypeNode *referenceType =
  576. (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, &referenceTypeId);
  577. if(!referenceType) {
  578. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  579. goto ret;
  580. }
  581. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  582. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  583. goto ret2;
  584. }
  585. if(referenceType->isAbstract == UA_TRUE) {
  586. result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
  587. goto ret2;
  588. }
  589. // todo: test if the referencetype is hierarchical
  590. //FIXME: a bit dirty workaround of preserving namespace
  591. //namespace index is assumed to be valid
  592. const UA_Node *managed = UA_NULL;
  593. UA_NodeId tempNodeid;
  594. UA_NodeId_init(&tempNodeid);
  595. UA_NodeId_copy(&node->nodeId, &tempNodeid);
  596. tempNodeid.namespaceIndex = 0;
  597. if(UA_NodeId_isNull(&tempNodeid)) {
  598. if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
  599. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  600. goto ret2;
  601. }
  602. result.addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
  603. } else {
  604. if(UA_NodeId_copy(&node->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
  605. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  606. goto ret2;
  607. }
  608. if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
  609. result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
  610. UA_NodeId_deleteMembers(&result.addedNodeId);
  611. goto ret2;
  612. }
  613. }
  614. // reference back to the parent
  615. UA_AddReferencesItem item;
  616. UA_AddReferencesItem_init(&item);
  617. item.sourceNodeId = managed->nodeId;
  618. item.referenceTypeId = referenceType->nodeId;
  619. item.isForward = UA_FALSE;
  620. item.targetNodeId.nodeId = parent->nodeId;
  621. UA_Server_addReferenceWithSession(server, session, &item);
  622. // todo: error handling. remove new node from nodestore
  623. UA_NodeStore_release(managed);
  624. ret2:
  625. UA_NodeId_deleteMembers(&tempNodeid);
  626. UA_NodeStore_release((const UA_Node*)referenceType);
  627. ret:
  628. UA_NodeStore_release(parent);
  629. return result;
  630. }
  631. #ifdef ENABLE_METHODCALLS
  632. UA_StatusCode
  633. UA_Server_addMethodNode(UA_Server *server, const UA_QualifiedName browseName, UA_NodeId nodeId,
  634. const UA_ExpandedNodeId parentNodeId, const UA_NodeId referenceTypeId,
  635. UA_MethodCallback method, UA_Int32 inputArgumentsSize,
  636. const UA_Argument *inputArguments, UA_Int32 outputArgumentsSize,
  637. const UA_Argument *outputArguments,
  638. UA_NodeId *createdNodeId) {
  639. UA_MethodNode *newMethod = UA_MethodNode_new();
  640. UA_NodeId_copy(&nodeId, &newMethod->nodeId);
  641. UA_QualifiedName_copy(&browseName, &newMethod->browseName);
  642. UA_String_copy(&browseName.name, &newMethod->displayName.text);
  643. newMethod->attachedMethod = method;
  644. newMethod->executable = UA_TRUE;
  645. newMethod->userExecutable = UA_TRUE;
  646. UA_AddNodesResult addRes = UA_Server_addNode(server, (UA_Node*)newMethod, parentNodeId, referenceTypeId);
  647. if(addRes.statusCode != UA_STATUSCODE_GOOD) {
  648. UA_MethodNode_delete(newMethod);
  649. return addRes.statusCode;
  650. }
  651. UA_ExpandedNodeId methodExpandedNodeId;
  652. UA_ExpandedNodeId_init(&methodExpandedNodeId);
  653. UA_NodeId_copy(&addRes.addedNodeId, &methodExpandedNodeId.nodeId);
  654. if (createdNodeId != UA_NULL)
  655. UA_NodeId_copy(&addRes.addedNodeId, createdNodeId);
  656. /* create InputArguments */
  657. UA_NodeId argId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
  658. UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
  659. UA_StatusCode retval = UA_NodeId_copy(&argId, &inputArgumentsVariableNode->nodeId);
  660. inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
  661. inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  662. inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  663. inputArgumentsVariableNode->valueRank = 1;
  664. UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant, inputArguments,
  665. inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  666. addRes = UA_Server_addNode(server, (UA_Node*)inputArgumentsVariableNode, methodExpandedNodeId,
  667. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
  668. if(addRes.statusCode != UA_STATUSCODE_GOOD) {
  669. UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
  670. // TODO Remove node
  671. return addRes.statusCode;
  672. }
  673. if (createdNodeId != UA_NULL)
  674. UA_NodeId_copy(&addRes.addedNodeId, createdNodeId);
  675. /* create OutputArguments */
  676. argId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
  677. UA_VariableNode *outputArgumentsVariableNode = UA_VariableNode_new();
  678. retval |= UA_NodeId_copy(&argId, &outputArgumentsVariableNode->nodeId);
  679. outputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
  680. outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  681. outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  682. outputArgumentsVariableNode->valueRank = 1;
  683. UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant, outputArguments,
  684. outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  685. addRes = UA_Server_addNode(server, (UA_Node*)outputArgumentsVariableNode, methodExpandedNodeId,
  686. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
  687. UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
  688. if(addRes.statusCode != UA_STATUSCODE_GOOD)
  689. // TODO Remove node
  690. retval = addRes.statusCode;
  691. return retval;
  692. }
  693. #endif