ua_server_addressspace.c 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334
  1. #include "ua_server.h"
  2. #include "ua_services.h"
  3. #include "ua_server_internal.h"
  4. UA_StatusCode UA_Server_getNodeCopy(UA_Server *server, UA_NodeId nodeId, void **copyInto) {
  5. const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
  6. UA_Node **copy = (UA_Node **) copyInto;
  7. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  8. if (!node)
  9. return UA_STATUSCODE_BADNODEIDINVALID;
  10. switch(node->nodeClass) {
  11. case UA_NODECLASS_DATATYPE:
  12. *copy = (UA_Node *) UA_VariableNode_new();
  13. retval |= UA_DataTypeNode_copy((const UA_DataTypeNode *) node, (UA_DataTypeNode *) *copy);
  14. break;
  15. case UA_NODECLASS_METHOD:
  16. *copy = (UA_Node *) UA_MethodNode_new();
  17. retval |= UA_MethodNode_copy((const UA_MethodNode *) node, (UA_MethodNode *) *copy);
  18. break;
  19. case UA_NODECLASS_OBJECT:
  20. *copy = (UA_Node *) UA_ObjectNode_new();
  21. retval |= UA_ObjectNode_copy((const UA_ObjectNode *) node, (UA_ObjectNode *) *copy);
  22. break;
  23. case UA_NODECLASS_OBJECTTYPE:
  24. *copy = (UA_Node *) UA_ObjectTypeNode_new();
  25. retval |= UA_ObjectTypeNode_copy((const UA_ObjectTypeNode *) node, (UA_ObjectTypeNode *) *copy);
  26. break;
  27. case UA_NODECLASS_REFERENCETYPE:
  28. *copy = (UA_Node *) UA_ReferenceTypeNode_new();
  29. retval |= UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode *) node, (UA_ReferenceTypeNode *) *copy);
  30. break;
  31. case UA_NODECLASS_VARIABLE:
  32. *copy = (UA_Node *) UA_VariableNode_new();
  33. retval |= UA_VariableNode_copy((const UA_VariableNode *) node, (UA_VariableNode *) *copy);
  34. break;
  35. case UA_NODECLASS_VARIABLETYPE:
  36. *copy = (UA_Node *) UA_VariableTypeNode_new();
  37. retval |= UA_VariableTypeNode_copy((const UA_VariableTypeNode *) node, (UA_VariableTypeNode *) *copy);
  38. break;
  39. case UA_NODECLASS_VIEW:
  40. *copy = (UA_Node *) UA_ViewNode_new();
  41. retval |= UA_ViewNode_copy((const UA_ViewNode *) node, (UA_ViewNode *) *copy);
  42. break;
  43. default:
  44. break;
  45. }
  46. UA_NodeStore_release(node);
  47. return retval;
  48. }
  49. UA_StatusCode UA_Server_deleteNodeCopy(UA_Server *server, void **nodeptr) {
  50. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  51. UA_Node **node = (UA_Node **) nodeptr;
  52. if (!(*node))
  53. return UA_STATUSCODE_BADNODEIDINVALID;
  54. switch((*node)->nodeClass) {
  55. case UA_NODECLASS_DATATYPE:
  56. UA_DataTypeNode_delete((UA_DataTypeNode *) *node);
  57. break;
  58. case UA_NODECLASS_METHOD:
  59. UA_MethodNode_delete((UA_MethodNode *) *node);
  60. break;
  61. case UA_NODECLASS_OBJECT:
  62. UA_ObjectNode_delete((UA_ObjectNode *) *node);
  63. break;
  64. case UA_NODECLASS_OBJECTTYPE:
  65. UA_ObjectTypeNode_delete((UA_ObjectTypeNode *) *node);
  66. break;
  67. case UA_NODECLASS_REFERENCETYPE:
  68. UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *) *node);
  69. break;
  70. case UA_NODECLASS_VARIABLE:
  71. UA_VariableNode_delete((UA_VariableNode *) *node);
  72. break;
  73. case UA_NODECLASS_VARIABLETYPE:
  74. UA_VariableTypeNode_delete((UA_VariableTypeNode *) *node);
  75. break;
  76. case UA_NODECLASS_VIEW:
  77. UA_ViewNode_delete((UA_ViewNode *) *node);
  78. break;
  79. default:
  80. break;
  81. }
  82. return retval;
  83. }
  84. UA_StatusCode UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
  85. union nodeUnion {
  86. const UA_Node *delNodeConst;
  87. UA_Node *delNode;
  88. } ptrs;
  89. ptrs.delNodeConst = UA_NodeStore_get(server->nodestore, &nodeId);
  90. if (!ptrs.delNodeConst)
  91. return UA_STATUSCODE_BADNODEIDINVALID;
  92. UA_NodeStore_release(ptrs.delNodeConst);
  93. // Remove the node from the hashmap/slot
  94. UA_NodeStore_remove(server->nodestore, &nodeId);
  95. /*
  96. * FIXME: Delete unreachable child nodes???
  97. */
  98. return UA_STATUSCODE_GOOD;
  99. }
  100. UA_StatusCode UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
  101. UA_NodeIteratorCallback callback, void *handle) {
  102. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  103. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
  104. if(!parent)
  105. return UA_STATUSCODE_BADNODEIDINVALID;
  106. for(int i=0; i<parent->referencesSize; i++) {
  107. UA_ReferenceNode *ref = &parent->references[i];
  108. retval |= callback(ref->targetId.nodeId, ref->isInverse, ref->referenceTypeId, handle);
  109. }
  110. UA_NodeStore_release(parent);
  111. return retval;
  112. }
  113. UA_StatusCode
  114. UA_Server_addVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  115. const UA_LocalizedText displayName, const UA_LocalizedText description,
  116. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  117. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  118. UA_Variant *value, UA_NodeId *createdNodeId) {
  119. UA_VariableNode *node = UA_VariableNode_new();
  120. UA_StatusCode retval;
  121. node->value.variant = *value; // copy content
  122. UA_NodeId_copy(&nodeId, &node->nodeId);
  123. UA_QualifiedName_copy(&browseName, &node->browseName);
  124. UA_LocalizedText_copy(&displayName, &node->displayName);
  125. UA_LocalizedText_copy(&description, &node->description);
  126. node->writeMask = writeMask;
  127. node->userWriteMask = userWriteMask;
  128. UA_ExpandedNodeId parentId;
  129. UA_ExpandedNodeId_init(&parentId);
  130. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  131. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  132. parentId, referenceTypeId);
  133. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
  134. UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
  135. if(res.statusCode != UA_STATUSCODE_GOOD) {
  136. UA_Variant_init(&node->value.variant);
  137. UA_VariableNode_delete(node);
  138. } else
  139. UA_free(value);
  140. retval = res.statusCode;
  141. if (createdNodeId != UA_NULL)
  142. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  143. UA_AddNodesResult_deleteMembers(&res);
  144. UA_ExpandedNodeId_deleteMembers(&parentId);
  145. return retval;
  146. }
  147. UA_StatusCode
  148. UA_Server_addObjectNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  149. const UA_LocalizedText displayName, const UA_LocalizedText description,
  150. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  151. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  152. const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId){
  153. UA_ObjectNode *node = UA_ObjectNode_new();
  154. UA_StatusCode retval;
  155. UA_NodeId_copy(&nodeId, &node->nodeId);
  156. UA_QualifiedName_copy(&browseName, &node->browseName);
  157. UA_LocalizedText_copy(&displayName, &node->displayName);
  158. UA_LocalizedText_copy(&description, &node->description);
  159. node->writeMask = writeMask;
  160. node->userWriteMask = userWriteMask;
  161. UA_ExpandedNodeId parentId; // we need an expandednodeid
  162. UA_ExpandedNodeId_init(&parentId);
  163. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  164. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  165. parentId, referenceTypeId);
  166. if(res.statusCode != UA_STATUSCODE_GOOD)
  167. UA_ObjectNode_delete(node);
  168. retval = res.statusCode;
  169. if (createdNodeId != UA_NULL)
  170. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  171. UA_AddNodesResult_deleteMembers(&res);
  172. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  173. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  174. }
  175. return retval;
  176. }
  177. UA_StatusCode
  178. UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  179. const UA_LocalizedText displayName, const UA_LocalizedText description,
  180. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  181. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  182. const UA_DataSource dataSource, UA_NodeId *createdNodeId) {
  183. UA_VariableNode *node = UA_VariableNode_new();
  184. UA_StatusCode retval;
  185. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  186. node->value.dataSource = dataSource;
  187. UA_NodeId_copy(&nodeId, &node->nodeId);
  188. UA_QualifiedName_copy(&browseName, &node->browseName);
  189. UA_LocalizedText_copy(&displayName, &node->displayName);
  190. UA_LocalizedText_copy(&description, &node->description);
  191. node->writeMask = writeMask;
  192. node->userWriteMask = userWriteMask;
  193. UA_ExpandedNodeId parentId; // dummy exapndednodeid
  194. UA_ExpandedNodeId_init(&parentId);
  195. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  196. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  197. parentId, referenceTypeId);
  198. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
  199. UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
  200. if(res.statusCode != UA_STATUSCODE_GOOD)
  201. UA_VariableNode_delete(node);
  202. retval = res.statusCode;
  203. if (createdNodeId != UA_NULL)
  204. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  205. UA_AddNodesResult_deleteMembers(&res);
  206. return retval;
  207. }
  208. UA_StatusCode
  209. UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  210. const UA_LocalizedText displayName, const UA_LocalizedText description,
  211. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  212. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  213. UA_Variant *value, const UA_Int32 valueRank, const UA_Boolean isAbstract,
  214. UA_NodeId *createdNodeId) {
  215. UA_VariableTypeNode *node = UA_VariableTypeNode_new();
  216. UA_StatusCode retval;
  217. node->value.variant = *value; // copy content
  218. UA_NodeId_copy(&nodeId, &node->nodeId);
  219. UA_QualifiedName_copy(&browseName, &node->browseName);
  220. UA_LocalizedText_copy(&displayName, &node->displayName);
  221. UA_LocalizedText_copy(&description, &node->description);
  222. node->writeMask = writeMask;
  223. node->userWriteMask = userWriteMask;
  224. UA_ExpandedNodeId parentId;
  225. UA_ExpandedNodeId_init(&parentId);
  226. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  227. node->isAbstract = isAbstract;
  228. node->valueRank = valueRank;
  229. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  230. parentId, referenceTypeId);
  231. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
  232. UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
  233. if(res.statusCode != UA_STATUSCODE_GOOD) {
  234. UA_Variant_init(&node->value.variant);
  235. UA_VariableTypeNode_delete(node);
  236. } else
  237. UA_free(value);
  238. retval = res.statusCode;
  239. if (createdNodeId != UA_NULL)
  240. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  241. UA_AddNodesResult_deleteMembers(&res);
  242. return retval ;
  243. }
  244. UA_StatusCode
  245. UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  246. const UA_LocalizedText displayName, const UA_LocalizedText description,
  247. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  248. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  249. const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
  250. UA_NodeId *createdNodeId) {
  251. UA_DataTypeNode *node = UA_DataTypeNode_new();
  252. UA_StatusCode retval;
  253. UA_NodeId_copy(&nodeId, &node->nodeId);
  254. UA_QualifiedName_copy(&browseName, &node->browseName);
  255. UA_LocalizedText_copy(&displayName, &node->displayName);
  256. UA_LocalizedText_copy(&description, &node->description);
  257. node->writeMask = writeMask;
  258. node->userWriteMask = userWriteMask;
  259. UA_ExpandedNodeId parentId; // we need an expandednodeid
  260. UA_ExpandedNodeId_init(&parentId);
  261. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  262. node->isAbstract = isAbstract;
  263. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  264. parentId, referenceTypeId);
  265. if(res.statusCode != UA_STATUSCODE_GOOD)
  266. UA_DataTypeNode_delete(node);
  267. retval = res.statusCode;
  268. if (createdNodeId != UA_NULL)
  269. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  270. UA_AddNodesResult_deleteMembers(&res);
  271. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  272. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  273. }
  274. return retval;
  275. }
  276. UA_StatusCode
  277. UA_Server_addViewNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  278. const UA_LocalizedText displayName, const UA_LocalizedText description,
  279. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  280. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  281. const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId) {
  282. UA_ViewNode *node = UA_ViewNode_new();
  283. UA_StatusCode retval;
  284. UA_NodeId_copy(&nodeId, &node->nodeId);
  285. UA_QualifiedName_copy(&browseName, &node->browseName);
  286. UA_LocalizedText_copy(&displayName, &node->displayName);
  287. UA_LocalizedText_copy(&description, &node->description);
  288. node->writeMask = writeMask;
  289. node->userWriteMask = userWriteMask;
  290. UA_ExpandedNodeId parentId; // we need an expandednodeid
  291. UA_ExpandedNodeId_init(&parentId);
  292. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  293. node->containsNoLoops = UA_TRUE;
  294. node->eventNotifier = 0;
  295. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  296. parentId, referenceTypeId);
  297. if(res.statusCode != UA_STATUSCODE_GOOD)
  298. UA_ViewNode_delete(node);
  299. retval = res.statusCode;
  300. if (createdNodeId != UA_NULL)
  301. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  302. UA_AddNodesResult_deleteMembers(&res);
  303. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  304. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  305. }
  306. return retval;
  307. }
  308. UA_StatusCode UA_Server_addReferenceTypeNode (UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  309. const UA_LocalizedText displayName, const UA_LocalizedText description,
  310. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  311. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  312. const UA_ExpandedNodeId typeDefinition, const 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. UA_LocalizedText_copy(&inverseName, &node->inverseName);
  321. node->writeMask = writeMask;
  322. node->userWriteMask = userWriteMask;
  323. UA_ExpandedNodeId parentId; // we need an expandednodeid
  324. UA_ExpandedNodeId_init(&parentId);
  325. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  326. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  327. parentId, referenceTypeId);
  328. if(res.statusCode != UA_STATUSCODE_GOOD)
  329. UA_ReferenceTypeNode_delete(node);
  330. retval = res.statusCode;
  331. if (createdNodeId != UA_NULL)
  332. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  333. UA_AddNodesResult_deleteMembers(&res);
  334. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  335. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  336. }
  337. return retval;
  338. }
  339. UA_StatusCode UA_Server_addObjectTypeNode (UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  340. const UA_LocalizedText displayName, const UA_LocalizedText description,
  341. const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
  342. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  343. const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
  344. UA_NodeId *createdNodeId) {
  345. UA_ObjectTypeNode *node = UA_ObjectTypeNode_new();
  346. UA_StatusCode retval;
  347. UA_NodeId_copy(&nodeId, &node->nodeId);
  348. UA_QualifiedName_copy(&browseName, &node->browseName);
  349. UA_LocalizedText_copy(&displayName, &node->displayName);
  350. UA_LocalizedText_copy(&description, &node->description);
  351. node->writeMask = writeMask;
  352. node->userWriteMask = userWriteMask;
  353. UA_ExpandedNodeId parentId; // we need an expandednodeid
  354. UA_ExpandedNodeId_init(&parentId);
  355. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  356. node->isAbstract = isAbstract;
  357. UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
  358. parentId, referenceTypeId);
  359. if(res.statusCode != UA_STATUSCODE_GOOD)
  360. UA_ObjectTypeNode_delete(node);
  361. retval = res.statusCode;
  362. if (createdNodeId != UA_NULL)
  363. UA_NodeId_copy(&res.addedNodeId, createdNodeId);
  364. UA_AddNodesResult_deleteMembers(&res);
  365. if(!UA_NodeId_isNull(&typeDefinition.nodeId)) {
  366. UA_Server_addReference(server, res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefinition);
  367. }
  368. return retval;
  369. }
  370. /* Userspace Version of addOneWayReferenceWithSession*/
  371. UA_StatusCode
  372. UA_Server_addMonodirectionalReference(UA_Server *server, UA_NodeId sourceNodeId, UA_ExpandedNodeId targetNodeId,
  373. UA_NodeId referenceTypeId, UA_Boolean isforward) {
  374. UA_AddReferencesItem ref;
  375. UA_AddReferencesItem_init(&ref);
  376. UA_StatusCode retval = UA_NodeId_copy(&sourceNodeId, &ref.sourceNodeId);
  377. retval |= UA_ExpandedNodeId_copy(&targetNodeId, &ref.targetNodeId);
  378. retval |= UA_NodeId_copy(&referenceTypeId, &ref.referenceTypeId);
  379. if(retval != UA_STATUSCODE_GOOD)
  380. goto cleanup;
  381. const UA_Node *target = UA_NodeStore_get(server->nodestore, &ref.targetNodeId.nodeId);
  382. if(!target) {
  383. retval = UA_STATUSCODE_BADNODEIDINVALID;
  384. goto cleanup;
  385. }
  386. if(isforward == UA_TRUE)
  387. ref.isForward = UA_TRUE;
  388. ref.targetNodeClass = target->nodeClass;
  389. UA_NodeStore_release(target);
  390. retval = addOneWayReferenceWithSession(server, (UA_Session *) UA_NULL, &ref);
  391. cleanup:
  392. UA_AddReferencesItem_deleteMembers(&ref);
  393. return retval;
  394. }
  395. /* Adds a one-way reference to the local nodestore */
  396. UA_StatusCode
  397. addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
  398. const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
  399. if(!node)
  400. return UA_STATUSCODE_BADINTERNALERROR;
  401. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  402. #ifndef UA_MULTITHREADING
  403. size_t i = node->referencesSize;
  404. if(node->referencesSize < 0)
  405. i = 0;
  406. size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
  407. UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
  408. if(!new_refs)
  409. retval = UA_STATUSCODE_BADOUTOFMEMORY;
  410. else {
  411. UA_ReferenceNode_init(&new_refs[i]);
  412. retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId);
  413. new_refs[i].isInverse = !item->isForward;
  414. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId);
  415. /* hack. be careful! possible only in the single-threaded case. */
  416. UA_Node *mutable_node = (UA_Node*)(uintptr_t)node;
  417. mutable_node->references = new_refs;
  418. if(retval != UA_STATUSCODE_GOOD) {
  419. UA_NodeId_deleteMembers(&new_refs[node->referencesSize].referenceTypeId);
  420. UA_ExpandedNodeId_deleteMembers(&new_refs[node->referencesSize].targetId);
  421. } else
  422. mutable_node->referencesSize = i+1;
  423. }
  424. UA_NodeStore_release(node);
  425. return retval;
  426. #else
  427. UA_Node *newNode = UA_NULL;
  428. void (*deleteNode)(UA_Node*) = UA_NULL;
  429. switch(node->nodeClass) {
  430. case UA_NODECLASS_OBJECT:
  431. newNode = (UA_Node*)UA_ObjectNode_new();
  432. UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode*)newNode);
  433. deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete;
  434. break;
  435. case UA_NODECLASS_VARIABLE:
  436. newNode = (UA_Node*)UA_VariableNode_new();
  437. UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode*)newNode);
  438. deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete;
  439. break;
  440. case UA_NODECLASS_METHOD:
  441. newNode = (UA_Node*)UA_MethodNode_new();
  442. UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode*)newNode);
  443. deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete;
  444. break;
  445. case UA_NODECLASS_OBJECTTYPE:
  446. newNode = (UA_Node*)UA_ObjectTypeNode_new();
  447. UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode*)newNode);
  448. deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete;
  449. break;
  450. case UA_NODECLASS_VARIABLETYPE:
  451. newNode = (UA_Node*)UA_VariableTypeNode_new();
  452. UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode*)newNode);
  453. deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete;
  454. break;
  455. case UA_NODECLASS_REFERENCETYPE:
  456. newNode = (UA_Node*)UA_ReferenceTypeNode_new();
  457. UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode*)newNode);
  458. deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete;
  459. break;
  460. case UA_NODECLASS_DATATYPE:
  461. newNode = (UA_Node*)UA_DataTypeNode_new();
  462. UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode*)newNode);
  463. deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete;
  464. break;
  465. case UA_NODECLASS_VIEW:
  466. newNode = (UA_Node*)UA_ViewNode_new();
  467. UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode*)newNode);
  468. deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
  469. break;
  470. default:
  471. return UA_STATUSCODE_BADINTERNALERROR;
  472. }
  473. UA_Int32 count = node->referencesSize;
  474. if(count < 0)
  475. count = 0;
  476. UA_ReferenceNode *old_refs = newNode->references;
  477. UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1));
  478. if(!new_refs) {
  479. deleteNode(newNode);
  480. UA_NodeStore_release(node);
  481. return UA_STATUSCODE_BADOUTOFMEMORY;
  482. }
  483. // insert the new reference
  484. UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
  485. UA_ReferenceNode_init(&new_refs[count]);
  486. retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
  487. new_refs[count].isInverse = !item->isForward;
  488. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
  489. if(retval != UA_STATUSCODE_GOOD) {
  490. UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count);
  491. newNode->references = UA_NULL;
  492. newNode->referencesSize = 0;
  493. deleteNode(newNode);
  494. UA_NodeStore_release(node);
  495. return UA_STATUSCODE_BADOUTOFMEMORY;
  496. }
  497. UA_free(old_refs);
  498. newNode->references = new_refs;
  499. newNode->referencesSize = ++count;
  500. retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
  501. UA_NodeStore_release(node);
  502. if(retval == UA_STATUSCODE_BADINTERNALERROR) {
  503. /* presumably because the node was replaced and an old version was updated at the same time.
  504. just try again */
  505. deleteNode(newNode);
  506. return addOneWayReferenceWithSession(server, session, item);
  507. }
  508. return retval;
  509. #endif
  510. }
  511. UA_StatusCode deleteOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item) {
  512. const UA_Node *orig;
  513. repeat_deleteref_oneway:
  514. orig = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
  515. if(!orig)
  516. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  517. #ifndef UA_MULTITHREADING
  518. /* We cheat if multithreading is not enabled and treat the node as mutable. */
  519. UA_Node *editable = (UA_Node*)(uintptr_t)orig;
  520. #else
  521. UA_Node *editable = UA_Node_copyAnyNodeClass(orig);
  522. UA_Boolean edited = UA_FALSE;;
  523. #endif
  524. for(UA_Int32 i = editable->referencesSize - 1; i >= 0; i--) {
  525. if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &editable->references[i].targetId.nodeId))
  526. continue;
  527. if(!UA_NodeId_equal(&item->referenceTypeId, &editable->references[i].referenceTypeId))
  528. continue;
  529. if(item->isForward == editable->references[i].isInverse)
  530. continue;
  531. /* move the last entry to override the current position */
  532. UA_ReferenceNode_deleteMembers(&editable->references[i]);
  533. editable->references[i] = editable->references[editable->referencesSize-1];
  534. editable->referencesSize--;
  535. #ifdef UA_MULTITHREADING
  536. edited = UA_TRUE;
  537. #endif
  538. }
  539. /* we removed the last reference */
  540. if(editable->referencesSize <= 0 && editable->references)
  541. UA_free(editable->references);
  542. #ifdef UA_MULTITHREADING
  543. if(!edited) {
  544. UA_Node_deleteAnyNodeClass(editable);
  545. } else if(UA_NodeStore_replace(server->nodestore, orig, editable, UA_NULL) != UA_STATUSCODE_GOOD) {
  546. /* the node was changed by another thread. repeat. */
  547. UA_Node_deleteAnyNodeClass(edited);
  548. UA_NodeStore_release(orig);
  549. goto repeat_deleteref_oneway;
  550. }
  551. #endif
  552. UA_NodeStore_release(orig);
  553. return UA_STATUSCODE_GOOD;;
  554. }
  555. /* userland version of addReferenceWithSession */
  556. UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
  557. const UA_ExpandedNodeId targetId) {
  558. UA_AddReferencesItem item;
  559. UA_AddReferencesItem_init(&item);
  560. item.sourceNodeId = sourceId;
  561. item.referenceTypeId = refTypeId;
  562. item.isForward = UA_TRUE;
  563. item.targetNodeId = targetId;
  564. return UA_Server_addReferenceWithSession(server, &adminSession, &item);
  565. }
  566. UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
  567. const UA_AddReferencesItem *item) {
  568. if(item->targetServerUri.length > 0)
  569. return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
  570. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  571. #ifdef UA_EXTERNAL_NAMESPACES
  572. UA_ExternalNodeStore *ensFirst = UA_NULL;
  573. UA_ExternalNodeStore *ensSecond = UA_NULL;
  574. for(size_t j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
  575. if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
  576. ensFirst = &server->externalNamespaces[j].externalNodeStore;
  577. if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)
  578. ensSecond = &server->externalNamespaces[j].externalNodeStore;
  579. }
  580. if(ensFirst) {
  581. // todo: use external nodestore
  582. } else
  583. #endif
  584. retval = addOneWayReferenceWithSession(server, session, item);
  585. if(retval)
  586. return retval;
  587. UA_AddReferencesItem secondItem;
  588. secondItem = *item;
  589. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  590. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  591. secondItem.isForward = !item->isForward;
  592. #ifdef UA_EXTERNAL_NAMESPACES
  593. if(ensSecond) {
  594. // todo: use external nodestore
  595. } else
  596. #endif
  597. retval = addOneWayReferenceWithSession (server, session, &secondItem);
  598. // todo: remove reference if the second direction failed
  599. return retval;
  600. }
  601. UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
  602. const UA_NodeId referenceTypeId) {
  603. return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
  604. }
  605. UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
  606. const UA_ExpandedNodeId parentNodeId, const UA_NodeId referenceTypeId) {
  607. UA_AddNodesResult result;
  608. UA_AddNodesResult_init(&result);
  609. if(node->nodeId.namespaceIndex >= server->namespacesSize) {
  610. result.statusCode = UA_STATUSCODE_BADNODEIDINVALID;
  611. return result;
  612. }
  613. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId.nodeId);
  614. if(!parent) {
  615. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  616. return result;
  617. }
  618. const UA_ReferenceTypeNode *referenceType =
  619. (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, &referenceTypeId);
  620. if(!referenceType) {
  621. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  622. goto ret;
  623. }
  624. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  625. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  626. goto ret2;
  627. }
  628. if(referenceType->isAbstract == UA_TRUE) {
  629. result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
  630. goto ret2;
  631. }
  632. // todo: test if the referencetype is hierarchical
  633. //FIXME: a bit dirty workaround of preserving namespace
  634. //namespace index is assumed to be valid
  635. const UA_Node *managed = UA_NULL;
  636. UA_NodeId tempNodeid;
  637. UA_NodeId_init(&tempNodeid);
  638. UA_NodeId_copy(&node->nodeId, &tempNodeid);
  639. tempNodeid.namespaceIndex = 0;
  640. if(UA_NodeId_isNull(&tempNodeid)) {
  641. if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
  642. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  643. goto ret2;
  644. }
  645. result.addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
  646. } else {
  647. if(UA_NodeId_copy(&node->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
  648. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  649. goto ret2;
  650. }
  651. if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
  652. result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
  653. UA_NodeId_deleteMembers(&result.addedNodeId);
  654. goto ret2;
  655. }
  656. }
  657. // reference back to the parent
  658. UA_AddReferencesItem item;
  659. UA_AddReferencesItem_init(&item);
  660. item.sourceNodeId = managed->nodeId;
  661. item.referenceTypeId = referenceType->nodeId;
  662. item.isForward = UA_FALSE;
  663. item.targetNodeId.nodeId = parent->nodeId;
  664. UA_Server_addReferenceWithSession(server, session, &item);
  665. // todo: error handling. remove new node from nodestore
  666. UA_NodeStore_release(managed);
  667. ret2:
  668. UA_NodeId_deleteMembers(&tempNodeid);
  669. UA_NodeStore_release((const UA_Node*)referenceType);
  670. ret:
  671. UA_NodeStore_release(parent);
  672. return result;
  673. }
  674. #ifdef ENABLE_METHODCALLS
  675. UA_StatusCode
  676. UA_Server_addMethodNode(UA_Server* server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
  677. UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId,
  678. const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  679. UA_MethodCallback method, void *handle, UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments,
  680. UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments,
  681. UA_NodeId* createdNodeId) {
  682. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  683. UA_MethodNode *newMethod = UA_MethodNode_new();
  684. UA_NodeId_copy(&nodeId, &newMethod->nodeId);
  685. UA_QualifiedName_copy(&browseName, &newMethod->browseName);
  686. UA_LocalizedText_copy(&displayName, &newMethod->displayName);
  687. UA_LocalizedText_copy(&description, &newMethod->description);
  688. newMethod->writeMask = writeMask;
  689. newMethod->userWriteMask = userWriteMask;
  690. newMethod->attachedMethod = method;
  691. newMethod->methodHandle = handle;
  692. newMethod->executable = UA_TRUE;
  693. newMethod->userExecutable = UA_TRUE;
  694. UA_ExpandedNodeId parentExpandedNodeId;
  695. UA_ExpandedNodeId_init(&parentExpandedNodeId);
  696. UA_NodeId_copy(&parentNodeId, &parentExpandedNodeId.nodeId);
  697. UA_AddNodesResult addRes = UA_Server_addNode(server, (UA_Node*)newMethod, parentExpandedNodeId, referenceTypeId);
  698. retval |= addRes.statusCode;
  699. if(retval!= UA_STATUSCODE_GOOD) {
  700. UA_MethodNode_delete(newMethod);
  701. return retval;
  702. }
  703. UA_ExpandedNodeId methodExpandedNodeId;
  704. UA_ExpandedNodeId_init(&methodExpandedNodeId);
  705. UA_NodeId_copy(&addRes.addedNodeId, &methodExpandedNodeId.nodeId);
  706. if (createdNodeId != UA_NULL)
  707. UA_NodeId_copy(&addRes.addedNodeId, createdNodeId);
  708. UA_AddNodesResult_deleteMembers(&addRes);
  709. /* Only proceed with creating in/outputArguments if the method and both arguments are not
  710. * UA_NULL; otherwise this is a pretty strong indicator that this node was generated,
  711. * in which case these arguments will be created later and individually.
  712. */
  713. if (method == UA_NULL && inputArguments == UA_NULL && outputArguments == UA_NULL &&
  714. inputArgumentsSize == 0 && outputArgumentsSize == 0)
  715. return retval;
  716. /* create InputArguments */
  717. UA_NodeId argId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
  718. UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
  719. retval |= UA_NodeId_copy(&argId, &inputArgumentsVariableNode->nodeId);
  720. inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
  721. inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  722. inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  723. inputArgumentsVariableNode->valueRank = 1;
  724. UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant, inputArguments,
  725. inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  726. addRes = UA_Server_addNode(server, (UA_Node*)inputArgumentsVariableNode, methodExpandedNodeId,
  727. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
  728. if(addRes.statusCode != UA_STATUSCODE_GOOD) {
  729. UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
  730. if(createdNodeId != UA_NULL)
  731. UA_NodeId_deleteMembers(createdNodeId);
  732. // TODO Remove node
  733. return addRes.statusCode;
  734. }
  735. UA_AddNodesResult_deleteMembers(&addRes);
  736. /* create OutputArguments */
  737. argId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
  738. UA_VariableNode *outputArgumentsVariableNode = UA_VariableNode_new();
  739. retval |= UA_NodeId_copy(&argId, &outputArgumentsVariableNode->nodeId);
  740. outputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
  741. outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  742. outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  743. outputArgumentsVariableNode->valueRank = 1;
  744. UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant, outputArguments,
  745. outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  746. addRes = UA_Server_addNode(server, (UA_Node*)outputArgumentsVariableNode, methodExpandedNodeId,
  747. UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
  748. UA_ExpandedNodeId_deleteMembers(&methodExpandedNodeId);
  749. if(addRes.statusCode != UA_STATUSCODE_GOOD) {
  750. if(createdNodeId != UA_NULL)
  751. UA_NodeId_deleteMembers(createdNodeId);
  752. // TODO Remove node
  753. retval = addRes.statusCode;
  754. }
  755. UA_AddNodesResult_deleteMembers(&addRes);
  756. return retval;
  757. }
  758. #endif
  759. UA_StatusCode UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId nodeId,
  760. const UA_AttributeId attributeId, const UA_Variant value) {
  761. UA_WriteValue wvalue;
  762. UA_WriteValue_init(&wvalue);
  763. wvalue.nodeId = nodeId;
  764. wvalue.attributeId = attributeId;
  765. wvalue.value.value = value;
  766. wvalue.value.hasValue = UA_TRUE;
  767. return Service_Write_single(server, &adminSession, &wvalue);
  768. }
  769. #ifdef ENABLE_METHODCALLS
  770. /* Allow userspace to attach a method to one defined via XML or to switch an attached method for another */
  771. UA_StatusCode
  772. UA_Server_setNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_MethodCallback method, void *handle) {
  773. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  774. const UA_Node *attachToMethod = UA_NULL;
  775. UA_MethodNode *replacementMethod = UA_NULL;
  776. if (!method)
  777. return UA_STATUSCODE_BADMETHODINVALID;
  778. if (!server)
  779. return UA_STATUSCODE_BADSERVERINDEXINVALID;
  780. attachToMethod = UA_NodeStore_get(server->nodestore, &methodNodeId);
  781. if (!attachToMethod)
  782. return UA_STATUSCODE_BADNODEIDINVALID;
  783. if (attachToMethod->nodeClass != UA_NODECLASS_METHOD){
  784. UA_NodeStore_release(attachToMethod);
  785. return UA_STATUSCODE_BADNODEIDINVALID;
  786. }
  787. replacementMethod = UA_MethodNode_new();
  788. UA_MethodNode_copy((const UA_MethodNode *) attachToMethod, replacementMethod);
  789. replacementMethod->attachedMethod = method;
  790. replacementMethod->methodHandle = handle;
  791. UA_NodeStore_replace(server->nodestore, attachToMethod, (UA_Node *) replacementMethod, UA_NULL);
  792. UA_NodeStore_release(attachToMethod);
  793. return retval;
  794. }
  795. #endif
  796. UA_StatusCode
  797. UA_Server_setNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource *value) {
  798. union {
  799. UA_Node *anyNode;
  800. UA_VariableNode *varNode;
  801. UA_VariableTypeNode *varTNode;
  802. } node;
  803. UA_StatusCode retval;
  804. retval = UA_Server_getNodeCopy(server, nodeId, (void **) &node.anyNode);
  805. if (retval != UA_STATUSCODE_GOOD || node.anyNode == UA_NULL)
  806. return retval;
  807. if (node.anyNode->nodeClass != UA_NODECLASS_VARIABLE && node.anyNode->nodeClass != UA_NODECLASS_VARIABLETYPE) {
  808. UA_Server_deleteNodeCopy(server, (void **) &node);
  809. return UA_STATUSCODE_BADNODECLASSINVALID;
  810. }
  811. if (node.anyNode->nodeClass == UA_NODECLASS_VARIABLE) {
  812. if (node.varNode->valueSource == UA_VALUESOURCE_VARIANT) {
  813. UA_Variant_deleteMembers(&node.varNode->value.variant);
  814. }
  815. node.varNode->valueSource = UA_VALUESOURCE_DATASOURCE;
  816. node.varNode->value.dataSource.handle = value->handle;
  817. node.varNode->value.dataSource.read = value->read;
  818. node.varNode->value.dataSource.write = value->write;
  819. }
  820. else {
  821. if (node.varTNode->valueSource == UA_VALUESOURCE_VARIANT) {
  822. UA_Variant_deleteMembers(&node.varTNode->value.variant);
  823. }
  824. node.varTNode->valueSource = UA_VALUESOURCE_DATASOURCE;
  825. node.varTNode->value.dataSource.handle = value->handle;
  826. node.varTNode->value.dataSource.read = value->read;
  827. node.varTNode->value.dataSource.write = value->write;
  828. }
  829. const UA_Node **inserted = UA_NULL;
  830. const UA_Node *oldNode = UA_NodeStore_get(server->nodestore, &node.anyNode->nodeId);
  831. retval |= UA_NodeStore_replace(server->nodestore, oldNode, node.anyNode, inserted);
  832. UA_NodeStore_release(oldNode);
  833. return retval;
  834. }
  835. UA_StatusCode UA_Server_getNodeAttribute(UA_Server *server, const UA_NodeId nodeId, UA_AttributeId attributeId, UA_Variant *v) {
  836. const UA_ReadValueId rvi = {.nodeId = nodeId, .attributeId = attributeId, .indexRange = UA_STRING_NULL,
  837. .dataEncoding = UA_QUALIFIEDNAME(0, "DefaultBinary")};
  838. UA_DataValue dv;
  839. UA_DataValue_init(&dv);
  840. Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rvi, &dv);
  841. if(dv.hasStatus && dv.status != UA_STATUSCODE_GOOD)
  842. return dv.status;
  843. *v = dv.value; // The caller needs to free the content eventually
  844. return UA_STATUSCODE_GOOD;
  845. }
  846. UA_StatusCode UA_Server_getNodeAttributeUnpacked(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId, void *v) {
  847. UA_Variant out;
  848. UA_Variant_init(&out);
  849. UA_StatusCode retval = UA_Server_getNodeAttribute(server, nodeId, attributeId, &out);
  850. if(retval != UA_STATUSCODE_GOOD)
  851. return retval;
  852. if(attributeId == UA_ATTRIBUTEID_VALUE)
  853. UA_memcpy(v, &out, sizeof(UA_Variant));
  854. else {
  855. UA_memcpy(v, out.data, out.type->memSize);
  856. out.data = UA_NULL;
  857. out.arrayLength = -1;
  858. UA_Variant_deleteMembers(&out);
  859. }
  860. return UA_STATUSCODE_GOOD;
  861. }
  862. #ifdef ENABLE_METHODCALLS
  863. UA_StatusCode UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId nodeId, UA_MethodCallback *method) {
  864. const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
  865. if(!node)
  866. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  867. if(node.anyNode->nodeClass != UA_NODECLASS_METHOD) {
  868. UA_NodeStore_release(node);
  869. return UA_STATUSCODE_BADNODECLASSINVALID;
  870. }
  871. *method = ((UA_MethodNode*)node)->attachToMethod;
  872. UA_NodeStore_release(node);
  873. return UA_STATUSCODE_GOOD;
  874. }
  875. #endif
  876. UA_StatusCode UA_Server_getNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource **value) {
  877. union {
  878. UA_Node *anyNode;
  879. UA_VariableNode *varNode;
  880. UA_VariableTypeNode *varTNode;
  881. } node;
  882. UA_StatusCode retval;
  883. *value = UA_NULL;
  884. retval = UA_Server_getNodeCopy(server, nodeId, (void **) &node.anyNode);
  885. if (retval != UA_STATUSCODE_GOOD || node.anyNode == UA_NULL)
  886. return retval;
  887. if (node.anyNode->nodeClass != UA_NODECLASS_VARIABLE && node.anyNode->nodeClass != UA_NODECLASS_VARIABLETYPE) {
  888. UA_Server_deleteNodeCopy(server, (void **) &node);
  889. return UA_STATUSCODE_BADNODECLASSINVALID;
  890. }
  891. if (node.anyNode->nodeClass == UA_NODECLASS_VARIABLE) {
  892. if (node.varNode->valueSource == UA_VALUESOURCE_VARIANT) {
  893. retval |= UA_Server_deleteNodeCopy(server, (void **) &node);
  894. return UA_STATUSCODE_BADINVALIDARGUMENT;
  895. }
  896. *value = (UA_DataSource *) UA_malloc(sizeof(UA_DataSource));
  897. (*(value))->handle = node.varNode->value.dataSource.handle;
  898. (*(value))->read = node.varNode->value.dataSource.read;
  899. (*(value))->write = node.varNode->value.dataSource.write;
  900. }
  901. else {
  902. if (node.varTNode->valueSource == UA_VALUESOURCE_VARIANT) {
  903. retval |= UA_Server_deleteNodeCopy(server, (void **) &node);
  904. return UA_STATUSCODE_BADINVALIDARGUMENT;
  905. }
  906. *value = (UA_DataSource *) UA_malloc(sizeof(UA_DataSource));
  907. (*(value))->handle = node.varNode->value.dataSource.handle;
  908. (*(value))->read = node.varNode->value.dataSource.read;
  909. (*(value))->write = node.varNode->value.dataSource.write;
  910. }
  911. retval |= UA_Server_deleteNodeCopy(server, (void **) &node);
  912. return retval;
  913. }
  914. #define arrayOfNodeIds_addNodeId(ARRAYNAME, NODEID) { \
  915. ARRAYNAME.size++; \
  916. ARRAYNAME.ids = UA_realloc(ARRAYNAME.ids, sizeof(UA_NodeId) * ARRAYNAME.size); \
  917. UA_NodeId_copy(&NODEID, &ARRAYNAME.ids[ARRAYNAME.size-1]); \
  918. }
  919. #define arrayOfNodeIds_deleteMembers(ARRAYNAME) { \
  920. if (ARRAYNAME.size > 0) \
  921. UA_free(ARRAYNAME.ids); \
  922. ARRAYNAME.size = 0; \
  923. }
  924. #define arrayOfNodeIds_idInArray(ARRAYNAME, NODEID, BOOLEAN, BOOLINIT) { \
  925. BOOLEAN = BOOLINIT;\
  926. for (int z=0; z<ARRAYNAME.size; z++) {\
  927. if (UA_NodeId_equal(&ARRAYNAME.ids[z], &NODEID)) {\
  928. BOOLEAN = !BOOLINIT; \
  929. break; \
  930. } \
  931. } \
  932. } \
  933. static void UA_Server_addInstanceOf_inheritParentAttributes(UA_Server *server, arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs,
  934. UA_NodeId objectRoot, UA_InstantiationCallback callback, UA_ObjectTypeNode *typeDefNode,
  935. arrayOfNodeIds *instantiatedTypes, void *handle)
  936. {
  937. UA_Boolean refTypeValid;
  938. UA_ReferenceNode ref;
  939. arrayOfNodeIds visitedNodes = (arrayOfNodeIds) {.size=0, .ids = UA_NULL};
  940. for(int i=0; i<typeDefNode->referencesSize; i++) {
  941. ref = typeDefNode->references[i];
  942. if (ref.isInverse == UA_FALSE)
  943. continue;
  944. refTypeValid = UA_FALSE;
  945. arrayOfNodeIds_idInArray((*subtypeRefs), ref.referenceTypeId, refTypeValid, UA_FALSE);
  946. if (!refTypeValid)
  947. continue;
  948. // Check if already tried to inherit from this node (there is such a thing as duplicate refs)
  949. arrayOfNodeIds_idInArray(visitedNodes, ref.targetId.nodeId, refTypeValid, UA_TRUE);
  950. if (!refTypeValid)
  951. continue;
  952. // Go ahead and inherit this nodes variables and methods (not objects!)
  953. arrayOfNodeIds_addNodeId(visitedNodes, ref.targetId.nodeId);
  954. UA_Server_appendInstanceOfSupertype(server, ref.targetId.nodeId, objectRoot, subtypeRefs, componentRefs, callback, instantiatedTypes, handle);
  955. } // End check all hassubtype refs
  956. arrayOfNodeIds_deleteMembers(visitedNodes);
  957. return;
  958. }
  959. static void UA_Server_addInstanceOf_instatiateChildObject(UA_Server *server, arrayOfNodeIds *subtypeRefs,
  960. arrayOfNodeIds *componentRefs, arrayOfNodeIds *typedefRefs,
  961. UA_Node *objectCopy, UA_NodeId parentId, UA_ExpandedNodeId typeDefinition,
  962. UA_NodeId referenceTypeId, UA_InstantiationCallback callback,
  963. UA_Boolean instantiateObjects, arrayOfNodeIds *instantiatedTypes,
  964. void *handle) {
  965. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  966. // Refuse to create this node if we detect a circular type definition
  967. UA_Boolean typeDefRecursion;
  968. arrayOfNodeIds_idInArray((*instantiatedTypes), typeDefinition.nodeId, typeDefRecursion, UA_FALSE);
  969. if (typeDefRecursion)
  970. return;
  971. UA_Node *typeDefNode;
  972. UA_Server_getNodeCopy(server, typeDefinition.nodeId, (void *) &typeDefNode);
  973. if (typeDefNode == UA_NULL) {
  974. return;
  975. }
  976. if (typeDefNode->nodeClass != UA_NODECLASS_OBJECTTYPE) {
  977. UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
  978. return;
  979. }
  980. // Create the object root as specified by the user
  981. UA_NodeId objectRoot;
  982. retval |= UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(parentId.namespaceIndex, 0), objectCopy->browseName,
  983. objectCopy->displayName, objectCopy->description, objectCopy->userWriteMask,
  984. objectCopy->writeMask, parentId, referenceTypeId, typeDefinition, &objectRoot);
  985. if (retval)
  986. return;
  987. if (callback != UA_NULL)
  988. callback(objectRoot, typeDefinition.nodeId, handle);
  989. // (1) If this node is a subtype of any other node, create its things first
  990. UA_Server_addInstanceOf_inheritParentAttributes(server, subtypeRefs, componentRefs, objectRoot, callback,
  991. (UA_ObjectTypeNode *) typeDefNode, instantiatedTypes, handle);
  992. // (2) For each object or variable referenced with hasComponent or hasProperty, create a new node of that
  993. // type for this objectRoot
  994. UA_Server_addInstanceOf_instatiateChildNode(server, subtypeRefs, componentRefs, typedefRefs,
  995. objectRoot, callback, (UA_ObjectTypeNode *) typeDefNode,
  996. UA_TRUE, instantiatedTypes, handle);
  997. return;
  998. }
  999. void UA_Server_addInstanceOf_instatiateChildNode(UA_Server *server, arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs,
  1000. arrayOfNodeIds *typedefRefs, UA_NodeId objectRoot, UA_InstantiationCallback callback,
  1001. void *typeDefNode, UA_Boolean instantiateObjects, arrayOfNodeIds *instantiatedTypes,
  1002. void *handle) {
  1003. UA_Boolean refTypeValid;
  1004. UA_NodeClass refClass;
  1005. UA_Node *nodeClone;
  1006. UA_ExpandedNodeId *objectRootExpanded = UA_ExpandedNodeId_new();
  1007. UA_VariableNode *newVarNode;
  1008. UA_VariableTypeNode *varTypeNode;
  1009. UA_ReferenceNode ref;
  1010. UA_NodeId_copy(&objectRoot, &objectRootExpanded->nodeId );
  1011. UA_AddNodesResult adres;
  1012. for(int i=0; i< ((UA_ObjectTypeNode *) typeDefNode)->referencesSize; i++) {
  1013. ref = ((UA_ObjectTypeNode *) typeDefNode)->references[i];
  1014. if (ref.isInverse)
  1015. continue;
  1016. arrayOfNodeIds_idInArray((*componentRefs), ref.referenceTypeId, refTypeValid, UA_FALSE);
  1017. if (!refTypeValid)
  1018. continue;
  1019. // What type of node is this?
  1020. UA_Server_getNodeAttribute_nodeClass(server, ref.targetId.nodeId, &refClass);
  1021. switch (refClass) {
  1022. case UA_NODECLASS_VARIABLE: // Just clone the variable node with a new nodeId
  1023. UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &nodeClone);
  1024. if (nodeClone == UA_NULL)
  1025. break;
  1026. UA_NodeId_init(&nodeClone->nodeId);
  1027. nodeClone->nodeId.namespaceIndex = objectRoot.namespaceIndex;
  1028. if (nodeClone != UA_NULL) {
  1029. adres = UA_Server_addNode(server, nodeClone, *objectRootExpanded, ref.referenceTypeId);
  1030. if (callback != UA_NULL)
  1031. callback(adres.addedNodeId, ref.targetId.nodeId, handle);
  1032. }
  1033. break;
  1034. case UA_NODECLASS_VARIABLETYPE: // Convert from a value protoype to a value, then add it
  1035. UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &varTypeNode);
  1036. newVarNode = UA_VariableNode_new();
  1037. newVarNode->nodeId.namespaceIndex = objectRoot.namespaceIndex;
  1038. UA_QualifiedName_copy(&varTypeNode->browseName, &varTypeNode->browseName);
  1039. UA_LocalizedText_copy(&varTypeNode->displayName, &varTypeNode->displayName);
  1040. UA_LocalizedText_copy(&varTypeNode->description, &varTypeNode->description);
  1041. newVarNode->writeMask = varTypeNode->writeMask;
  1042. newVarNode->userWriteMask = varTypeNode->userWriteMask;
  1043. newVarNode->valueRank = varTypeNode->valueRank;
  1044. newVarNode->valueSource = varTypeNode->valueSource;
  1045. if (varTypeNode->valueSource == UA_VALUESOURCE_DATASOURCE)
  1046. newVarNode->value.dataSource = varTypeNode->value.dataSource;
  1047. else
  1048. UA_Variant_copy(&varTypeNode->value.variant, &newVarNode->value.variant);
  1049. adres = UA_Server_addNode(server, (UA_Node *) newVarNode, *objectRootExpanded, ref.referenceTypeId);
  1050. if (callback != UA_NULL)
  1051. callback(adres.addedNodeId, ref.targetId.nodeId, handle);
  1052. UA_Server_deleteNodeCopy(server, (void **) &newVarNode);
  1053. UA_Server_deleteNodeCopy(server, (void **) &varTypeNode);
  1054. break;
  1055. case UA_NODECLASS_OBJECT: // An object may have it's own inheritance or child nodes
  1056. if (!instantiateObjects)
  1057. break;
  1058. UA_Server_getNodeCopy(server, ref.targetId.nodeId, (void **) &nodeClone);
  1059. if (nodeClone == UA_NULL)
  1060. break; // switch
  1061. // Retrieve this nodes type definition
  1062. UA_ExpandedNodeId_init(objectRootExpanded); // Slight misuse of an unsused ExpandedNodeId to encode the typeDefinition
  1063. int tidx;
  1064. for(tidx=0; tidx<nodeClone->referencesSize; tidx++) {
  1065. arrayOfNodeIds_idInArray((*typedefRefs), nodeClone->references[tidx].referenceTypeId, refTypeValid, UA_FALSE);
  1066. if (refTypeValid)
  1067. break;
  1068. } // End iterate over nodeClone refs
  1069. if (!refTypeValid) // This may be plain wrong, but since got this far...
  1070. objectRootExpanded->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  1071. else
  1072. UA_ExpandedNodeId_copy(&nodeClone->references[tidx].targetId, objectRootExpanded);
  1073. int lastArrayDepth = instantiatedTypes->size;
  1074. arrayOfNodeIds_addNodeId((*instantiatedTypes), ((UA_ObjectTypeNode *) typeDefNode)->nodeId);
  1075. UA_Server_addInstanceOf_instatiateChildObject(server, subtypeRefs, componentRefs, typedefRefs, nodeClone,
  1076. objectRoot, *objectRootExpanded, ref.referenceTypeId,
  1077. callback, UA_TRUE, instantiatedTypes, handle);
  1078. instantiatedTypes->size = lastArrayDepth;
  1079. instantiatedTypes->ids = (UA_NodeId *) realloc(instantiatedTypes->ids, lastArrayDepth);
  1080. UA_Server_deleteNodeCopy(server, (void **) &nodeClone);
  1081. UA_ExpandedNodeId_deleteMembers(objectRootExpanded); // since we only borrowed this, reset it
  1082. UA_NodeId_copy(&objectRoot, &objectRootExpanded->nodeId );
  1083. break;
  1084. case UA_NODECLASS_METHOD: // Link this method (don't clone the node)
  1085. UA_Server_addMonodirectionalReference(server, objectRoot, ref.targetId, ref.referenceTypeId, UA_TRUE);
  1086. break;
  1087. default:
  1088. break;
  1089. }
  1090. }
  1091. if (objectRootExpanded != UA_NULL)
  1092. UA_ExpandedNodeId_delete(objectRootExpanded);
  1093. return;
  1094. }
  1095. UA_StatusCode UA_Server_appendInstanceOfSupertype(UA_Server *server, UA_NodeId nodeId, UA_NodeId appendToNodeId,
  1096. arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs,
  1097. UA_InstantiationCallback callback, arrayOfNodeIds *instantiatedTypes,
  1098. void *handle)
  1099. {
  1100. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1101. UA_Node *typeDefNode = UA_NULL;
  1102. UA_Server_getNodeCopy(server, nodeId, (void *) &typeDefNode);
  1103. if (typeDefNode == UA_NULL) {
  1104. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  1105. }
  1106. if (typeDefNode->nodeClass != UA_NODECLASS_OBJECTTYPE) {
  1107. UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
  1108. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  1109. }
  1110. UA_ExpandedNodeId *objectRootExpanded = UA_ExpandedNodeId_new();
  1111. UA_NodeId_copy(&appendToNodeId, &objectRootExpanded->nodeId );
  1112. // (1) If this node is a subtype of any other node, create its things first
  1113. UA_Server_addInstanceOf_inheritParentAttributes(server, subtypeRefs, componentRefs, appendToNodeId, callback,
  1114. (UA_ObjectTypeNode *) typeDefNode, instantiatedTypes, handle);
  1115. UA_Server_addInstanceOf_instatiateChildNode(server, subtypeRefs, componentRefs, UA_NULL,
  1116. appendToNodeId, callback, (UA_ObjectTypeNode *) typeDefNode,
  1117. UA_FALSE, instantiatedTypes, handle);
  1118. if (objectRootExpanded != UA_NULL)
  1119. UA_ExpandedNodeId_delete(objectRootExpanded);
  1120. return retval;
  1121. }
  1122. UA_StatusCode UA_Server_addInstanceOf(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
  1123. UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId,
  1124. const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask,
  1125. const UA_ExpandedNodeId typeDefinition, UA_InstantiationCallback callback, void *handle,
  1126. UA_NodeId *createdNodeId)
  1127. {
  1128. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1129. UA_Node *typeDefNode = UA_NULL;
  1130. UA_Server_getNodeCopy(server, typeDefinition.nodeId, (void *) &typeDefNode);
  1131. if (typeDefNode == UA_NULL) {
  1132. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  1133. }
  1134. if (typeDefNode->nodeClass != UA_NODECLASS_OBJECTTYPE) {
  1135. UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
  1136. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  1137. }
  1138. // Create the object root as specified by the user
  1139. UA_NodeId objectRoot;
  1140. retval |= UA_Server_addObjectNode(server, nodeId, browseName, displayName, description, userWriteMask, writeMask,
  1141. parentNodeId, referenceTypeId,
  1142. typeDefinition, &objectRoot
  1143. );
  1144. if (retval)
  1145. return retval;
  1146. // These refs will be examined later.
  1147. // FIXME: Create these arrays dynamically to include any subtypes as well
  1148. arrayOfNodeIds subtypeRefs = (arrayOfNodeIds) {
  1149. .size = 1,
  1150. .ids = (UA_NodeId[]) { UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE)}
  1151. };
  1152. arrayOfNodeIds componentRefs = (arrayOfNodeIds) {
  1153. .size = 2,
  1154. .ids = (UA_NodeId[]) { UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY)}
  1155. };
  1156. arrayOfNodeIds typedefRefs = (arrayOfNodeIds) {
  1157. .size = 1,
  1158. .ids = (UA_NodeId[]) { UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION)}
  1159. };
  1160. UA_ExpandedNodeId *objectRootExpanded = UA_ExpandedNodeId_new();
  1161. UA_NodeId_copy(&objectRoot, &objectRootExpanded->nodeId );
  1162. arrayOfNodeIds instantiatedTypes = (arrayOfNodeIds ) {.size=0, .ids=NULL};
  1163. arrayOfNodeIds_addNodeId(instantiatedTypes, typeDefNode->nodeId);
  1164. // (1) If this node is a subtype of any other node, create its things first
  1165. UA_Server_addInstanceOf_inheritParentAttributes(server, &subtypeRefs, &componentRefs, objectRoot, callback,
  1166. (UA_ObjectTypeNode *) typeDefNode, &instantiatedTypes, handle);
  1167. // (2) For each object or variable referenced with hasComponent or hasProperty, create a new node of that
  1168. // type for this objectRoot
  1169. UA_Server_addInstanceOf_instatiateChildNode(server, &subtypeRefs, &componentRefs, &typedefRefs,
  1170. objectRoot, callback, (UA_ObjectTypeNode *) typeDefNode,
  1171. UA_TRUE, &instantiatedTypes, handle);
  1172. arrayOfNodeIds_deleteMembers(instantiatedTypes);
  1173. UA_ExpandedNodeId_delete(objectRootExpanded);
  1174. UA_Server_deleteNodeCopy(server, (void **) &typeDefNode);
  1175. return retval;
  1176. }