ua_nodes.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include "ua_server_internal.h"
  5. #include "ua_nodes.h"
  6. /* There is no UA_Node_new() method here. Creating nodes is part of the
  7. * NodeStore layer */
  8. void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
  9. /* Delete standard content */
  10. UA_NodeId_deleteMembers(&node->nodeId);
  11. UA_QualifiedName_deleteMembers(&node->browseName);
  12. UA_LocalizedText_deleteMembers(&node->displayName);
  13. UA_LocalizedText_deleteMembers(&node->description);
  14. /* Delete references */
  15. UA_Node_deleteReferences(node);
  16. /* Delete unique content of the nodeclass */
  17. switch(node->nodeClass) {
  18. case UA_NODECLASS_OBJECT:
  19. break;
  20. case UA_NODECLASS_METHOD:
  21. break;
  22. case UA_NODECLASS_OBJECTTYPE:
  23. break;
  24. case UA_NODECLASS_VARIABLE:
  25. case UA_NODECLASS_VARIABLETYPE: {
  26. UA_VariableNode *p = (UA_VariableNode*)node;
  27. UA_NodeId_deleteMembers(&p->dataType);
  28. UA_Array_delete(p->arrayDimensions, p->arrayDimensionsSize,
  29. &UA_TYPES[UA_TYPES_INT32]);
  30. p->arrayDimensions = NULL;
  31. p->arrayDimensionsSize = 0;
  32. if(p->valueSource == UA_VALUESOURCE_DATA)
  33. UA_DataValue_deleteMembers(&p->value.data.value);
  34. break;
  35. }
  36. case UA_NODECLASS_REFERENCETYPE: {
  37. UA_ReferenceTypeNode *p = (UA_ReferenceTypeNode*)node;
  38. UA_LocalizedText_deleteMembers(&p->inverseName);
  39. break;
  40. }
  41. case UA_NODECLASS_DATATYPE:
  42. break;
  43. case UA_NODECLASS_VIEW:
  44. break;
  45. default:
  46. break;
  47. }
  48. }
  49. static UA_StatusCode
  50. UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
  51. dst->eventNotifier = src->eventNotifier;
  52. return UA_STATUSCODE_GOOD;
  53. }
  54. static UA_StatusCode
  55. UA_CommonVariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
  56. UA_StatusCode retval = UA_Array_copy(src->arrayDimensions,
  57. src->arrayDimensionsSize,
  58. (void**)&dst->arrayDimensions,
  59. &UA_TYPES[UA_TYPES_INT32]);
  60. if(retval != UA_STATUSCODE_GOOD)
  61. return retval;
  62. dst->arrayDimensionsSize = src->arrayDimensionsSize;
  63. retval = UA_NodeId_copy(&src->dataType, &dst->dataType);
  64. dst->valueRank = src->valueRank;
  65. dst->valueSource = src->valueSource;
  66. if(src->valueSource == UA_VALUESOURCE_DATA) {
  67. retval |= UA_DataValue_copy(&src->value.data.value,
  68. &dst->value.data.value);
  69. dst->value.data.callback = src->value.data.callback;
  70. } else
  71. dst->value.dataSource = src->value.dataSource;
  72. return retval;
  73. }
  74. static UA_StatusCode
  75. UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
  76. UA_StatusCode retval = UA_CommonVariableNode_copy(src, dst);
  77. dst->accessLevel = src->accessLevel;
  78. dst->minimumSamplingInterval = src->minimumSamplingInterval;
  79. dst->historizing = src->historizing;
  80. return retval;
  81. }
  82. static UA_StatusCode
  83. UA_VariableTypeNode_copy(const UA_VariableTypeNode *src,
  84. UA_VariableTypeNode *dst) {
  85. UA_StatusCode retval = UA_CommonVariableNode_copy((const UA_VariableNode*)src,
  86. (UA_VariableNode*)dst);
  87. dst->isAbstract = src->isAbstract;
  88. return retval;
  89. }
  90. static UA_StatusCode
  91. UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
  92. dst->executable = src->executable;
  93. dst->method = src->method;
  94. return UA_STATUSCODE_GOOD;
  95. }
  96. static UA_StatusCode
  97. UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
  98. dst->isAbstract = src->isAbstract;
  99. dst->lifecycle = src->lifecycle;
  100. return UA_STATUSCODE_GOOD;
  101. }
  102. static UA_StatusCode
  103. UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src,
  104. UA_ReferenceTypeNode *dst) {
  105. UA_StatusCode retval = UA_LocalizedText_copy(&src->inverseName,
  106. &dst->inverseName);
  107. dst->isAbstract = src->isAbstract;
  108. dst->symmetric = src->symmetric;
  109. return retval;
  110. }
  111. static UA_StatusCode
  112. UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) {
  113. dst->isAbstract = src->isAbstract;
  114. return UA_STATUSCODE_GOOD;
  115. }
  116. static UA_StatusCode
  117. UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
  118. dst->containsNoLoops = src->containsNoLoops;
  119. dst->eventNotifier = src->eventNotifier;
  120. return UA_STATUSCODE_GOOD;
  121. }
  122. UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst) {
  123. if(src->nodeClass != dst->nodeClass)
  124. return UA_STATUSCODE_BADINTERNALERROR;
  125. /* Copy standard content */
  126. UA_StatusCode retval = UA_NodeId_copy(&src->nodeId, &dst->nodeId);
  127. dst->nodeClass = src->nodeClass;
  128. retval |= UA_QualifiedName_copy(&src->browseName, &dst->browseName);
  129. retval |= UA_LocalizedText_copy(&src->displayName, &dst->displayName);
  130. retval |= UA_LocalizedText_copy(&src->description, &dst->description);
  131. dst->writeMask = src->writeMask;
  132. dst->context = src->context;
  133. dst->constructed = src->constructed;
  134. if(retval != UA_STATUSCODE_GOOD) {
  135. UA_Node_deleteMembersAnyNodeClass(dst);
  136. return retval;
  137. }
  138. /* Copy the references */
  139. dst->references = NULL;
  140. if(src->referencesSize > 0) {
  141. dst->references =
  142. (UA_NodeReferenceKind*)UA_calloc(src->referencesSize,
  143. sizeof(UA_NodeReferenceKind));
  144. if(!dst->references) {
  145. UA_Node_deleteMembersAnyNodeClass(dst);
  146. return UA_STATUSCODE_BADOUTOFMEMORY;
  147. }
  148. dst->referencesSize = src->referencesSize;
  149. for(size_t i = 0; i < src->referencesSize; ++i) {
  150. UA_NodeReferenceKind *srefs = &src->references[i];
  151. UA_NodeReferenceKind *drefs = &dst->references[i];
  152. drefs->isInverse = srefs->isInverse;
  153. retval = UA_NodeId_copy(&srefs->referenceTypeId, &drefs->referenceTypeId);
  154. if(retval != UA_STATUSCODE_GOOD)
  155. break;
  156. retval = UA_Array_copy(srefs->targetIds, srefs->targetIdsSize,
  157. (void**)&drefs->targetIds,
  158. &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
  159. if(retval != UA_STATUSCODE_GOOD)
  160. break;
  161. drefs->targetIdsSize = srefs->targetIdsSize;
  162. }
  163. if(retval != UA_STATUSCODE_GOOD) {
  164. UA_Node_deleteMembersAnyNodeClass(dst);
  165. return retval;
  166. }
  167. }
  168. /* Copy unique content of the nodeclass */
  169. switch(src->nodeClass) {
  170. case UA_NODECLASS_OBJECT:
  171. retval = UA_ObjectNode_copy((const UA_ObjectNode*)src, (UA_ObjectNode*)dst);
  172. break;
  173. case UA_NODECLASS_VARIABLE:
  174. retval = UA_VariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst);
  175. break;
  176. case UA_NODECLASS_METHOD:
  177. retval = UA_MethodNode_copy((const UA_MethodNode*)src, (UA_MethodNode*)dst);
  178. break;
  179. case UA_NODECLASS_OBJECTTYPE:
  180. retval = UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)src, (UA_ObjectTypeNode*)dst);
  181. break;
  182. case UA_NODECLASS_VARIABLETYPE:
  183. retval = UA_VariableTypeNode_copy((const UA_VariableTypeNode*)src, (UA_VariableTypeNode*)dst);
  184. break;
  185. case UA_NODECLASS_REFERENCETYPE:
  186. retval = UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)src, (UA_ReferenceTypeNode*)dst);
  187. break;
  188. case UA_NODECLASS_DATATYPE:
  189. retval = UA_DataTypeNode_copy((const UA_DataTypeNode*)src, (UA_DataTypeNode*)dst);
  190. break;
  191. case UA_NODECLASS_VIEW:
  192. retval = UA_ViewNode_copy((const UA_ViewNode*)src, (UA_ViewNode*)dst);
  193. break;
  194. default:
  195. break;
  196. }
  197. if(retval != UA_STATUSCODE_GOOD)
  198. UA_Node_deleteMembersAnyNodeClass(dst);
  199. return retval;
  200. }
  201. /******************************/
  202. /* Copy Attributes into Nodes */
  203. /******************************/
  204. static UA_StatusCode
  205. copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item,
  206. const UA_NodeAttributes *attr) {
  207. UA_StatusCode retval;
  208. retval = UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
  209. retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
  210. retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
  211. retval |= UA_LocalizedText_copy(&attr->description, &node->description);
  212. node->writeMask = attr->writeMask;
  213. return retval;
  214. }
  215. static UA_StatusCode
  216. copyCommonVariableAttributes(UA_VariableNode *node,
  217. const UA_VariableAttributes *attr) {
  218. /* Copy the array dimensions */
  219. UA_StatusCode retval =
  220. UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
  221. (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
  222. if(retval != UA_STATUSCODE_GOOD)
  223. return retval;
  224. node->arrayDimensionsSize = attr->arrayDimensionsSize;
  225. /* Data type and value rank */
  226. retval |= UA_NodeId_copy(&attr->dataType, &node->dataType);
  227. node->valueRank = attr->valueRank;
  228. /* Copy the value */
  229. node->valueSource = UA_VALUESOURCE_DATA;
  230. retval |= UA_Variant_copy(&attr->value, &node->value.data.value.value);
  231. node->value.data.value.hasValue = true;
  232. return retval;
  233. }
  234. static UA_StatusCode
  235. copyVariableNodeAttributes(UA_VariableNode *vnode,
  236. const UA_VariableAttributes *attr) {
  237. vnode->accessLevel = attr->accessLevel;
  238. vnode->historizing = attr->historizing;
  239. vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
  240. return copyCommonVariableAttributes(vnode, attr);
  241. }
  242. static UA_StatusCode
  243. copyVariableTypeNodeAttributes(UA_VariableTypeNode *vtnode,
  244. const UA_VariableTypeAttributes *attr) {
  245. vtnode->isAbstract = attr->isAbstract;
  246. return copyCommonVariableAttributes((UA_VariableNode*)vtnode,
  247. (const UA_VariableAttributes*)attr);
  248. }
  249. static UA_StatusCode
  250. copyObjectNodeAttributes(UA_ObjectNode *onode, const UA_ObjectAttributes *attr) {
  251. onode->eventNotifier = attr->eventNotifier;
  252. return UA_STATUSCODE_GOOD;
  253. }
  254. static UA_StatusCode
  255. copyReferenceTypeNodeAttributes(UA_ReferenceTypeNode *rtnode,
  256. const UA_ReferenceTypeAttributes *attr) {
  257. rtnode->isAbstract = attr->isAbstract;
  258. rtnode->symmetric = attr->symmetric;
  259. return UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
  260. }
  261. static UA_StatusCode
  262. copyObjectTypeNodeAttributes(UA_ObjectTypeNode *otnode,
  263. const UA_ObjectTypeAttributes *attr) {
  264. otnode->isAbstract = attr->isAbstract;
  265. return UA_STATUSCODE_GOOD;
  266. }
  267. static UA_StatusCode
  268. copyViewNodeAttributes(UA_ViewNode *vnode, const UA_ViewAttributes *attr) {
  269. vnode->containsNoLoops = attr->containsNoLoops;
  270. vnode->eventNotifier = attr->eventNotifier;
  271. return UA_STATUSCODE_GOOD;
  272. }
  273. static UA_StatusCode
  274. copyDataTypeNodeAttributes(UA_DataTypeNode *dtnode,
  275. const UA_DataTypeAttributes *attr) {
  276. dtnode->isAbstract = attr->isAbstract;
  277. return UA_STATUSCODE_GOOD;
  278. }
  279. static UA_StatusCode
  280. copyMethodNodeAttributes(UA_MethodNode *mnode,
  281. const UA_MethodAttributes *attr) {
  282. mnode->executable = attr->executable;
  283. return UA_STATUSCODE_GOOD;
  284. }
  285. #define CHECK_ATTRIBUTES(TYPE) \
  286. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_##TYPE]) { \
  287. retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; \
  288. break; \
  289. }
  290. /* Copy the attributes into a new node. On success, newNode points to the
  291. * created node */
  292. UA_StatusCode
  293. UA_Node_createFromAttributes(const UA_AddNodesItem *item, UA_Node **newNode) {
  294. /* Check that we can read the attributes */
  295. if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
  296. !item->nodeAttributes.content.decoded.type)
  297. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  298. /* Create the node */
  299. // todo: error case where the nodeclass is faulty should return a different
  300. // status code
  301. UA_Node *node = UA_NodeStore_newNode(item->nodeClass);
  302. if(!node)
  303. return UA_STATUSCODE_BADOUTOFMEMORY;
  304. /* Copy the attributes into the node */
  305. void *data = item->nodeAttributes.content.decoded.data;
  306. UA_StatusCode retval = copyStandardAttributes(node, item,
  307. (const UA_NodeAttributes*)data);
  308. switch(item->nodeClass) {
  309. case UA_NODECLASS_OBJECT:
  310. CHECK_ATTRIBUTES(OBJECTATTRIBUTES);
  311. retval |= copyObjectNodeAttributes((UA_ObjectNode*)node,
  312. (const UA_ObjectAttributes*)data);
  313. break;
  314. case UA_NODECLASS_VARIABLE:
  315. CHECK_ATTRIBUTES(VARIABLEATTRIBUTES);
  316. retval |= copyVariableNodeAttributes((UA_VariableNode*)node,
  317. (const UA_VariableAttributes*)data);
  318. break;
  319. case UA_NODECLASS_OBJECTTYPE:
  320. CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES);
  321. retval |= copyObjectTypeNodeAttributes((UA_ObjectTypeNode*)node,
  322. (const UA_ObjectTypeAttributes*)data);
  323. break;
  324. case UA_NODECLASS_VARIABLETYPE:
  325. CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES);
  326. retval |= copyVariableTypeNodeAttributes((UA_VariableTypeNode*)node,
  327. (const UA_VariableTypeAttributes*)data);
  328. break;
  329. case UA_NODECLASS_REFERENCETYPE:
  330. CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES);
  331. retval |= copyReferenceTypeNodeAttributes((UA_ReferenceTypeNode*)node,
  332. (const UA_ReferenceTypeAttributes*)data);
  333. break;
  334. case UA_NODECLASS_DATATYPE:
  335. CHECK_ATTRIBUTES(DATATYPEATTRIBUTES);
  336. retval |= copyDataTypeNodeAttributes((UA_DataTypeNode*)node,
  337. (const UA_DataTypeAttributes*)data);
  338. break;
  339. case UA_NODECLASS_VIEW:
  340. CHECK_ATTRIBUTES(VIEWATTRIBUTES);
  341. retval |= copyViewNodeAttributes((UA_ViewNode*)node,
  342. (const UA_ViewAttributes*)data);
  343. break;
  344. case UA_NODECLASS_METHOD:
  345. CHECK_ATTRIBUTES(METHODATTRIBUTES);
  346. retval |= copyMethodNodeAttributes((UA_MethodNode*)node,
  347. (const UA_MethodAttributes*)data);
  348. break;
  349. case UA_NODECLASS_UNSPECIFIED:
  350. default:
  351. retval = UA_STATUSCODE_BADNODECLASSINVALID;
  352. }
  353. if(retval == UA_STATUSCODE_GOOD)
  354. *newNode = (UA_Node*)node;
  355. else
  356. UA_NodeStore_deleteNode(node);
  357. return retval;
  358. }
  359. /*********************/
  360. /* Manage References */
  361. /*********************/
  362. static UA_StatusCode
  363. addReferenceTarget(UA_NodeReferenceKind *refs, const UA_ExpandedNodeId *target) {
  364. UA_ExpandedNodeId *targets =
  365. (UA_ExpandedNodeId*) UA_realloc(refs->targetIds,
  366. sizeof(UA_ExpandedNodeId) * (refs->targetIdsSize+1));
  367. if(!targets)
  368. return UA_STATUSCODE_BADOUTOFMEMORY;
  369. refs->targetIds = targets;
  370. UA_StatusCode retval =
  371. UA_ExpandedNodeId_copy(target, &refs->targetIds[refs->targetIdsSize]);
  372. if(retval == UA_STATUSCODE_GOOD) {
  373. refs->targetIdsSize++;
  374. } else if(refs->targetIdsSize == 0) {
  375. /* We had zero references before (realloc was a malloc) */
  376. UA_free(refs->targetIds);
  377. refs->targetIds = NULL;
  378. }
  379. return retval;
  380. }
  381. static UA_StatusCode
  382. addReferenceKind(UA_Node *node, const UA_AddReferencesItem *item) {
  383. UA_NodeReferenceKind *refs =
  384. (UA_NodeReferenceKind*)UA_realloc(node->references,
  385. sizeof(UA_NodeReferenceKind) * (node->referencesSize+1));
  386. if(!refs)
  387. return UA_STATUSCODE_BADOUTOFMEMORY;
  388. node->references = refs;
  389. UA_NodeReferenceKind *newRef = &refs[node->referencesSize];
  390. memset(newRef, 0, sizeof(UA_NodeReferenceKind));
  391. newRef->isInverse = !item->isForward;
  392. UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &newRef->referenceTypeId);
  393. retval |= addReferenceTarget(newRef, &item->targetNodeId);
  394. if(retval == UA_STATUSCODE_GOOD) {
  395. node->referencesSize++;
  396. } else {
  397. UA_NodeId_deleteMembers(&newRef->referenceTypeId);
  398. if(node->referencesSize == 0) {
  399. UA_free(node->references);
  400. node->references = NULL;
  401. }
  402. }
  403. return retval;
  404. }
  405. UA_StatusCode
  406. UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item) {
  407. for(size_t i = 0; i < node->referencesSize; ++i) {
  408. UA_NodeReferenceKind *refs = &node->references[i];
  409. if(refs->isInverse == item->isForward)
  410. continue;
  411. if(!UA_NodeId_equal(&refs->referenceTypeId, &item->referenceTypeId))
  412. continue;
  413. return addReferenceTarget(refs, &item->targetNodeId);
  414. }
  415. return addReferenceKind(node, item);
  416. }
  417. UA_StatusCode
  418. UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item) {
  419. for(size_t i = node->referencesSize; i > 0; --i) {
  420. UA_NodeReferenceKind *refs = &node->references[i-1];
  421. if(item->isForward == refs->isInverse)
  422. continue;
  423. if(!UA_NodeId_equal(&item->referenceTypeId, &refs->referenceTypeId))
  424. continue;
  425. for(size_t j = refs->targetIdsSize; j > 0; --j) {
  426. if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &refs->targetIds[j-1].nodeId))
  427. continue;
  428. /* Ok, delete the reference */
  429. UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j-1]);
  430. refs->targetIdsSize--;
  431. /* One matching target remaining */
  432. if(refs->targetIdsSize > 0) {
  433. if(j-1 != refs->targetIdsSize) // avoid valgrind error: Source
  434. // and destination overlap in
  435. // memcpy
  436. refs->targetIds[j-1] = refs->targetIds[refs->targetIdsSize];
  437. return UA_STATUSCODE_GOOD;
  438. }
  439. /* Remove refs */
  440. UA_free(refs->targetIds);
  441. UA_NodeId_deleteMembers(&refs->referenceTypeId);
  442. node->referencesSize--;
  443. if(node->referencesSize > 0) {
  444. if(i-1 != node->referencesSize) // avoid valgrind error: Source
  445. // and destination overlap in
  446. // memcpy
  447. node->references[i-1] = node->references[node->referencesSize];
  448. return UA_STATUSCODE_GOOD;
  449. }
  450. /* Remove the node references */
  451. UA_free(node->references);
  452. node->references = NULL;
  453. return UA_STATUSCODE_GOOD;
  454. }
  455. }
  456. return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
  457. }
  458. void UA_Node_deleteReferences(UA_Node *node) {
  459. for(size_t i = 0; i < node->referencesSize; ++i) {
  460. UA_NodeReferenceKind *refs = &node->references[i];
  461. for(size_t j = 0; j < refs->targetIdsSize; ++j)
  462. UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j]);
  463. UA_free(refs->targetIds);
  464. UA_NodeId_deleteMembers(&refs->referenceTypeId);
  465. }
  466. if(node->references)
  467. UA_free(node->references);
  468. node->references = NULL;
  469. node->referencesSize = 0;
  470. }