ua_services_nodemanagement.c 41 KB

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