ua_services_nodemanagement.c 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
  4. #include "ua_server_internal.h"
  5. #include "ua_services.h"
  6. /************************/
  7. /* Forward Declarations */
  8. /************************/
  9. static UA_StatusCode
  10. addReference(UA_Server *server, UA_Session *session,
  11. const UA_AddReferencesItem *item);
  12. static UA_StatusCode
  13. deleteReference(UA_Server *server, UA_Session *session,
  14. const UA_DeleteReferencesItem *item);
  15. static UA_StatusCode
  16. deleteNode(UA_Server *server, UA_Session *session,
  17. const UA_NodeId *nodeId, UA_Boolean deleteReferences);
  18. /**********************/
  19. /* Consistency Checks */
  20. /**********************/
  21. /* Check if the requested parent node exists, has the right node class and is
  22. * referenced with an allowed (hierarchical) reference type. For "type" nodes,
  23. * only hasSubType references are allowed. */
  24. static UA_StatusCode
  25. checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeClass,
  26. const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
  27. /* Objects do not need a parent (e.g. mandatory/optional modellingrules) */
  28. if(nodeClass == UA_NODECLASS_OBJECT && UA_NodeId_isNull(parentNodeId) &&
  29. UA_NodeId_isNull(referenceTypeId))
  30. return UA_STATUSCODE_GOOD;
  31. /* See if the parent exists */
  32. const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId);
  33. if(!parent) {
  34. UA_LOG_INFO_SESSION(server->config.logger, session,
  35. "AddNodes: Parent node not found");
  36. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  37. }
  38. /* Check the referencetype exists */
  39. const UA_ReferenceTypeNode *referenceType =
  40. (const UA_ReferenceTypeNode*)UA_NodeStore_get(server->nodestore, referenceTypeId);
  41. if(!referenceType) {
  42. UA_LOG_INFO_SESSION(server->config.logger, session,
  43. "AddNodes: Reference type to the parent not found");
  44. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  45. }
  46. /* Check if the referencetype is a reference type node */
  47. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  48. UA_LOG_INFO_SESSION(server->config.logger, session,
  49. "AddNodes: Reference type to the parent invalid");
  50. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  51. }
  52. /* Check that the reference type is not abstract */
  53. if(referenceType->isAbstract == true) {
  54. UA_LOG_INFO_SESSION(server->config.logger, session,
  55. "AddNodes: Abstract reference type to the parent not allowed");
  56. return UA_STATUSCODE_BADREFERENCENOTALLOWED;
  57. }
  58. /* Check hassubtype relation for type nodes */
  59. const UA_NodeId subtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
  60. if(nodeClass == UA_NODECLASS_DATATYPE ||
  61. nodeClass == UA_NODECLASS_VARIABLETYPE ||
  62. nodeClass == UA_NODECLASS_OBJECTTYPE ||
  63. nodeClass == UA_NODECLASS_REFERENCETYPE) {
  64. /* type needs hassubtype reference to the supertype */
  65. if(!UA_NodeId_equal(referenceTypeId, &subtypeId)) {
  66. UA_LOG_INFO_SESSION(server->config.logger, session,
  67. "AddNodes: New type node need to have a "
  68. "HasSubType reference");
  69. return UA_STATUSCODE_BADREFERENCENOTALLOWED;
  70. }
  71. /* supertype needs to be of the same node type */
  72. if(parent->nodeClass != nodeClass) {
  73. UA_LOG_INFO_SESSION(server->config.logger, session,
  74. "AddNodes: New type node needs to be of the same "
  75. "node type as the parent");
  76. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  77. }
  78. return UA_STATUSCODE_GOOD;
  79. }
  80. /* Test if the referencetype is hierarchical */
  81. const UA_NodeId hierarchicalReference =
  82. UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
  83. if(!isNodeInTree(server->nodestore, referenceTypeId,
  84. &hierarchicalReference, &subtypeId, 1)) {
  85. UA_LOG_INFO_SESSION(server->config.logger, session,
  86. "AddNodes: Reference type is not hierarchical");
  87. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  88. }
  89. return UA_STATUSCODE_GOOD;
  90. }
  91. /************/
  92. /* Add Node */
  93. /************/
  94. static void
  95. Service_AddNodes_single(UA_Server *server, UA_Session *session,
  96. const UA_AddNodesItem *item, UA_AddNodesResult *result,
  97. UA_InstantiationCallback *instantiationCallback);
  98. static UA_StatusCode
  99. copyChildNodesToNode(UA_Server *server, UA_Session *session,
  100. const UA_NodeId *sourceNodeId, const UA_NodeId *destinationNodeId,
  101. UA_InstantiationCallback *instantiationCallback);
  102. /* copy an existing variable under the given parent. then instantiate the
  103. * variable for its type */
  104. static UA_StatusCode
  105. copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
  106. const UA_NodeId *referenceType, const UA_NodeId *parent,
  107. UA_InstantiationCallback *instantiationCallback) {
  108. const UA_VariableNode *node =
  109. (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
  110. if(!node)
  111. return UA_STATUSCODE_BADNODEIDINVALID;
  112. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  113. return UA_STATUSCODE_BADNODECLASSINVALID;
  114. /* Get the current value */
  115. UA_DataValue value;
  116. UA_DataValue_init(&value);
  117. UA_StatusCode retval = readValueAttribute(server, node, &value);
  118. if(retval != UA_STATUSCODE_GOOD)
  119. return retval;
  120. /* Prepare the variable description */
  121. UA_VariableAttributes attr;
  122. UA_VariableAttributes_init(&attr);
  123. attr.displayName = node->displayName;
  124. attr.description = node->description;
  125. attr.writeMask = node->writeMask;
  126. attr.userWriteMask = node->userWriteMask;
  127. attr.value = value.value;
  128. attr.dataType = node->dataType;
  129. attr.valueRank = node->valueRank;
  130. attr.arrayDimensionsSize = node->arrayDimensionsSize;
  131. attr.arrayDimensions = node->arrayDimensions;
  132. attr.accessLevel = node->accessLevel;
  133. attr.userAccessLevel = node->userAccessLevel;
  134. attr.minimumSamplingInterval = node->minimumSamplingInterval;
  135. attr.historizing = node->historizing;
  136. UA_AddNodesItem item;
  137. UA_AddNodesItem_init(&item);
  138. item.nodeClass = UA_NODECLASS_VARIABLE;
  139. item.parentNodeId.nodeId = *parent;
  140. item.referenceTypeId = *referenceType;
  141. item.browseName = node->browseName;
  142. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  143. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
  144. item.nodeAttributes.content.decoded.data = &attr;
  145. const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)getNodeType(server, (const UA_Node*)node);
  146. if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE || vt->isAbstract) {
  147. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  148. goto cleanup;
  149. }
  150. item.typeDefinition.nodeId = vt->nodeId;
  151. /* Add the variable and instantiate the children */
  152. UA_AddNodesResult res;
  153. UA_AddNodesResult_init(&res);
  154. Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
  155. if(res.statusCode != UA_STATUSCODE_GOOD) {
  156. retval = res.statusCode;
  157. goto cleanup;
  158. }
  159. retval = copyChildNodesToNode(server, session, &node->nodeId,
  160. &res.addedNodeId, instantiationCallback);
  161. if(retval == UA_STATUSCODE_GOOD && instantiationCallback)
  162. instantiationCallback->method(res.addedNodeId, node->nodeId,
  163. instantiationCallback->handle);
  164. UA_NodeId_deleteMembers(&res.addedNodeId);
  165. cleanup:
  166. if(value.hasValue && value.value.storageType == UA_VARIANT_DATA)
  167. UA_Variant_deleteMembers(&value.value);
  168. return retval;
  169. }
  170. /* Copy an existing object under the given parent. Then instantiate for all
  171. * hastypedefinitions of the original version. */
  172. static UA_StatusCode
  173. copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *object,
  174. const UA_NodeId *referenceType, const UA_NodeId *parent,
  175. UA_InstantiationCallback *instantiationCallback) {
  176. const UA_ObjectNode *node =
  177. (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, object);
  178. if(!node)
  179. return UA_STATUSCODE_BADNODEIDINVALID;
  180. if(node->nodeClass != UA_NODECLASS_OBJECT)
  181. return UA_STATUSCODE_BADNODECLASSINVALID;
  182. /* Prepare the item */
  183. UA_ObjectAttributes attr;
  184. UA_ObjectAttributes_init(&attr);
  185. attr.displayName = node->displayName;
  186. attr.description = node->description;
  187. attr.writeMask = node->writeMask;
  188. attr.userWriteMask = node->userWriteMask;
  189. attr.eventNotifier = node->eventNotifier;
  190. UA_AddNodesItem item;
  191. UA_AddNodesItem_init(&item);
  192. item.nodeClass = UA_NODECLASS_OBJECT;
  193. item.parentNodeId.nodeId = *parent;
  194. item.referenceTypeId = *referenceType;
  195. item.browseName = node->browseName;
  196. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  197. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES];
  198. item.nodeAttributes.content.decoded.data = &attr;
  199. const UA_ObjectTypeNode *objtype = (const UA_ObjectTypeNode*)getNodeType(server, (const UA_Node*)node);
  200. if(!objtype || objtype->nodeClass != UA_NODECLASS_OBJECTTYPE || objtype->isAbstract)
  201. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  202. item.typeDefinition.nodeId = objtype->nodeId;
  203. /* add the new object */
  204. UA_AddNodesResult res;
  205. UA_AddNodesResult_init(&res);
  206. Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
  207. if(res.statusCode != UA_STATUSCODE_GOOD)
  208. return res.statusCode;
  209. /* Copy any aggregated/nested variables/methods/subobjects this object contains
  210. * These objects may not be part of the nodes type. */
  211. UA_StatusCode retval = copyChildNodesToNode(server, session, &node->nodeId,
  212. &res.addedNodeId, instantiationCallback);
  213. if(retval == UA_STATUSCODE_GOOD && instantiationCallback)
  214. instantiationCallback->method(res.addedNodeId, node->nodeId,
  215. instantiationCallback->handle);
  216. UA_NodeId_deleteMembers(&res.addedNodeId);
  217. return retval;
  218. }
  219. static UA_StatusCode
  220. setObjectInstanceHandle(UA_Server *server, UA_Session *session,
  221. UA_ObjectNode* node, void * (*constructor)(const UA_NodeId instance)) {
  222. if(node->nodeClass != UA_NODECLASS_OBJECT)
  223. return UA_STATUSCODE_BADNODECLASSINVALID;
  224. if(!node->instanceHandle)
  225. node->instanceHandle = constructor(node->nodeId);
  226. return UA_STATUSCODE_GOOD;
  227. }
  228. static UA_StatusCode
  229. instantiateNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
  230. UA_NodeClass nodeClass, const UA_NodeId *typeId,
  231. UA_InstantiationCallback *instantiationCallback) {
  232. /* see if the type node is correct */
  233. const UA_Node *typenode = UA_NodeStore_get(server->nodestore, typeId);
  234. if(!typenode)
  235. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  236. if(nodeClass == UA_NODECLASS_VARIABLE) {
  237. if(typenode->nodeClass != UA_NODECLASS_VARIABLETYPE ||
  238. ((const UA_VariableTypeNode*)typenode)->isAbstract)
  239. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  240. } else if(nodeClass == UA_NODECLASS_OBJECT) {
  241. if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE ||
  242. ((const UA_ObjectTypeNode*)typenode)->isAbstract)
  243. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  244. } else {
  245. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  246. }
  247. /* Get the hierarchy of the type and all its supertypes */
  248. UA_NodeId *hierarchy = NULL;
  249. size_t hierarchySize = 0;
  250. UA_StatusCode retval =
  251. getTypeHierarchy(server->nodestore, typenode, true, &hierarchy, &hierarchySize);
  252. if(retval != UA_STATUSCODE_GOOD)
  253. return retval;
  254. /* Copy members of the type and supertypes */
  255. for(size_t i = 0; i < hierarchySize; ++i)
  256. retval |= copyChildNodesToNode(server, session, &hierarchy[i], nodeId, instantiationCallback);
  257. UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
  258. if(retval != UA_STATUSCODE_GOOD)
  259. return retval;
  260. /* Call the object constructor */
  261. if(typenode->nodeClass == UA_NODECLASS_OBJECTTYPE) {
  262. const UA_ObjectLifecycleManagement *olm =
  263. &((const UA_ObjectTypeNode*)typenode)->lifecycleManagement;
  264. if(olm->constructor)
  265. UA_Server_editNode(server, session, nodeId,
  266. (UA_EditNodeCallback)setObjectInstanceHandle,
  267. olm->constructor);
  268. }
  269. /* Add a hasType reference */
  270. UA_AddReferencesItem addref;
  271. UA_AddReferencesItem_init(&addref);
  272. addref.sourceNodeId = *nodeId;
  273. addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  274. addref.isForward = true;
  275. addref.targetNodeId.nodeId = *typeId;
  276. return addReference(server, session, &addref);
  277. }
  278. /* Search for an instance of "browseName" in node searchInstance
  279. * Used during copyChildNodes to find overwritable/mergable nodes */
  280. static UA_StatusCode
  281. instanceFindAggregateByBrowsename(UA_Server *server, UA_Session *session,
  282. const UA_NodeId *searchInstance,
  283. const UA_QualifiedName *browseName,
  284. UA_NodeId *outInstanceNodeId) {
  285. UA_BrowseDescription bd;
  286. UA_BrowseDescription_init(&bd);
  287. bd.nodeId = *searchInstance;
  288. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  289. bd.includeSubtypes = true;
  290. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  291. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  292. bd.resultMask = UA_BROWSERESULTMASK_NODECLASS | UA_BROWSERESULTMASK_BROWSENAME;
  293. UA_BrowseResult br;
  294. UA_BrowseResult_init(&br);
  295. Service_Browse_single(server, session, NULL, &bd, 0, &br);
  296. if(br.statusCode != UA_STATUSCODE_GOOD)
  297. return br.statusCode;
  298. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  299. for(size_t i = 0; i < br.referencesSize; ++i) {
  300. UA_ReferenceDescription *rd = &br.references[i];
  301. if(rd->browseName.namespaceIndex == browseName->namespaceIndex &&
  302. UA_String_equal(&rd->browseName.name, &browseName->name)) {
  303. retval = UA_NodeId_copy(&rd->nodeId.nodeId, outInstanceNodeId);
  304. break;
  305. }
  306. }
  307. UA_BrowseResult_deleteMembers(&br);
  308. return retval;
  309. }
  310. static UA_Boolean
  311. mandatoryChild(UA_Server *server, UA_Session *session, const UA_NodeId *childNodeId) {
  312. const UA_NodeId mandatoryId = UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY);
  313. const UA_NodeId hasModellingRuleId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE);
  314. /* Get the child */
  315. const UA_Node *child = UA_NodeStore_get(server->nodestore, childNodeId);
  316. if(!child)
  317. return false;
  318. /* Look for the reference making the child mandatory */
  319. for(size_t i = 0; i < child->referencesSize; ++i) {
  320. UA_ReferenceNode *ref = &child->references[i];
  321. if(!UA_NodeId_equal(&hasModellingRuleId, &ref->referenceTypeId))
  322. continue;
  323. if(!UA_NodeId_equal(&mandatoryId, &ref->targetId.nodeId))
  324. continue;
  325. if(ref->isInverse)
  326. continue;
  327. return true;
  328. }
  329. return false;
  330. }
  331. /* Copy any children of Node sourceNodeId to another node destinationNodeId
  332. * Used at 2 places:
  333. * (1) During instantiation, when any children of the Type are copied
  334. * (2) During instantiation to copy any *nested* instances to the new node
  335. * (2.1) Might call instantiation of a type first
  336. * (2.2) *Should* then overwrite nested contents in definition --> this scenario is currently not handled!
  337. */
  338. static UA_StatusCode
  339. copyChildNodesToNode(UA_Server* server, UA_Session* session,
  340. const UA_NodeId* sourceNodeId, const UA_NodeId* destinationNodeId,
  341. UA_InstantiationCallback* instantiationCallback) {
  342. /* Browse to get all children */
  343. UA_BrowseDescription bd;
  344. UA_BrowseDescription_init(&bd);
  345. bd.nodeId = *sourceNodeId;
  346. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  347. bd.includeSubtypes = true;
  348. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  349. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  350. bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS |
  351. UA_BROWSERESULTMASK_BROWSENAME;
  352. UA_BrowseResult br;
  353. UA_BrowseResult_init(&br);
  354. Service_Browse_single(server, session, NULL, &bd, 0, &br);
  355. if(br.statusCode != UA_STATUSCODE_GOOD)
  356. return br.statusCode;
  357. /* Copy all children */
  358. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  359. UA_NodeId existingChild = UA_NODEID_NULL;
  360. for(size_t i = 0; i < br.referencesSize; ++i) {
  361. UA_ReferenceDescription *rd = &br.references[i];
  362. /* Is the child mandatory? If not, skip */
  363. if(!mandatoryChild(server, session, &rd->nodeId.nodeId))
  364. continue;
  365. /* TODO: If a child is optional, check whether optional children that
  366. * were manually added fit the constraints. */
  367. /* Check for deduplication */
  368. retval = instanceFindAggregateByBrowsename(server, session, destinationNodeId,
  369. &rd->browseName, &existingChild);
  370. if(retval != UA_STATUSCODE_GOOD)
  371. break;
  372. if(UA_NodeId_equal(&UA_NODEID_NULL, &existingChild)) {
  373. /* New node in child */
  374. if(rd->nodeClass == UA_NODECLASS_METHOD) {
  375. /* add a reference to the method in the objecttype */
  376. UA_AddReferencesItem newItem;
  377. UA_AddReferencesItem_init(&newItem);
  378. newItem.sourceNodeId = *destinationNodeId;
  379. newItem.referenceTypeId = rd->referenceTypeId;
  380. newItem.isForward = true;
  381. newItem.targetNodeId = rd->nodeId;
  382. newItem.targetNodeClass = UA_NODECLASS_METHOD;
  383. retval = addReference(server, session, &newItem);
  384. } else if(rd->nodeClass == UA_NODECLASS_VARIABLE)
  385. retval = copyExistingVariable(server, session, &rd->nodeId.nodeId,
  386. &rd->referenceTypeId, destinationNodeId,
  387. instantiationCallback);
  388. else if(rd->nodeClass == UA_NODECLASS_OBJECT)
  389. retval = copyExistingObject(server, session, &rd->nodeId.nodeId,
  390. &rd->referenceTypeId, destinationNodeId,
  391. instantiationCallback);
  392. } else {
  393. /* Preexistent node in child
  394. * General strategy if we meet an already existing node:
  395. * - Preexistent variable contents always 'win' overwriting anything
  396. * supertypes would instantiate
  397. * - Always copy contents of template *into* existant node (merge
  398. * contents of e.g. Folders like ParameterSet) */
  399. if(rd->nodeClass == UA_NODECLASS_METHOD) {
  400. /* Do nothing, existent method wins */
  401. } else if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
  402. rd->nodeClass == UA_NODECLASS_OBJECT) {
  403. if(!UA_NodeId_equal(&rd->nodeId.nodeId, &existingChild))
  404. retval = copyChildNodesToNode(server, session, &rd->nodeId.nodeId,
  405. &existingChild, instantiationCallback);
  406. }
  407. UA_NodeId_deleteMembers(&existingChild);
  408. }
  409. if(retval != UA_STATUSCODE_GOOD)
  410. break;
  411. }
  412. UA_BrowseResult_deleteMembers(&br);
  413. return retval;
  414. }
  415. UA_StatusCode
  416. Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
  417. const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
  418. const UA_NodeId *typeDefinition,
  419. UA_InstantiationCallback *instantiationCallback,
  420. UA_NodeId *addedNodeId) {
  421. UA_ASSERT_RCU_LOCKED();
  422. /* Check the namespaceindex */
  423. if(node->nodeId.namespaceIndex >= server->namespacesSize) {
  424. UA_LOG_INFO_SESSION(server->config.logger, session, "AddNodes: Namespace invalid");
  425. UA_NodeStore_deleteNode(node);
  426. return UA_STATUSCODE_BADNODEIDINVALID;
  427. }
  428. /* Check the reference to the parent */
  429. UA_StatusCode retval = checkParentReference(server, session, node->nodeClass,
  430. parentNodeId, referenceTypeId);
  431. if(retval != UA_STATUSCODE_GOOD) {
  432. UA_LOG_INFO_SESSION(server->config.logger, session,
  433. "AddNodes: Checking the reference to the parent returned "
  434. "error code %s", UA_StatusCode_name(retval));
  435. UA_NodeStore_deleteNode(node);
  436. return retval;
  437. }
  438. /* Add the node to the nodestore */
  439. retval = UA_NodeStore_insert(server->nodestore, node);
  440. if(retval != UA_STATUSCODE_GOOD) {
  441. UA_LOG_INFO_SESSION(server->config.logger, session,
  442. "AddNodes: Node could not be added to the nodestore "
  443. "with error code %s", UA_StatusCode_name(retval));
  444. return retval;
  445. }
  446. /* Copy the nodeid if needed */
  447. if(addedNodeId) {
  448. retval = UA_NodeId_copy(&node->nodeId, addedNodeId);
  449. if(retval != UA_STATUSCODE_GOOD) {
  450. UA_LOG_INFO_SESSION(server->config.logger, session,
  451. "AddNodes: Could not copy the nodeid");
  452. goto remove_node;
  453. }
  454. }
  455. /* Hierarchical reference back to the parent */
  456. if(!UA_NodeId_isNull(parentNodeId)) {
  457. UA_AddReferencesItem item;
  458. UA_AddReferencesItem_init(&item);
  459. item.sourceNodeId = node->nodeId;
  460. item.referenceTypeId = *referenceTypeId;
  461. item.isForward = false;
  462. item.targetNodeId.nodeId = *parentNodeId;
  463. retval = addReference(server, session, &item);
  464. if(retval != UA_STATUSCODE_GOOD) {
  465. UA_LOG_INFO_SESSION(server->config.logger, session,
  466. "AddNodes: Could not add the reference to the parent"
  467. "with error code %s", UA_StatusCode_name(retval));
  468. goto remove_node;
  469. }
  470. }
  471. /* Fall back to a default typedefinition for variables and objects */
  472. const UA_NodeId basedatavariabletype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
  473. const UA_NodeId baseobjecttype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  474. if(node->nodeClass == UA_NODECLASS_VARIABLE ||
  475. node->nodeClass == UA_NODECLASS_OBJECT) {
  476. if(!typeDefinition || UA_NodeId_isNull(typeDefinition)) {
  477. if(node->nodeClass == UA_NODECLASS_VARIABLE)
  478. typeDefinition = &basedatavariabletype;
  479. else
  480. typeDefinition = &baseobjecttype;
  481. }
  482. /* Instantiate variables and objects */
  483. retval = instantiateNode(server, session, &node->nodeId, node->nodeClass,
  484. typeDefinition, instantiationCallback);
  485. if(retval != UA_STATUSCODE_GOOD) {
  486. UA_LOG_INFO_SESSION(server->config.logger, session,
  487. "AddNodes: Could not instantiate the node with"
  488. "error code %s", UA_StatusCode_name(retval));
  489. goto remove_node;
  490. }
  491. }
  492. /* Custom callback */
  493. if(instantiationCallback)
  494. instantiationCallback->method(node->nodeId, *typeDefinition,
  495. instantiationCallback->handle);
  496. return UA_STATUSCODE_GOOD;
  497. remove_node:
  498. deleteNode(server, &adminSession, &node->nodeId, true);
  499. return retval;
  500. }
  501. /*******************************************/
  502. /* Create nodes from attribute description */
  503. /*******************************************/
  504. static UA_StatusCode
  505. copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item,
  506. const UA_NodeAttributes *attr) {
  507. UA_StatusCode retval;
  508. retval = UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
  509. retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
  510. retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
  511. retval |= UA_LocalizedText_copy(&attr->description, &node->description);
  512. node->writeMask = attr->writeMask;
  513. node->userWriteMask = attr->userWriteMask;
  514. return retval;
  515. }
  516. static UA_StatusCode
  517. copyCommonVariableAttributes(UA_Server *server, UA_VariableNode *node,
  518. const UA_AddNodesItem *item,
  519. const UA_VariableAttributes *attr) {
  520. const UA_NodeId basevartype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE);
  521. const UA_NodeId basedatavartype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
  522. const UA_NodeId *typeDef = &item->typeDefinition.nodeId;
  523. if(UA_NodeId_isNull(typeDef)) /* workaround when the variabletype is undefined */
  524. typeDef = &basedatavartype;
  525. /* Make sure we can instantiate the basetypes themselves */
  526. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  527. if(UA_NodeId_equal(&node->nodeId, &basevartype) ||
  528. UA_NodeId_equal(&node->nodeId, &basedatavartype)) {
  529. node->dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
  530. node->valueRank = -2;
  531. return retval;
  532. }
  533. const UA_VariableTypeNode *vt =
  534. (const UA_VariableTypeNode*)UA_NodeStore_get(server->nodestore, typeDef);
  535. if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE)
  536. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  537. if(node->nodeClass == UA_NODECLASS_VARIABLE && vt->isAbstract)
  538. return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  539. /* Set the datatype */
  540. if(!UA_NodeId_isNull(&attr->dataType))
  541. retval = writeDataTypeAttribute(server, node, &attr->dataType, &vt->dataType);
  542. else /* workaround common error where the datatype is left as NA_NODEID_NULL */
  543. retval = UA_NodeId_copy(&vt->dataType, &node->dataType);
  544. if(retval != UA_STATUSCODE_GOOD)
  545. return retval;
  546. /* Set the array dimensions. Check only against the vt. */
  547. retval = compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions,
  548. attr->arrayDimensionsSize, attr->arrayDimensions);
  549. if(retval == UA_STATUSCODE_GOOD) {
  550. retval = UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
  551. (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
  552. }
  553. if(retval != UA_STATUSCODE_GOOD) {
  554. UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
  555. "Array dimensions incompatible with the VariableType "
  556. "with error code %s", UA_StatusCode_name(retval));
  557. return retval;
  558. }
  559. node->arrayDimensionsSize = attr->arrayDimensionsSize;
  560. /* Set the valuerank */
  561. if(attr->valueRank != 0 || !UA_Variant_isScalar(&attr->value))
  562. retval = writeValueRankAttribute(server, node, attr->valueRank, vt->valueRank);
  563. else /* workaround common error where the valuerank is left as 0 */
  564. node->valueRank = vt->valueRank;
  565. if(retval != UA_STATUSCODE_GOOD) {
  566. UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
  567. "Value Rank incompatible with the VariableType "
  568. "with error code %s", UA_StatusCode_name(retval));
  569. return retval;
  570. }
  571. /* Set the value */
  572. UA_DataValue value;
  573. UA_DataValue_init(&value);
  574. value.hasValue = true;
  575. value.value = attr->value;
  576. value.value.storageType = UA_VARIANT_DATA_NODELETE;
  577. /* Use the default value from the vt if none is defined */
  578. if(!value.value.type) {
  579. retval = readValueAttribute(server, (const UA_VariableNode*)vt, &value);
  580. UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
  581. "Could not read the value of the variable type "
  582. "with error code %s", UA_StatusCode_name(retval));
  583. if(retval != UA_STATUSCODE_GOOD)
  584. return retval;
  585. }
  586. /* Write the value to the node */
  587. retval = writeValueAttribute(server, node, &value, NULL);
  588. if(retval != UA_STATUSCODE_GOOD) {
  589. UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
  590. "Could not set the value of the new node "
  591. "with error code %s", UA_StatusCode_name(retval));
  592. }
  593. UA_DataValue_deleteMembers(&value);
  594. return retval;
  595. }
  596. static UA_StatusCode
  597. copyVariableNodeAttributes(UA_Server *server, UA_VariableNode *vnode,
  598. const UA_AddNodesItem *item,
  599. const UA_VariableAttributes *attr) {
  600. vnode->accessLevel = attr->accessLevel;
  601. vnode->userAccessLevel = attr->userAccessLevel;
  602. vnode->historizing = attr->historizing;
  603. vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
  604. return copyCommonVariableAttributes(server, vnode, item, attr);
  605. }
  606. static UA_StatusCode
  607. copyVariableTypeNodeAttributes(UA_Server *server, UA_VariableTypeNode *vtnode,
  608. const UA_AddNodesItem *item,
  609. const UA_VariableTypeAttributes *attr) {
  610. vtnode->isAbstract = attr->isAbstract;
  611. return copyCommonVariableAttributes(server, (UA_VariableNode*)vtnode, item,
  612. (const UA_VariableAttributes*)attr);
  613. }
  614. static UA_StatusCode
  615. copyObjectNodeAttributes(UA_ObjectNode *onode, const UA_ObjectAttributes *attr) {
  616. onode->eventNotifier = attr->eventNotifier;
  617. return UA_STATUSCODE_GOOD;
  618. }
  619. static UA_StatusCode
  620. copyReferenceTypeNodeAttributes(UA_ReferenceTypeNode *rtnode,
  621. const UA_ReferenceTypeAttributes *attr) {
  622. rtnode->isAbstract = attr->isAbstract;
  623. rtnode->symmetric = attr->symmetric;
  624. return UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
  625. }
  626. static UA_StatusCode
  627. copyObjectTypeNodeAttributes(UA_ObjectTypeNode *otnode,
  628. const UA_ObjectTypeAttributes *attr) {
  629. otnode->isAbstract = attr->isAbstract;
  630. return UA_STATUSCODE_GOOD;
  631. }
  632. static UA_StatusCode
  633. copyViewNodeAttributes(UA_ViewNode *vnode, const UA_ViewAttributes *attr) {
  634. vnode->containsNoLoops = attr->containsNoLoops;
  635. vnode->eventNotifier = attr->eventNotifier;
  636. return UA_STATUSCODE_GOOD;
  637. }
  638. static UA_StatusCode
  639. copyDataTypeNodeAttributes(UA_DataTypeNode *dtnode,
  640. const UA_DataTypeAttributes *attr) {
  641. dtnode->isAbstract = attr->isAbstract;
  642. return UA_STATUSCODE_GOOD;
  643. }
  644. #define CHECK_ATTRIBUTES(TYPE) \
  645. if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_##TYPE]) { \
  646. retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; \
  647. break; \
  648. }
  649. static UA_StatusCode
  650. createNodeFromAttributes(UA_Server *server, const UA_AddNodesItem *item, UA_Node **newNode) {
  651. /* Check that we can read the attributes */
  652. if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
  653. !item->nodeAttributes.content.decoded.type)
  654. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  655. /* Create the node */
  656. // todo: error case where the nodeclass is faulty
  657. void *node = UA_NodeStore_newNode(item->nodeClass);
  658. if(!node)
  659. return UA_STATUSCODE_BADOUTOFMEMORY;
  660. /* Copy the attributes into the node */
  661. void *data = item->nodeAttributes.content.decoded.data;
  662. UA_StatusCode retval = copyStandardAttributes(node, item, data);
  663. switch(item->nodeClass) {
  664. case UA_NODECLASS_OBJECT:
  665. CHECK_ATTRIBUTES(OBJECTATTRIBUTES);
  666. retval |= copyObjectNodeAttributes(node, data);
  667. break;
  668. case UA_NODECLASS_VARIABLE:
  669. CHECK_ATTRIBUTES(VARIABLEATTRIBUTES);
  670. retval |= copyVariableNodeAttributes(server, node, item, data);
  671. break;
  672. case UA_NODECLASS_OBJECTTYPE:
  673. CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES);
  674. retval |= copyObjectTypeNodeAttributes(node, data);
  675. break;
  676. case UA_NODECLASS_VARIABLETYPE:
  677. CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES);
  678. retval |= copyVariableTypeNodeAttributes(server, node, item, data);
  679. break;
  680. case UA_NODECLASS_REFERENCETYPE:
  681. CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES);
  682. retval |= copyReferenceTypeNodeAttributes(node, data);
  683. break;
  684. case UA_NODECLASS_DATATYPE:
  685. CHECK_ATTRIBUTES(DATATYPEATTRIBUTES);
  686. retval |= copyDataTypeNodeAttributes(node, data);
  687. break;
  688. case UA_NODECLASS_VIEW:
  689. CHECK_ATTRIBUTES(VIEWATTRIBUTES);
  690. retval |= copyViewNodeAttributes(node, data);
  691. break;
  692. case UA_NODECLASS_METHOD:
  693. case UA_NODECLASS_UNSPECIFIED:
  694. default:
  695. retval = UA_STATUSCODE_BADNODECLASSINVALID;
  696. }
  697. if(retval == UA_STATUSCODE_GOOD)
  698. *newNode = node;
  699. else
  700. UA_NodeStore_deleteNode(node);
  701. return retval;
  702. }
  703. static void
  704. Service_AddNodes_single(UA_Server *server, UA_Session *session,
  705. const UA_AddNodesItem *item, UA_AddNodesResult *result,
  706. UA_InstantiationCallback *instantiationCallback) {
  707. /* Create the node from the attributes*/
  708. UA_Node *node = NULL;
  709. result->statusCode = createNodeFromAttributes(server, item, &node);
  710. if(result->statusCode != UA_STATUSCODE_GOOD) {
  711. UA_LOG_INFO_SESSION(server->config.logger, session,
  712. "Could not add node with error code %s",
  713. UA_StatusCode_name(result->statusCode));
  714. return;
  715. }
  716. /* Run consistency checks and add the node */
  717. UA_assert(node != NULL);
  718. result->statusCode = Service_AddNodes_existing(server, session, node, &item->parentNodeId.nodeId,
  719. &item->referenceTypeId, &item->typeDefinition.nodeId,
  720. instantiationCallback, &result->addedNodeId);
  721. if(result->statusCode != UA_STATUSCODE_GOOD) {
  722. UA_LOG_INFO_SESSION(server->config.logger, session,
  723. "Could not add node with error code %s",
  724. UA_StatusCode_name(result->statusCode));
  725. }
  726. }
  727. void Service_AddNodes(UA_Server *server, UA_Session *session,
  728. const UA_AddNodesRequest *request,
  729. UA_AddNodesResponse *response) {
  730. UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing AddNodesRequest");
  731. if(request->nodesToAddSize <= 0) {
  732. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  733. return;
  734. }
  735. size_t size = request->nodesToAddSize;
  736. response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
  737. if(!response->results) {
  738. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  739. return;
  740. }
  741. response->resultsSize = size;
  742. for(size_t i = 0; i < size; ++i) {
  743. Service_AddNodes_single(server, session, &request->nodesToAdd[i],
  744. &response->results[i], NULL);
  745. }
  746. }
  747. UA_StatusCode
  748. __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
  749. const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
  750. const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
  751. const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
  752. const UA_DataType *attributeType,
  753. UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
  754. /* prepare the item */
  755. UA_AddNodesItem item;
  756. UA_AddNodesItem_init(&item);
  757. item.parentNodeId.nodeId = parentNodeId;
  758. item.referenceTypeId = referenceTypeId;
  759. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  760. item.browseName = browseName;
  761. item.nodeClass = nodeClass;
  762. item.typeDefinition.nodeId = typeDefinition;
  763. item.nodeAttributes = (UA_ExtensionObject){
  764. .encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE,
  765. .content.decoded = {attributeType, (void*)(uintptr_t)attr}};
  766. /* run the service */
  767. UA_AddNodesResult result;
  768. UA_AddNodesResult_init(&result);
  769. UA_RCU_LOCK();
  770. Service_AddNodes_single(server, &adminSession, &item, &result, instantiationCallback);
  771. UA_RCU_UNLOCK();
  772. /* prepare the output */
  773. if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
  774. *outNewNodeId = result.addedNodeId;
  775. else
  776. UA_NodeId_deleteMembers(&result.addedNodeId);
  777. return result.statusCode;
  778. }
  779. /**************************************************/
  780. /* Add Special Nodes (not possible over the wire) */
  781. /**************************************************/
  782. UA_StatusCode
  783. UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  784. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  785. const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
  786. const UA_VariableAttributes attr, const UA_DataSource dataSource,
  787. UA_NodeId *outNewNodeId) {
  788. /* Create the new node */
  789. UA_VariableNode *node = UA_NodeStore_newVariableNode();
  790. if(!node)
  791. return UA_STATUSCODE_BADOUTOFMEMORY;
  792. /* Read the current value (to do typechecking) */
  793. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  794. UA_VariableAttributes editAttr = attr;
  795. UA_DataValue value;
  796. UA_DataValue_init(&value);
  797. if(dataSource.read)
  798. retval = dataSource.read(dataSource.handle, requestedNewNodeId,
  799. false, NULL, &value);
  800. else
  801. retval = UA_STATUSCODE_BADTYPEMISMATCH;
  802. editAttr.value = value.value;
  803. if(retval != UA_STATUSCODE_GOOD) {
  804. UA_NodeStore_deleteNode((UA_Node*)node);
  805. return retval;
  806. }
  807. /* Copy attributes into node */
  808. UA_RCU_LOCK();
  809. UA_AddNodesItem item;
  810. UA_AddNodesItem_init(&item);
  811. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  812. item.browseName = browseName;
  813. item.typeDefinition.nodeId = typeDefinition;
  814. item.parentNodeId.nodeId = parentNodeId;
  815. retval |= copyStandardAttributes((UA_Node*)node, &item, (const UA_NodeAttributes*)&editAttr);
  816. retval |= copyVariableNodeAttributes(server, node, &item, &editAttr);
  817. UA_DataValue_deleteMembers(&node->value.data.value);
  818. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  819. node->value.dataSource = dataSource;
  820. UA_DataValue_deleteMembers(&value);
  821. if(retval != UA_STATUSCODE_GOOD) {
  822. UA_NodeStore_deleteNode((UA_Node*)node);
  823. UA_RCU_UNLOCK();
  824. return retval;
  825. }
  826. /* Add the node */
  827. UA_AddNodesResult result;
  828. UA_AddNodesResult_init(&result);
  829. retval = Service_AddNodes_existing(server, &adminSession, (UA_Node*)node, &parentNodeId,
  830. &referenceTypeId, &typeDefinition, NULL, outNewNodeId);
  831. UA_RCU_UNLOCK();
  832. return retval;
  833. }
  834. #ifdef UA_ENABLE_METHODCALLS
  835. UA_StatusCode
  836. UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  837. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  838. const UA_QualifiedName browseName, const UA_MethodAttributes attr,
  839. UA_MethodCallback method, void *handle,
  840. size_t inputArgumentsSize, const UA_Argument* inputArguments,
  841. size_t outputArgumentsSize, const UA_Argument* outputArguments,
  842. UA_NodeId *outNewNodeId) {
  843. UA_MethodNode *node = UA_NodeStore_newMethodNode();
  844. if(!node)
  845. return UA_STATUSCODE_BADOUTOFMEMORY;
  846. UA_AddNodesItem item;
  847. UA_AddNodesItem_init(&item);
  848. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  849. item.browseName = browseName;
  850. copyStandardAttributes((UA_Node*)node, &item, (const UA_NodeAttributes*)&attr);
  851. node->executable = attr.executable;
  852. node->userExecutable = attr.userExecutable;
  853. node->attachedMethod = method;
  854. node->methodHandle = handle;
  855. /* Add the node */
  856. UA_NodeId newMethodId;
  857. UA_NodeId_init(&newMethodId);
  858. UA_RCU_LOCK();
  859. UA_StatusCode retval = Service_AddNodes_existing(server, &adminSession, (UA_Node*)node, &parentNodeId,
  860. &referenceTypeId, &UA_NODEID_NULL, NULL, &newMethodId);
  861. UA_RCU_UNLOCK();
  862. if(retval != UA_STATUSCODE_GOOD)
  863. return retval;
  864. const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
  865. const UA_NodeId propertytype = UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE);
  866. if(inputArgumentsSize > 0) {
  867. UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
  868. inputArgumentsVariableNode->nodeId.namespaceIndex = newMethodId.namespaceIndex;
  869. inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0, "InputArguments");
  870. inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  871. inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
  872. inputArgumentsVariableNode->valueRank = 1;
  873. /* UAExpert creates a monitoreditem on inputarguments ... */
  874. inputArgumentsVariableNode->minimumSamplingInterval = 10000.0f;
  875. //TODO: 0.3 work item: the addMethodNode API does not have the possibility to set nodeIDs
  876. //actually we need to change the signature to pass UA_NS0ID_SERVER_GETMONITOREDITEMS_INPUTARGUMENTS
  877. //and UA_NS0ID_SERVER_GETMONITOREDITEMS_OUTPUTARGUMENTS into the function :/
  878. if(newMethodId.namespaceIndex == 0 &&
  879. newMethodId.identifierType == UA_NODEIDTYPE_NUMERIC &&
  880. newMethodId.identifier.numeric == UA_NS0ID_SERVER_GETMONITOREDITEMS) {
  881. inputArgumentsVariableNode->nodeId =
  882. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS_INPUTARGUMENTS);
  883. }
  884. UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.data.value.value,
  885. inputArguments, inputArgumentsSize,
  886. &UA_TYPES[UA_TYPES_ARGUMENT]);
  887. inputArgumentsVariableNode->value.data.value.hasValue = true;
  888. UA_RCU_LOCK();
  889. // todo: check if adding succeeded
  890. Service_AddNodes_existing(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
  891. &newMethodId, &hasproperty, &propertytype, NULL, NULL);
  892. UA_RCU_UNLOCK();
  893. }
  894. if(outputArgumentsSize > 0) {
  895. /* create OutputArguments */
  896. UA_VariableNode *outputArgumentsVariableNode = UA_NodeStore_newVariableNode();
  897. outputArgumentsVariableNode->nodeId.namespaceIndex = newMethodId.namespaceIndex;
  898. outputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0, "OutputArguments");
  899. outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  900. outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
  901. outputArgumentsVariableNode->valueRank = 1;
  902. //FIXME: comment in line 882
  903. if(newMethodId.namespaceIndex == 0 &&
  904. newMethodId.identifierType == UA_NODEIDTYPE_NUMERIC &&
  905. newMethodId.identifier.numeric == UA_NS0ID_SERVER_GETMONITOREDITEMS) {
  906. outputArgumentsVariableNode->nodeId =
  907. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS_OUTPUTARGUMENTS);
  908. }
  909. UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.data.value.value,
  910. outputArguments, outputArgumentsSize,
  911. &UA_TYPES[UA_TYPES_ARGUMENT]);
  912. outputArgumentsVariableNode->value.data.value.hasValue = true;
  913. UA_RCU_LOCK();
  914. // todo: check if adding succeeded
  915. Service_AddNodes_existing(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
  916. &newMethodId, &hasproperty, &propertytype, NULL, NULL);
  917. UA_RCU_UNLOCK();
  918. }
  919. if(outNewNodeId)
  920. *outNewNodeId = newMethodId;
  921. else
  922. UA_NodeId_deleteMembers(&newMethodId);
  923. return retval;
  924. }
  925. #endif
  926. /******************/
  927. /* Add References */
  928. /******************/
  929. static UA_StatusCode
  930. deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
  931. const UA_DeleteReferencesItem *item);
  932. /* Adds a one-way reference to the local nodestore */
  933. static UA_StatusCode
  934. addOneWayReference(UA_Server *server, UA_Session *session,
  935. UA_Node *node, const UA_AddReferencesItem *item) {
  936. size_t i = node->referencesSize;
  937. size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
  938. UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
  939. if(!new_refs)
  940. return UA_STATUSCODE_BADOUTOFMEMORY;
  941. node->references = new_refs;
  942. UA_ReferenceNode_init(&new_refs[i]);
  943. UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId);
  944. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId);
  945. new_refs[i].isInverse = !item->isForward;
  946. if(retval == UA_STATUSCODE_GOOD)
  947. node->referencesSize = i+1;
  948. else
  949. UA_ReferenceNode_deleteMembers(&new_refs[i]);
  950. return retval;
  951. }
  952. static UA_StatusCode
  953. addReference(UA_Server *server, UA_Session *session,
  954. const UA_AddReferencesItem *item) {
  955. /* Currently no expandednodeids are allowed */
  956. if(item->targetServerUri.length > 0)
  957. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  958. /* Add the first direction */
  959. UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  960. (UA_EditNodeCallback)addOneWayReference,
  961. item);
  962. if(retval != UA_STATUSCODE_GOOD)
  963. return retval;
  964. /* Add the second direction */
  965. UA_AddReferencesItem secondItem;
  966. UA_AddReferencesItem_init(&secondItem);
  967. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  968. secondItem.referenceTypeId = item->referenceTypeId;
  969. secondItem.isForward = !item->isForward;
  970. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  971. /* keep default secondItem.targetNodeClass = UA_NODECLASS_UNSPECIFIED */
  972. retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  973. (UA_EditNodeCallback)addOneWayReference, &secondItem);
  974. /* remove reference if the second direction failed */
  975. if(retval != UA_STATUSCODE_GOOD) {
  976. UA_DeleteReferencesItem deleteItem;
  977. deleteItem.sourceNodeId = item->sourceNodeId;
  978. deleteItem.referenceTypeId = item->referenceTypeId;
  979. deleteItem.isForward = item->isForward;
  980. deleteItem.targetNodeId = item->targetNodeId;
  981. deleteItem.deleteBidirectional = false;
  982. /* ignore returned status code */
  983. UA_Server_editNode(server, session, &item->sourceNodeId,
  984. (UA_EditNodeCallback)deleteOneWayReference, &deleteItem);
  985. }
  986. return retval;
  987. }
  988. void Service_AddReferences(UA_Server *server, UA_Session *session,
  989. const UA_AddReferencesRequest *request,
  990. UA_AddReferencesResponse *response) {
  991. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  992. "Processing AddReferencesRequest");
  993. if(request->referencesToAddSize <= 0) {
  994. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  995. return;
  996. }
  997. response->results = UA_malloc(sizeof(UA_StatusCode) * request->referencesToAddSize);
  998. if(!response->results) {
  999. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  1000. return;
  1001. }
  1002. response->resultsSize = request->referencesToAddSize;
  1003. for(size_t i = 0; i < response->resultsSize; ++i)
  1004. response->results[i] =
  1005. addReference(server, session, &request->referencesToAdd[i]);
  1006. }
  1007. UA_StatusCode
  1008. UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
  1009. const UA_NodeId refTypeId, const UA_ExpandedNodeId targetId,
  1010. UA_Boolean isForward) {
  1011. UA_AddReferencesItem item;
  1012. UA_AddReferencesItem_init(&item);
  1013. item.sourceNodeId = sourceId;
  1014. item.referenceTypeId = refTypeId;
  1015. item.isForward = isForward;
  1016. item.targetNodeId = targetId;
  1017. UA_RCU_LOCK();
  1018. UA_StatusCode retval = addReference(server, &adminSession, &item);
  1019. UA_RCU_UNLOCK();
  1020. return retval;
  1021. }
  1022. /****************/
  1023. /* Delete Nodes */
  1024. /****************/
  1025. static void
  1026. removeReferences(UA_Server *server, UA_Session *session, const UA_Node *node) {
  1027. UA_DeleteReferencesItem item;
  1028. UA_DeleteReferencesItem_init(&item);
  1029. item.targetNodeId.nodeId = node->nodeId;
  1030. for(size_t i = 0; i < node->referencesSize; ++i) {
  1031. item.isForward = node->references[i].isInverse;
  1032. item.sourceNodeId = node->references[i].targetId.nodeId;
  1033. item.referenceTypeId = node->references[i].referenceTypeId;
  1034. deleteReference(server, session, &item);
  1035. }
  1036. }
  1037. static UA_StatusCode
  1038. deleteNode(UA_Server *server, UA_Session *session,
  1039. const UA_NodeId *nodeId, UA_Boolean deleteReferences) {
  1040. const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
  1041. if(!node)
  1042. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  1043. /* TODO: check if the information model consistency is violated */
  1044. /* TODO: Check if the node is a mandatory child of an object */
  1045. /* Destroy an object before removing it */
  1046. if(node->nodeClass == UA_NODECLASS_OBJECT) {
  1047. /* Call the destructor from the object type */
  1048. const UA_ObjectTypeNode *typenode = getObjectNodeType(server, (const UA_ObjectNode*)node);
  1049. if(typenode && typenode->lifecycleManagement.destructor)
  1050. typenode->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle);
  1051. }
  1052. /* Remove references to the node (not the references in the node that will
  1053. * be deleted anyway) */
  1054. if(deleteReferences)
  1055. removeReferences(server, session, node);
  1056. return UA_NodeStore_remove(server->nodestore, nodeId);
  1057. }
  1058. void Service_DeleteNodes(UA_Server *server, UA_Session *session,
  1059. const UA_DeleteNodesRequest *request,
  1060. UA_DeleteNodesResponse *response) {
  1061. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  1062. "Processing DeleteNodesRequest");
  1063. if(request->nodesToDeleteSize == 0) {
  1064. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  1065. return;
  1066. }
  1067. response->results = UA_malloc(sizeof(UA_StatusCode) * request->nodesToDeleteSize);
  1068. if(!response->results) {
  1069. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;;
  1070. return;
  1071. }
  1072. response->resultsSize = request->nodesToDeleteSize;
  1073. for(size_t i = 0; i < request->nodesToDeleteSize; ++i) {
  1074. UA_DeleteNodesItem *item = &request->nodesToDelete[i];
  1075. response->results[i] = deleteNode(server, session, &item->nodeId,
  1076. item->deleteTargetReferences);
  1077. }
  1078. }
  1079. UA_StatusCode
  1080. UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
  1081. UA_Boolean deleteReferences) {
  1082. UA_RCU_LOCK();
  1083. UA_StatusCode retval = deleteNode(server, &adminSession,
  1084. &nodeId, deleteReferences);
  1085. UA_RCU_UNLOCK();
  1086. return retval;
  1087. }
  1088. /*********************/
  1089. /* Delete References */
  1090. /*********************/
  1091. // TODO: Check consistency constraints, remove the references.
  1092. static UA_StatusCode
  1093. deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
  1094. const UA_DeleteReferencesItem *item) {
  1095. UA_Boolean edited = false;
  1096. for(size_t i = node->referencesSize; i > 0; --i) {
  1097. UA_ReferenceNode *ref = &node->references[i-1];
  1098. if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &ref->targetId.nodeId))
  1099. continue;
  1100. if(!UA_NodeId_equal(&item->referenceTypeId, &ref->referenceTypeId))
  1101. continue;
  1102. if(item->isForward == ref->isInverse)
  1103. continue;
  1104. UA_ReferenceNode_deleteMembers(ref);
  1105. /* move the last entry to override the current position */
  1106. node->references[i-1] = node->references[node->referencesSize-1];
  1107. --node->referencesSize;
  1108. edited = true;
  1109. break;
  1110. }
  1111. if(!edited)
  1112. return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
  1113. /* we removed the last reference */
  1114. if(node->referencesSize == 0 && node->references) {
  1115. UA_free(node->references);
  1116. node->references = NULL;
  1117. }
  1118. return UA_STATUSCODE_GOOD;;
  1119. }
  1120. static UA_StatusCode
  1121. deleteReference(UA_Server *server, UA_Session *session,
  1122. const UA_DeleteReferencesItem *item) {
  1123. UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  1124. (UA_EditNodeCallback)deleteOneWayReference, item);
  1125. if(retval != UA_STATUSCODE_GOOD)
  1126. return retval;
  1127. if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
  1128. return retval;
  1129. UA_DeleteReferencesItem secondItem;
  1130. UA_DeleteReferencesItem_init(&secondItem);
  1131. secondItem.isForward = !item->isForward;
  1132. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  1133. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  1134. secondItem.referenceTypeId = item->referenceTypeId;
  1135. return UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  1136. (UA_EditNodeCallback)deleteOneWayReference, &secondItem);
  1137. }
  1138. void
  1139. Service_DeleteReferences(UA_Server *server, UA_Session *session,
  1140. const UA_DeleteReferencesRequest *request,
  1141. UA_DeleteReferencesResponse *response) {
  1142. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  1143. "Processing DeleteReferencesRequest");
  1144. if(request->referencesToDeleteSize <= 0) {
  1145. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  1146. return;
  1147. }
  1148. response->results = UA_malloc(sizeof(UA_StatusCode) * request->referencesToDeleteSize);
  1149. if(!response->results) {
  1150. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;;
  1151. return;
  1152. }
  1153. response->resultsSize = request->referencesToDeleteSize;
  1154. for(size_t i = 0; i < request->referencesToDeleteSize; ++i)
  1155. response->results[i] =
  1156. deleteReference(server, session, &request->referencesToDelete[i]);
  1157. }
  1158. UA_StatusCode
  1159. UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
  1160. const UA_NodeId referenceTypeId,
  1161. UA_Boolean isForward, const UA_ExpandedNodeId targetNodeId,
  1162. UA_Boolean deleteBidirectional) {
  1163. UA_DeleteReferencesItem item;
  1164. item.sourceNodeId = sourceNodeId;
  1165. item.referenceTypeId = referenceTypeId;
  1166. item.isForward = isForward;
  1167. item.targetNodeId = targetNodeId;
  1168. item.deleteBidirectional = deleteBidirectional;
  1169. UA_RCU_LOCK();
  1170. UA_StatusCode retval = deleteReference(server, &adminSession, &item);
  1171. UA_RCU_UNLOCK();
  1172. return retval;
  1173. }
  1174. /**********************/
  1175. /* Set Value Callback */
  1176. /**********************/
  1177. static UA_StatusCode
  1178. setValueCallback(UA_Server *server, UA_Session *session,
  1179. UA_VariableNode *node, UA_ValueCallback *callback) {
  1180. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1181. return UA_STATUSCODE_BADNODECLASSINVALID;
  1182. node->value.data.callback = *callback;
  1183. return UA_STATUSCODE_GOOD;
  1184. }
  1185. UA_StatusCode
  1186. UA_Server_setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
  1187. const UA_ValueCallback callback) {
  1188. UA_RCU_LOCK();
  1189. UA_StatusCode retval = UA_Server_editNode(server, &adminSession, &nodeId,
  1190. (UA_EditNodeCallback)setValueCallback, &callback);
  1191. UA_RCU_UNLOCK();
  1192. return retval;
  1193. }
  1194. /******************/
  1195. /* Set DataSource */
  1196. /******************/
  1197. static UA_StatusCode
  1198. setDataSource(UA_Server *server, UA_Session *session,
  1199. UA_VariableNode* node, UA_DataSource *dataSource) {
  1200. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1201. return UA_STATUSCODE_BADNODECLASSINVALID;
  1202. if(node->valueSource == UA_VALUESOURCE_DATA)
  1203. UA_DataValue_deleteMembers(&node->value.data.value);
  1204. node->value.dataSource = *dataSource;
  1205. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  1206. return UA_STATUSCODE_GOOD;
  1207. }
  1208. UA_StatusCode
  1209. UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  1210. const UA_DataSource dataSource) {
  1211. UA_RCU_LOCK();
  1212. UA_StatusCode retval = UA_Server_editNode(server, &adminSession, &nodeId,
  1213. (UA_EditNodeCallback)setDataSource, &dataSource);
  1214. UA_RCU_UNLOCK();
  1215. return retval;
  1216. }
  1217. /****************************/
  1218. /* Set Lifecycle Management */
  1219. /****************************/
  1220. static UA_StatusCode
  1221. setOLM(UA_Server *server, UA_Session *session,
  1222. UA_ObjectTypeNode* node, UA_ObjectLifecycleManagement *olm) {
  1223. if(node->nodeClass != UA_NODECLASS_OBJECTTYPE)
  1224. return UA_STATUSCODE_BADNODECLASSINVALID;
  1225. node->lifecycleManagement = *olm;
  1226. return UA_STATUSCODE_GOOD;
  1227. }
  1228. UA_StatusCode
  1229. UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server, UA_NodeId nodeId,
  1230. UA_ObjectLifecycleManagement olm) {
  1231. UA_RCU_LOCK();
  1232. UA_StatusCode retval = UA_Server_editNode(server, &adminSession, &nodeId,
  1233. (UA_EditNodeCallback)setOLM, &olm);
  1234. UA_RCU_UNLOCK();
  1235. return retval;
  1236. }
  1237. /***********************/
  1238. /* Set Method Callback */
  1239. /***********************/
  1240. #ifdef UA_ENABLE_METHODCALLS
  1241. struct addMethodCallback {
  1242. UA_MethodCallback callback;
  1243. void *handle;
  1244. };
  1245. static UA_StatusCode
  1246. editMethodCallback(UA_Server *server, UA_Session* session,
  1247. UA_Node* node, const void* handle) {
  1248. if(node->nodeClass != UA_NODECLASS_METHOD)
  1249. return UA_STATUSCODE_BADNODECLASSINVALID;
  1250. const struct addMethodCallback *newCallback = handle;
  1251. UA_MethodNode *mnode = (UA_MethodNode*) node;
  1252. mnode->attachedMethod = newCallback->callback;
  1253. mnode->methodHandle = newCallback->handle;
  1254. return UA_STATUSCODE_GOOD;
  1255. }
  1256. UA_StatusCode
  1257. UA_Server_setMethodNode_callback(UA_Server *server, const UA_NodeId methodNodeId,
  1258. UA_MethodCallback method, void *handle) {
  1259. struct addMethodCallback cb = { method, handle };
  1260. UA_RCU_LOCK();
  1261. UA_StatusCode retval = UA_Server_editNode(server, &adminSession,
  1262. &methodNodeId, editMethodCallback, &cb);
  1263. UA_RCU_UNLOCK();
  1264. return retval;
  1265. }
  1266. #endif