ua_services_nodemanagement.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015
  1. #include "ua_util.h"
  2. #include "ua_server_internal.h"
  3. #include "ua_services.h"
  4. #include "ua_statuscodes.h"
  5. #include "ua_nodestore.h"
  6. #include "ua_session.h"
  7. #include "ua_types_generated_encoding_binary.h"
  8. /************/
  9. /* Add Node */
  10. /************/
  11. void
  12. UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
  13. const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
  14. UA_AddNodesResult *result) {
  15. if(node->nodeId.namespaceIndex >= server->namespacesSize) {
  16. result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
  17. UA_NodeStore_deleteNode(node);
  18. return;
  19. }
  20. const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId);
  21. if(!parent) {
  22. result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  23. UA_NodeStore_deleteNode(node);
  24. return;
  25. }
  26. const UA_ReferenceTypeNode *referenceType =
  27. (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
  28. if(!referenceType) {
  29. result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  30. UA_NodeStore_deleteNode(node);
  31. return;
  32. }
  33. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  34. result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  35. UA_NodeStore_deleteNode(node);
  36. return;
  37. }
  38. if(referenceType->isAbstract == true) {
  39. result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
  40. UA_NodeStore_deleteNode(node);
  41. return;
  42. }
  43. // todo: test if the referencetype is hierarchical
  44. // todo: namespace index is assumed to be valid
  45. result->statusCode = UA_NodeStore_insert(server->nodestore, node);
  46. if(result->statusCode == UA_STATUSCODE_GOOD)
  47. result->statusCode = UA_NodeId_copy(&node->nodeId, &result->addedNodeId);
  48. else
  49. return;
  50. // reference back to the parent
  51. UA_AddReferencesItem item;
  52. UA_AddReferencesItem_init(&item);
  53. item.sourceNodeId = node->nodeId;
  54. item.referenceTypeId = *referenceTypeId;
  55. item.isForward = false;
  56. item.targetNodeId.nodeId = *parentNodeId;
  57. Service_AddReferences_single(server, session, &item);
  58. // todo: error handling. remove new node from nodestore
  59. }
  60. static UA_StatusCode
  61. instantiateVariableNode(UA_Server *server, UA_Session *session,
  62. const UA_NodeId *nodeId, const UA_NodeId *typeId,
  63. UA_InstantiationCallback *instantiationCallback);
  64. static UA_StatusCode
  65. instantiateObjectNode(UA_Server *server, UA_Session *session,
  66. const UA_NodeId *nodeId, const UA_NodeId *typeId,
  67. UA_InstantiationCallback *instantiationCallback);
  68. /* copy an existing variable under the given parent. then instantiate the
  69. variable for all hastypedefinitions of the original version. */
  70. static UA_StatusCode
  71. copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
  72. const UA_NodeId *referenceType, const UA_NodeId *parent,
  73. UA_InstantiationCallback *instantiationCallback) {
  74. const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
  75. if(!node)
  76. return UA_STATUSCODE_BADNODEIDINVALID;
  77. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  78. return UA_STATUSCODE_BADNODECLASSINVALID;
  79. // copy the variable attributes
  80. UA_VariableAttributes attr;
  81. UA_VariableAttributes_init(&attr);
  82. UA_LocalizedText_copy(&node->displayName, &attr.displayName);
  83. UA_LocalizedText_copy(&node->description, &attr.description);
  84. attr.writeMask = node->writeMask;
  85. attr.userWriteMask = node->userWriteMask;
  86. // todo: handle data sources!!!!
  87. UA_Variant_copy(&node->value.variant.value, &attr.value);
  88. // datatype is taken from the value
  89. // valuerank is taken from the value
  90. // array dimensions are taken from the value
  91. attr.accessLevel = node->accessLevel;
  92. attr.userAccessLevel = node->userAccessLevel;
  93. attr.minimumSamplingInterval = node->minimumSamplingInterval;
  94. attr.historizing = node->historizing;
  95. UA_AddNodesItem item;
  96. UA_AddNodesItem_init(&item);
  97. UA_NodeId_copy(parent, &item.parentNodeId.nodeId);
  98. UA_NodeId_copy(referenceType, &item.referenceTypeId);
  99. UA_QualifiedName_copy(&node->browseName, &item.browseName);
  100. item.nodeClass = UA_NODECLASS_VARIABLE;
  101. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  102. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
  103. item.nodeAttributes.content.decoded.data = &attr;
  104. // don't add a typedefinition here.
  105. // add the new variable
  106. UA_AddNodesResult res;
  107. UA_AddNodesResult_init(&res);
  108. Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
  109. UA_VariableAttributes_deleteMembers(&attr);
  110. UA_AddNodesItem_deleteMembers(&item);
  111. // now instantiate the variable for all hastypedefinition references
  112. for(size_t i = 0; i < node->referencesSize; i++) {
  113. UA_ReferenceNode *rn = &node->references[i];
  114. if(rn->isInverse)
  115. continue;
  116. const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  117. if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
  118. continue;
  119. instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
  120. }
  121. if (instantiationCallback != NULL)
  122. instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
  123. UA_AddNodesResult_deleteMembers(&res);
  124. return UA_STATUSCODE_GOOD;
  125. }
  126. /* copy an existing object under the given parent. then instantiate the
  127. variable for all hastypedefinitions of the original version. */
  128. static UA_StatusCode
  129. copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
  130. const UA_NodeId *referenceType, const UA_NodeId *parent,
  131. UA_InstantiationCallback *instantiationCallback) {
  132. const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);
  133. if(!node)
  134. return UA_STATUSCODE_BADNODEIDINVALID;
  135. if(node->nodeClass != UA_NODECLASS_OBJECT)
  136. return UA_STATUSCODE_BADNODECLASSINVALID;
  137. // copy the variable attributes
  138. UA_ObjectAttributes attr;
  139. UA_ObjectAttributes_init(&attr);
  140. UA_LocalizedText_copy(&node->displayName, &attr.displayName);
  141. UA_LocalizedText_copy(&node->description, &attr.description);
  142. attr.writeMask = node->writeMask;
  143. attr.userWriteMask = node->userWriteMask;
  144. attr.eventNotifier = node->eventNotifier;
  145. UA_AddNodesItem item;
  146. UA_AddNodesItem_init(&item);
  147. UA_NodeId_copy(parent, &item.parentNodeId.nodeId);
  148. UA_NodeId_copy(referenceType, &item.referenceTypeId);
  149. UA_QualifiedName_copy(&node->browseName, &item.browseName);
  150. item.nodeClass = UA_NODECLASS_OBJECT;
  151. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  152. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES];
  153. item.nodeAttributes.content.decoded.data = &attr;
  154. // don't add a typedefinition here.
  155. // add the new object
  156. UA_AddNodesResult res;
  157. UA_AddNodesResult_init(&res);
  158. Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
  159. UA_ObjectAttributes_deleteMembers(&attr);
  160. UA_AddNodesItem_deleteMembers(&item);
  161. // now instantiate the object for all hastypedefinition references
  162. for(size_t i = 0; i < node->referencesSize; i++) {
  163. UA_ReferenceNode *rn = &node->references[i];
  164. if(rn->isInverse)
  165. continue;
  166. const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  167. if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
  168. continue;
  169. instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
  170. }
  171. if (instantiationCallback != NULL)
  172. instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
  173. UA_AddNodesResult_deleteMembers(&res);
  174. return UA_STATUSCODE_GOOD;
  175. }
  176. static UA_StatusCode
  177. setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* node, void *handle) {
  178. if(node->nodeClass != UA_NODECLASS_OBJECT)
  179. return UA_STATUSCODE_BADNODECLASSINVALID;
  180. node->instanceHandle = handle;
  181. return UA_STATUSCODE_GOOD;
  182. }
  183. static UA_StatusCode
  184. instantiateObjectNode(UA_Server *server, UA_Session *session,
  185. const UA_NodeId *nodeId, const UA_NodeId *typeId,
  186. UA_InstantiationCallback *instantiationCallback) {
  187. const UA_ObjectTypeNode *typenode = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
  188. if(!typenode)
  189. return UA_STATUSCODE_BADNODEIDINVALID;
  190. if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE)
  191. return UA_STATUSCODE_BADNODECLASSINVALID;
  192. /* Add all the child nodes */
  193. UA_BrowseDescription browseChildren;
  194. UA_BrowseDescription_init(&browseChildren);
  195. browseChildren.nodeId = *typeId;
  196. browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  197. browseChildren.includeSubtypes = true;
  198. browseChildren.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  199. browseChildren.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  200. browseChildren.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS;
  201. UA_BrowseResult browseResult;
  202. UA_BrowseResult_init(&browseResult);
  203. // todo: continuation points if there are too many results
  204. Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult);
  205. for(size_t i = 0; i < browseResult.referencesSize; i++) {
  206. UA_ReferenceDescription *rd = &browseResult.references[i];
  207. if(rd->nodeClass == UA_NODECLASS_METHOD) {
  208. /* add a reference to the method in the objecttype */
  209. UA_AddReferencesItem item;
  210. UA_AddReferencesItem_init(&item);
  211. item.sourceNodeId = *nodeId;
  212. item.referenceTypeId = rd->referenceTypeId;
  213. item.isForward = true;
  214. item.targetNodeId = rd->nodeId;
  215. item.targetNodeClass = UA_NODECLASS_METHOD;
  216. Service_AddReferences_single(server, session, &item);
  217. } else if(rd->nodeClass == UA_NODECLASS_VARIABLE)
  218. copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
  219. else if(rd->nodeClass == UA_NODECLASS_OBJECT)
  220. copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
  221. }
  222. /* add a hastypedefinition reference */
  223. UA_AddReferencesItem addref;
  224. UA_AddReferencesItem_init(&addref);
  225. addref.sourceNodeId = *nodeId;
  226. addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  227. addref.isForward = true;
  228. addref.targetNodeId.nodeId = *typeId;
  229. addref.targetNodeClass = UA_NODECLASS_OBJECTTYPE;
  230. Service_AddReferences_single(server, session, &addref);
  231. /* call the constructor */
  232. const UA_ObjectLifecycleManagement *olm = &typenode->lifecycleManagement;
  233. if(olm->constructor)
  234. UA_Server_editNode(server, session, nodeId,
  235. (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId));
  236. return UA_STATUSCODE_GOOD;
  237. }
  238. static UA_StatusCode
  239. instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
  240. const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
  241. const UA_ObjectTypeNode *typenode = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
  242. if(!typenode)
  243. return UA_STATUSCODE_BADNODEIDINVALID;
  244. if(typenode->nodeClass != UA_NODECLASS_VARIABLETYPE)
  245. return UA_STATUSCODE_BADNODECLASSINVALID;
  246. /* get the references to child properties */
  247. UA_BrowseDescription browseChildren;
  248. UA_BrowseDescription_init(&browseChildren);
  249. browseChildren.nodeId = *typeId;
  250. browseChildren.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
  251. browseChildren.includeSubtypes = true;
  252. browseChildren.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  253. browseChildren.nodeClassMask = UA_NODECLASS_VARIABLE;
  254. browseChildren.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS;
  255. UA_BrowseResult browseResult;
  256. UA_BrowseResult_init(&browseResult);
  257. // todo: continuation points if there are too many results
  258. Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult);
  259. /* add the child properties */
  260. for(size_t i = 0; i < browseResult.referencesSize; i++) {
  261. UA_ReferenceDescription *rd = &browseResult.references[i];
  262. copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
  263. }
  264. /* add a hastypedefinition reference */
  265. UA_AddReferencesItem addref;
  266. UA_AddReferencesItem_init(&addref);
  267. addref.sourceNodeId = *nodeId;
  268. addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  269. addref.isForward = true;
  270. addref.targetNodeId.nodeId = *typeId;
  271. addref.targetNodeClass = UA_NODECLASS_OBJECTTYPE;
  272. Service_AddReferences_single(server, session, &addref);
  273. return UA_STATUSCODE_GOOD;
  274. }
  275. static UA_StatusCode
  276. copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item, const UA_NodeAttributes *attr) {
  277. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  278. retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
  279. retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
  280. retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
  281. retval |= UA_LocalizedText_copy(&attr->description, &node->description);
  282. node->writeMask = attr->writeMask;
  283. node->userWriteMask = attr->userWriteMask;
  284. return retval;
  285. }
  286. static UA_Node *
  287. variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttributes *attr) {
  288. UA_VariableNode *vnode = UA_NodeStore_newVariableNode();
  289. if(!vnode)
  290. return NULL;
  291. UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
  292. // todo: test if the type / valueRank / value attributes are consistent
  293. vnode->accessLevel = attr->accessLevel;
  294. vnode->userAccessLevel = attr->userAccessLevel;
  295. vnode->historizing = attr->historizing;
  296. vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
  297. vnode->valueRank = attr->valueRank;
  298. retval |= UA_Variant_copy(&attr->value, &vnode->value.variant.value);
  299. if(retval != UA_STATUSCODE_GOOD) {
  300. UA_NodeStore_deleteNode((UA_Node*)vnode);
  301. return NULL;
  302. }
  303. return (UA_Node*)vnode;
  304. }
  305. static UA_Node *
  306. objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes *attr) {
  307. UA_ObjectNode *onode = UA_NodeStore_newObjectNode();
  308. if(!onode)
  309. return NULL;
  310. UA_StatusCode retval = copyStandardAttributes((UA_Node*)onode, item, (const UA_NodeAttributes*)attr);
  311. onode->eventNotifier = attr->eventNotifier;
  312. if(retval != UA_STATUSCODE_GOOD) {
  313. UA_NodeStore_deleteNode((UA_Node*)onode);
  314. return NULL;
  315. }
  316. return (UA_Node*)onode;
  317. }
  318. static UA_Node *
  319. referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) {
  320. UA_ReferenceTypeNode *rtnode = UA_NodeStore_newReferenceTypeNode();
  321. if(!rtnode)
  322. return NULL;
  323. UA_StatusCode retval = copyStandardAttributes((UA_Node*)rtnode, item, (const UA_NodeAttributes*)attr);
  324. rtnode->isAbstract = attr->isAbstract;
  325. rtnode->symmetric = attr->symmetric;
  326. retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
  327. if(retval != UA_STATUSCODE_GOOD) {
  328. UA_NodeStore_deleteNode((UA_Node*)rtnode);
  329. return NULL;
  330. }
  331. return (UA_Node*)rtnode;
  332. }
  333. static UA_Node *
  334. objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAttributes *attr) {
  335. UA_ObjectTypeNode *otnode = UA_NodeStore_newObjectTypeNode();
  336. if(!otnode)
  337. return NULL;
  338. UA_StatusCode retval = copyStandardAttributes((UA_Node*)otnode, item, (const UA_NodeAttributes*)attr);
  339. otnode->isAbstract = attr->isAbstract;
  340. if(retval != UA_STATUSCODE_GOOD) {
  341. UA_NodeStore_deleteNode((UA_Node*)otnode);
  342. return NULL;
  343. }
  344. return (UA_Node*)otnode;
  345. }
  346. static UA_Node *
  347. variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTypeAttributes *attr) {
  348. UA_VariableTypeNode *vtnode = UA_NodeStore_newVariableTypeNode();
  349. if(!vtnode)
  350. return NULL;
  351. UA_StatusCode retval = copyStandardAttributes((UA_Node*)vtnode, item, (const UA_NodeAttributes*)attr);
  352. UA_Variant_copy(&attr->value, &vtnode->value.variant.value);
  353. // datatype is taken from the value
  354. vtnode->valueRank = attr->valueRank;
  355. // array dimensions are taken from the value
  356. vtnode->isAbstract = attr->isAbstract;
  357. if(retval != UA_STATUSCODE_GOOD) {
  358. UA_NodeStore_deleteNode((UA_Node*)vtnode);
  359. return NULL;
  360. }
  361. return (UA_Node*)vtnode;
  362. }
  363. static UA_Node *
  364. viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *attr) {
  365. UA_ViewNode *vnode = UA_NodeStore_newViewNode();
  366. if(!vnode)
  367. return NULL;
  368. UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
  369. vnode->containsNoLoops = attr->containsNoLoops;
  370. vnode->eventNotifier = attr->eventNotifier;
  371. if(retval != UA_STATUSCODE_GOOD) {
  372. UA_NodeStore_deleteNode((UA_Node*)vnode);
  373. return NULL;
  374. }
  375. return (UA_Node*)vnode;
  376. }
  377. static UA_Node *
  378. dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttributes *attr) {
  379. UA_DataTypeNode *dtnode = UA_NodeStore_newDataTypeNode();
  380. if(!dtnode)
  381. return NULL;
  382. UA_StatusCode retval = copyStandardAttributes((UA_Node*)dtnode, item, (const UA_NodeAttributes*)attr);
  383. dtnode->isAbstract = attr->isAbstract;
  384. if(retval != UA_STATUSCODE_GOOD) {
  385. UA_NodeStore_deleteNode((UA_Node*)dtnode);
  386. return NULL;
  387. }
  388. return (UA_Node*)dtnode;
  389. }
  390. void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
  391. UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback) {
  392. if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
  393. !item->nodeAttributes.content.decoded.type) {
  394. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  395. return;
  396. }
  397. /* create the node */
  398. UA_Node *node;
  399. switch(item->nodeClass) {
  400. case UA_NODECLASS_OBJECT:
  401. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES]) {
  402. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  403. return;
  404. }
  405. node = objectNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
  406. break;
  407. case UA_NODECLASS_VARIABLE:
  408. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]) {
  409. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  410. return;
  411. }
  412. node = variableNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
  413. break;
  414. case UA_NODECLASS_OBJECTTYPE:
  415. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]) {
  416. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  417. return;
  418. }
  419. node = objectTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
  420. break;
  421. case UA_NODECLASS_VARIABLETYPE:
  422. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]) {
  423. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  424. return;
  425. }
  426. node = variableTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
  427. break;
  428. case UA_NODECLASS_REFERENCETYPE:
  429. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]) {
  430. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  431. return;
  432. }
  433. node = referenceTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
  434. break;
  435. case UA_NODECLASS_DATATYPE:
  436. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]) {
  437. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  438. return;
  439. }
  440. node = dataTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
  441. break;
  442. case UA_NODECLASS_VIEW:
  443. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_VIEWATTRIBUTES]) {
  444. result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  445. return;
  446. }
  447. node = viewNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
  448. break;
  449. case UA_NODECLASS_METHOD:
  450. case UA_NODECLASS_UNSPECIFIED:
  451. default:
  452. result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
  453. return;
  454. }
  455. if(!node) {
  456. result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  457. return;
  458. }
  459. /* add it to the server */
  460. UA_Server_addExistingNode(server, session, node, &item->parentNodeId.nodeId,
  461. &item->referenceTypeId, result);
  462. if(result->statusCode != UA_STATUSCODE_GOOD)
  463. return;
  464. /* instantiate if it has a type */
  465. if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
  466. if (instantiationCallback != NULL)
  467. instantiationCallback->method(result->addedNodeId, item->typeDefinition.nodeId,
  468. instantiationCallback->handle);
  469. if(item->nodeClass == UA_NODECLASS_OBJECT)
  470. result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
  471. &item->typeDefinition.nodeId, instantiationCallback);
  472. else if(item->nodeClass == UA_NODECLASS_VARIABLE)
  473. result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
  474. &item->typeDefinition.nodeId, instantiationCallback);
  475. }
  476. /* if instantiation failed, remove the node */
  477. if(result->statusCode != UA_STATUSCODE_GOOD)
  478. Service_DeleteNodes_single(server, session, &result->addedNodeId, true);
  479. }
  480. void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
  481. UA_AddNodesResponse *response) {
  482. if(request->nodesToAddSize <= 0) {
  483. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  484. return;
  485. }
  486. size_t size = request->nodesToAddSize;
  487. response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
  488. if(!response->results) {
  489. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  490. return;
  491. }
  492. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  493. #ifdef _MSC_VER
  494. UA_Boolean *isExternal = UA_alloca(size);
  495. UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32)*size);
  496. #else
  497. UA_Boolean isExternal[size];
  498. UA_UInt32 indices[size];
  499. #endif
  500. memset(isExternal, false, sizeof(UA_Boolean) * size);
  501. for(size_t j = 0; j <server->externalNamespacesSize; j++) {
  502. size_t indexSize = 0;
  503. for(size_t i = 0;i < size;i++) {
  504. if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex !=
  505. server->externalNamespaces[j].index)
  506. continue;
  507. isExternal[i] = true;
  508. indices[indexSize] = i;
  509. indexSize++;
  510. }
  511. if(indexSize == 0)
  512. continue;
  513. UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
  514. ens->addNodes(ens->ensHandle, &request->requestHeader, request->nodesToAdd,
  515. indices, indexSize, response->results, response->diagnosticInfos);
  516. }
  517. #endif
  518. response->resultsSize = size;
  519. for(size_t i = 0; i < size; i++) {
  520. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  521. if(!isExternal[i])
  522. #endif
  523. Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i], NULL);
  524. }
  525. }
  526. /**************************************************/
  527. /* Add Special Nodes (not possible over the wire) */
  528. /**************************************************/
  529. UA_StatusCode UA_EXPORT
  530. UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  531. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  532. const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
  533. const UA_VariableAttributes attr, const UA_DataSource dataSource,
  534. UA_NodeId *outNewNodeId) {
  535. UA_AddNodesResult result;
  536. UA_AddNodesResult_init(&result);
  537. UA_AddNodesItem item;
  538. UA_AddNodesItem_init(&item);
  539. result.statusCode = UA_QualifiedName_copy(&browseName, &item.browseName);
  540. item.nodeClass = UA_NODECLASS_VARIABLE;
  541. result.statusCode |= UA_NodeId_copy(&parentNodeId, &item.parentNodeId.nodeId);
  542. result.statusCode |= UA_NodeId_copy(&referenceTypeId, &item.referenceTypeId);
  543. result.statusCode |= UA_NodeId_copy(&requestedNewNodeId, &item.requestedNewNodeId.nodeId);
  544. result.statusCode |= UA_NodeId_copy(&typeDefinition, &item.typeDefinition.nodeId);
  545. UA_VariableAttributes attrCopy;
  546. result.statusCode |= UA_VariableAttributes_copy(&attr, &attrCopy);
  547. if(result.statusCode != UA_STATUSCODE_GOOD) {
  548. UA_AddNodesItem_deleteMembers(&item);
  549. UA_VariableAttributes_deleteMembers(&attrCopy);
  550. return result.statusCode;
  551. }
  552. UA_VariableNode *node = UA_NodeStore_newVariableNode();
  553. if(!node) {
  554. UA_AddNodesItem_deleteMembers(&item);
  555. UA_VariableAttributes_deleteMembers(&attrCopy);
  556. return UA_STATUSCODE_BADOUTOFMEMORY;
  557. }
  558. copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
  559. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  560. node->value.dataSource = dataSource;
  561. node->accessLevel = attr.accessLevel;
  562. node->userAccessLevel = attr.userAccessLevel;
  563. node->historizing = attr.historizing;
  564. node->minimumSamplingInterval = attr.minimumSamplingInterval;
  565. node->valueRank = attr.valueRank;
  566. UA_RCU_LOCK();
  567. UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
  568. &item.referenceTypeId, &result);
  569. UA_RCU_UNLOCK();
  570. UA_AddNodesItem_deleteMembers(&item);
  571. UA_VariableAttributes_deleteMembers(&attrCopy);
  572. if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
  573. *outNewNodeId = result.addedNodeId;
  574. else
  575. UA_AddNodesResult_deleteMembers(&result);
  576. return result.statusCode;
  577. }
  578. #ifdef UA_ENABLE_METHODCALLS
  579. UA_StatusCode UA_EXPORT
  580. UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  581. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  582. const UA_QualifiedName browseName, const UA_MethodAttributes attr,
  583. UA_MethodCallback method, void *handle,
  584. size_t inputArgumentsSize, const UA_Argument* inputArguments,
  585. size_t outputArgumentsSize, const UA_Argument* outputArguments,
  586. UA_NodeId *outNewNodeId) {
  587. UA_AddNodesResult result;
  588. UA_AddNodesResult_init(&result);
  589. UA_AddNodesItem item;
  590. UA_AddNodesItem_init(&item);
  591. result.statusCode = UA_QualifiedName_copy(&browseName, &item.browseName);
  592. item.nodeClass = UA_NODECLASS_METHOD;
  593. result.statusCode |= UA_NodeId_copy(&parentNodeId, &item.parentNodeId.nodeId);
  594. result.statusCode |= UA_NodeId_copy(&referenceTypeId, &item.referenceTypeId);
  595. result.statusCode |= UA_NodeId_copy(&requestedNewNodeId, &item.requestedNewNodeId.nodeId);
  596. UA_MethodAttributes attrCopy;
  597. result.statusCode |= UA_MethodAttributes_copy(&attr, &attrCopy);
  598. if(result.statusCode != UA_STATUSCODE_GOOD) {
  599. UA_AddNodesItem_deleteMembers(&item);
  600. UA_MethodAttributes_deleteMembers(&attrCopy);
  601. return result.statusCode;
  602. }
  603. UA_MethodNode *node = UA_NodeStore_newMethodNode();
  604. if(!node) {
  605. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  606. UA_AddNodesItem_deleteMembers(&item);
  607. UA_MethodAttributes_deleteMembers(&attrCopy);
  608. return result.statusCode;
  609. }
  610. copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
  611. node->executable = attrCopy.executable;
  612. node->userExecutable = attrCopy.executable;
  613. node->attachedMethod = method;
  614. node->methodHandle = handle;
  615. UA_AddNodesItem_deleteMembers(&item);
  616. UA_MethodAttributes_deleteMembers(&attrCopy);
  617. UA_RCU_LOCK();
  618. UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
  619. &item.referenceTypeId, &result);
  620. UA_RCU_UNLOCK();
  621. if(result.statusCode != UA_STATUSCODE_GOOD)
  622. return result.statusCode;
  623. UA_ExpandedNodeId parent;
  624. UA_ExpandedNodeId_init(&parent);
  625. parent.nodeId = result.addedNodeId;
  626. const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
  627. UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
  628. inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
  629. inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
  630. inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  631. inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  632. inputArgumentsVariableNode->valueRank = 1;
  633. UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
  634. inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  635. UA_AddNodesResult inputAddRes;
  636. UA_RCU_LOCK();
  637. UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
  638. &parent.nodeId, &hasproperty, &inputAddRes);
  639. UA_RCU_UNLOCK();
  640. // todo: check if adding succeeded
  641. UA_AddNodesResult_deleteMembers(&inputAddRes);
  642. /* create OutputArguments */
  643. /* FIXME: See comment in inputArguments */
  644. UA_VariableNode *outputArgumentsVariableNode = UA_NodeStore_newVariableNode();
  645. outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
  646. outputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
  647. outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  648. outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  649. outputArgumentsVariableNode->valueRank = 1;
  650. UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
  651. outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  652. UA_AddNodesResult outputAddRes;
  653. UA_RCU_LOCK();
  654. UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
  655. &parent.nodeId, &hasproperty, &outputAddRes);
  656. UA_RCU_UNLOCK();
  657. // todo: check if adding succeeded
  658. UA_AddNodesResult_deleteMembers(&outputAddRes);
  659. if(outNewNodeId)
  660. *outNewNodeId = result.addedNodeId; // don't deleteMember the result
  661. else
  662. UA_AddNodesResult_deleteMembers(&result);
  663. return result.statusCode;
  664. }
  665. static UA_StatusCode __UA_Server_editMethodCallback(UA_Server *server, UA_Session* session, UA_Node* node, const void* handle) {
  666. const struct {
  667. UA_MethodCallback callback;
  668. void *handle;
  669. } *newCallback = handle;
  670. if (node == NULL)
  671. return UA_STATUSCODE_BADNODEIDINVALID;
  672. if (node->nodeClass != UA_NODECLASS_METHOD)
  673. return UA_STATUSCODE_BADNODECLASSINVALID;
  674. if (newCallback == NULL)
  675. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  676. UA_MethodNode *mnode = (UA_MethodNode *) node;
  677. mnode->attachedMethod = newCallback->callback;
  678. mnode->methodHandle = newCallback->handle;
  679. return 0;
  680. }
  681. UA_StatusCode UA_EXPORT
  682. UA_Server_methodNode_attachCallback(UA_Server *server, const UA_NodeId methodNodeId,
  683. UA_MethodCallback method, void *handle) {
  684. struct {
  685. UA_MethodCallback callback;
  686. void *handle;
  687. } newCallback;
  688. newCallback.callback = method;
  689. newCallback.handle = handle;
  690. UA_RCU_LOCK();
  691. UA_StatusCode retval = UA_Server_editNode(server, &adminSession, &methodNodeId,
  692. __UA_Server_editMethodCallback, &newCallback);
  693. UA_RCU_UNLOCK();
  694. return retval;
  695. }
  696. #endif
  697. /******************/
  698. /* Add References */
  699. /******************/
  700. /* Adds a one-way reference to the local nodestore */
  701. static UA_StatusCode
  702. addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, const UA_AddReferencesItem *item) {
  703. size_t i = node->referencesSize;
  704. size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
  705. UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
  706. if(!new_refs)
  707. return UA_STATUSCODE_BADOUTOFMEMORY;
  708. node->references = new_refs;
  709. UA_ReferenceNode_init(&new_refs[i]);
  710. UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId);
  711. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId);
  712. new_refs[i].isInverse = !item->isForward;
  713. if(retval == UA_STATUSCODE_GOOD)
  714. node->referencesSize = i+1;
  715. else
  716. UA_ReferenceNode_deleteMembers(&new_refs[i]);
  717. return retval;
  718. }
  719. UA_StatusCode
  720. Service_AddReferences_single(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
  721. if(item->targetServerUri.length > 0)
  722. return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
  723. /* cast away the const to loop the call through UA_Server_editNode */
  724. UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  725. (UA_EditNodeCallback)addOneWayReference,
  726. item);
  727. if(retval != UA_STATUSCODE_GOOD)
  728. return retval;
  729. UA_AddReferencesItem secondItem;
  730. secondItem = *item;
  731. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  732. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  733. secondItem.isForward = !item->isForward;
  734. retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  735. (UA_EditNodeCallback)addOneWayReference, &secondItem);
  736. // todo: remove reference if the second direction failed
  737. return retval;
  738. }
  739. void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
  740. UA_AddReferencesResponse *response) {
  741. if(request->referencesToAddSize <= 0) {
  742. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  743. return;
  744. }
  745. size_t size = request->referencesToAddSize;
  746. if(!(response->results = UA_malloc(sizeof(UA_StatusCode) * size))) {
  747. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  748. return;
  749. }
  750. response->resultsSize = size;
  751. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  752. #ifdef NO_ALLOCA
  753. UA_Boolean isExternal[size];
  754. UA_UInt32 indices[size];
  755. #else
  756. UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
  757. UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
  758. #endif /*NO_ALLOCA */
  759. memset(isExternal, false, sizeof(UA_Boolean) * size);
  760. for(size_t j = 0; j < server->externalNamespacesSize; j++) {
  761. size_t indicesSize = 0;
  762. for(size_t i = 0;i < size;i++) {
  763. if(request->referencesToAdd[i].sourceNodeId.namespaceIndex
  764. != server->externalNamespaces[j].index)
  765. continue;
  766. isExternal[i] = true;
  767. indices[indicesSize] = i;
  768. indicesSize++;
  769. }
  770. if (indicesSize == 0)
  771. continue;
  772. UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
  773. ens->addReferences(ens->ensHandle, &request->requestHeader, request->referencesToAdd,
  774. indices, indicesSize, response->results, response->diagnosticInfos);
  775. }
  776. #endif
  777. response->resultsSize = size;
  778. for(size_t i = 0; i < response->resultsSize; i++) {
  779. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  780. if(!isExternal[i])
  781. #endif
  782. Service_AddReferences_single(server, session, &request->referencesToAdd[i]);
  783. }
  784. }
  785. /****************/
  786. /* Delete Nodes */
  787. /****************/
  788. // TODO: Check consistency constraints, remove the references.
  789. UA_StatusCode
  790. Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
  791. UA_Boolean deleteReferences) {
  792. const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
  793. if(!node)
  794. return UA_STATUSCODE_BADNODEIDINVALID;
  795. if(deleteReferences == true) {
  796. UA_DeleteReferencesItem delItem;
  797. UA_DeleteReferencesItem_init(&delItem);
  798. delItem.deleteBidirectional = false;
  799. delItem.targetNodeId.nodeId = *nodeId;
  800. for(size_t i = 0; i < node->referencesSize; i++) {
  801. delItem.sourceNodeId = node->references[i].targetId.nodeId;
  802. delItem.isForward = node->references[i].isInverse;
  803. Service_DeleteReferences_single(server, session, &delItem);
  804. }
  805. }
  806. /* destroy an object before removing it */
  807. if(node->nodeClass == UA_NODECLASS_OBJECT) {
  808. /* find the object type(s) */
  809. UA_BrowseDescription bd;
  810. UA_BrowseDescription_init(&bd);
  811. bd.browseDirection = UA_BROWSEDIRECTION_INVERSE;
  812. bd.nodeId = *nodeId;
  813. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
  814. bd.includeSubtypes = true;
  815. bd.nodeClassMask = UA_NODECLASS_OBJECTTYPE;
  816. /* browse type definitions with admin rights */
  817. UA_BrowseResult result;
  818. UA_BrowseResult_init(&result);
  819. Service_Browse_single(server, &adminSession, NULL, &bd, UA_UINT32_MAX, &result);
  820. for(size_t i = 0; i < result.referencesSize; i++) {
  821. /* call the destructor */
  822. UA_ReferenceDescription *rd = &result.references[i];
  823. const UA_ObjectTypeNode *typenode =
  824. (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId);
  825. if(!typenode)
  826. continue;
  827. if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE || !typenode->lifecycleManagement.destructor)
  828. continue;
  829. /* if there are several types with lifecycle management, call all the destructors */
  830. typenode->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle);
  831. }
  832. UA_BrowseResult_deleteMembers(&result);
  833. }
  834. return UA_NodeStore_remove(server->nodestore, nodeId);
  835. }
  836. void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
  837. UA_DeleteNodesResponse *response) {
  838. if(request->nodesToDeleteSize <= 0) {
  839. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  840. return;
  841. }
  842. response->results = UA_malloc(sizeof(UA_StatusCode) * request->nodesToDeleteSize);
  843. if(!response->results) {
  844. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;;
  845. return;
  846. }
  847. response->resultsSize = request->nodesToDeleteSize;
  848. for(size_t i=0; i<request->nodesToDeleteSize; i++) {
  849. UA_DeleteNodesItem *item = &request->nodesToDelete[i];
  850. response->results[i] = Service_DeleteNodes_single(server, session, &item->nodeId,
  851. item->deleteTargetReferences);
  852. }
  853. }
  854. /*********************/
  855. /* Delete References */
  856. /*********************/
  857. static UA_StatusCode
  858. deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
  859. const UA_DeleteReferencesItem *item) {
  860. UA_Boolean edited = false;
  861. for(size_t i = node->referencesSize - 1; ; i--) {
  862. if(i > node->referencesSize)
  863. break; /* underflow after i == 0 */
  864. if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &node->references[i].targetId.nodeId))
  865. continue;
  866. if(!UA_NodeId_equal(&item->referenceTypeId, &node->references[i].referenceTypeId))
  867. continue;
  868. if(item->isForward == node->references[i].isInverse)
  869. continue;
  870. /* move the last entry to override the current position */
  871. UA_ReferenceNode_deleteMembers(&node->references[i]);
  872. node->references[i] = node->references[node->referencesSize-1];
  873. node->referencesSize--;
  874. edited = true;
  875. break;
  876. }
  877. if(!edited)
  878. return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
  879. /* we removed the last reference */
  880. if(node->referencesSize == 0 && node->references)
  881. UA_free(node->references);
  882. return UA_STATUSCODE_GOOD;;
  883. }
  884. UA_StatusCode
  885. Service_DeleteReferences_single(UA_Server *server, UA_Session *session,
  886. const UA_DeleteReferencesItem *item) {
  887. UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  888. (UA_EditNodeCallback)deleteOneWayReference, item);
  889. if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
  890. return retval;
  891. UA_DeleteReferencesItem secondItem;
  892. UA_DeleteReferencesItem_init(&secondItem);
  893. secondItem.isForward = !item->isForward;
  894. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  895. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  896. return UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  897. (UA_EditNodeCallback)deleteOneWayReference, &secondItem);
  898. }
  899. void
  900. Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
  901. UA_DeleteReferencesResponse *response) {
  902. if(request->referencesToDeleteSize <= 0) {
  903. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  904. return;
  905. }
  906. response->results = UA_malloc(sizeof(UA_StatusCode) * request->referencesToDeleteSize);
  907. if(!response->results) {
  908. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;;
  909. return;
  910. }
  911. response->resultsSize = request->referencesToDeleteSize;
  912. for(size_t i = 0; i < request->referencesToDeleteSize; i++)
  913. response->results[i] =
  914. Service_DeleteReferences_single(server, session, &request->referencesToDelete[i]);
  915. }