ua_server_addressspace.c 39 KB

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