ua_services_nodemanagement.c 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522
  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. /* Edit Node Context */
  8. /*********************/
  9. UA_StatusCode
  10. UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
  11. void **nodeContext) {
  12. const UA_Node *node = UA_Nodestore_get(server, &nodeId);
  13. if(!node)
  14. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  15. *nodeContext = node->context;
  16. UA_Nodestore_release(server, node);
  17. return UA_STATUSCODE_GOOD;
  18. }
  19. static UA_StatusCode
  20. editNodeContext(UA_Server *server, UA_Session* session,
  21. UA_Node* node, void *context) {
  22. node->context = context;
  23. return UA_STATUSCODE_GOOD;
  24. }
  25. UA_StatusCode
  26. UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
  27. void *nodeContext) {
  28. UA_StatusCode retval =
  29. UA_Server_editNode(server, &adminSession, &nodeId,
  30. (UA_EditNodeCallback)editNodeContext, nodeContext);
  31. return retval;
  32. }
  33. /**********************/
  34. /* Consistency Checks */
  35. /**********************/
  36. /* Check if the requested parent node exists, has the right node class and is
  37. * referenced with an allowed (hierarchical) reference type. For "type" nodes,
  38. * only hasSubType references are allowed. */
  39. static UA_StatusCode
  40. checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeClass,
  41. const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
  42. /* Objects do not need a parent (e.g. mandatory/optional modellingrules) */
  43. if(nodeClass == UA_NODECLASS_OBJECT && UA_NodeId_isNull(parentNodeId) &&
  44. UA_NodeId_isNull(referenceTypeId))
  45. return UA_STATUSCODE_GOOD;
  46. /* Omit checks during bootstrap */
  47. if(server->bootstrapNS0)
  48. return UA_STATUSCODE_GOOD;
  49. /* See if the parent exists */
  50. const UA_Node *parent = UA_Nodestore_get(server, parentNodeId);
  51. if(!parent) {
  52. UA_LOG_INFO_SESSION(server->config.logger, session,
  53. "AddNodes: Parent node not found");
  54. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  55. }
  56. UA_NodeClass parentNodeClass = parent->nodeClass;
  57. UA_Nodestore_release(server, parent);
  58. /* Check the referencetype exists */
  59. const UA_ReferenceTypeNode *referenceType = (const UA_ReferenceTypeNode*)
  60. UA_Nodestore_get(server, referenceTypeId);
  61. if(!referenceType) {
  62. UA_LOG_INFO_SESSION(server->config.logger, session,
  63. "AddNodes: Reference type to the parent not found");
  64. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  65. }
  66. UA_NodeClass referenceTypeNodeClass = referenceType->nodeClass;
  67. UA_Boolean referenceTypeIsAbstract = referenceType->isAbstract;
  68. UA_Nodestore_release(server, (const UA_Node*)referenceType);
  69. /* Check if the referencetype is a reference type node */
  70. if(referenceTypeNodeClass != UA_NODECLASS_REFERENCETYPE) {
  71. UA_LOG_INFO_SESSION(server->config.logger, session,
  72. "AddNodes: Reference type to the parent invalid");
  73. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  74. }
  75. /* Check that the reference type is not abstract */
  76. if(referenceTypeIsAbstract == true) {
  77. UA_LOG_INFO_SESSION(server->config.logger, session,
  78. "AddNodes: Abstract reference type to the parent not allowed");
  79. return UA_STATUSCODE_BADREFERENCENOTALLOWED;
  80. }
  81. /* Check hassubtype relation for type nodes */
  82. if(nodeClass == UA_NODECLASS_DATATYPE ||
  83. nodeClass == UA_NODECLASS_VARIABLETYPE ||
  84. nodeClass == UA_NODECLASS_OBJECTTYPE ||
  85. nodeClass == UA_NODECLASS_REFERENCETYPE) {
  86. /* type needs hassubtype reference to the supertype */
  87. if(!UA_NodeId_equal(referenceTypeId, &subtypeId)) {
  88. UA_LOG_INFO_SESSION(server->config.logger, session,
  89. "AddNodes: New type node need to have a "
  90. "HasSubType reference");
  91. return UA_STATUSCODE_BADREFERENCENOTALLOWED;
  92. }
  93. /* supertype needs to be of the same node type */
  94. if(parentNodeClass != nodeClass) {
  95. UA_LOG_INFO_SESSION(server->config.logger, session,
  96. "AddNodes: New type node needs to be of the same "
  97. "node type as the parent");
  98. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  99. }
  100. return UA_STATUSCODE_GOOD;
  101. }
  102. /* Test if the referencetype is hierarchical */
  103. const UA_NodeId hierarchicalReference =
  104. UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
  105. if(!isNodeInTree(&server->config.nodestore, referenceTypeId,
  106. &hierarchicalReference, &subtypeId, 1)) {
  107. UA_LOG_INFO_SESSION(server->config.logger, session,
  108. "AddNodes: Reference type is not hierarchical");
  109. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  110. }
  111. return UA_STATUSCODE_GOOD;
  112. }
  113. static UA_StatusCode
  114. typeCheckVariableNode(UA_Server *server, UA_Session *session,
  115. const UA_VariableNode *node, const UA_VariableTypeNode *vt,
  116. const UA_NodeId *parentNodeId) {
  117. /* The value might come from a datasource, so we perform a
  118. * regular read. */
  119. UA_DataValue value;
  120. UA_DataValue_init(&value);
  121. UA_StatusCode retval = readValueAttribute(server, session, node, &value);
  122. if(retval != UA_STATUSCODE_GOOD)
  123. return retval;
  124. /* Check the datatype against the vt */
  125. if(!compatibleDataType(server, &node->dataType, &vt->dataType))
  126. return UA_STATUSCODE_BADTYPEMISMATCH;
  127. /* Get the array dimensions */
  128. size_t arrayDims = node->arrayDimensionsSize;
  129. if(arrayDims == 0 && value.hasValue && value.value.type &&
  130. !UA_Variant_isScalar(&value.value)) {
  131. arrayDims = 1; /* No array dimensions on an array implies one dimension */
  132. }
  133. /* Check valueRank against array dimensions */
  134. if (!(node->nodeClass == UA_NODECLASS_VARIABLETYPE && ((const UA_VariableTypeNode*)node)->isAbstract && node->valueRank == 0) &&
  135. !compatibleValueRankArrayDimensions(node->valueRank, arrayDims))
  136. return UA_STATUSCODE_BADTYPEMISMATCH;
  137. /* If variable node is created below BaseObjectType and has its default valueRank of -2,
  138. * skip the test */
  139. const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  140. const UA_NodeId refs[] = {
  141. UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
  142. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)
  143. };
  144. if(node->valueRank != vt->valueRank &&
  145. node->valueRank != UA_VariableAttributes_default.valueRank &&
  146. !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, refs , 2)) {
  147. /* Check valueRank against the vt */
  148. if(!compatibleValueRanks(node->valueRank, vt->valueRank))
  149. return UA_STATUSCODE_BADTYPEMISMATCH;
  150. }
  151. /* Check array dimensions against the vt */
  152. if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions,
  153. node->arrayDimensionsSize, node->arrayDimensions))
  154. return UA_STATUSCODE_BADTYPEMISMATCH;
  155. /* Typecheck the value */
  156. if(!server->bootstrapNS0 && value.hasValue) {
  157. /* If the type-check failed write the same value again. The
  158. * write-service tries to convert to the correct type... */
  159. if(!compatibleValue(server, &node->dataType, node->valueRank,
  160. node->arrayDimensionsSize, node->arrayDimensions,
  161. &value.value, NULL))
  162. retval = UA_Server_writeValue(server, node->nodeId, value.value);
  163. UA_DataValue_deleteMembers(&value);
  164. }
  165. return retval;
  166. }
  167. /********************/
  168. /* Instantiate Node */
  169. /********************/
  170. static const UA_NodeId baseDataVariableType =
  171. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEDATAVARIABLETYPE}};
  172. static const UA_NodeId baseObjectType =
  173. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEOBJECTTYPE}};
  174. /* Use attributes from the variable type wherever required */
  175. static UA_StatusCode
  176. useVariableTypeAttributes(UA_Server *server, UA_Session *session,
  177. UA_VariableNode *node, const UA_AddNodesItem *item) {
  178. const UA_VariableAttributes *attributes = (const UA_VariableAttributes*)
  179. item->nodeAttributes.content.decoded.data;
  180. /* Select the type definition */
  181. const UA_NodeId *typeDefinition;
  182. if(node->nodeClass == UA_NODECLASS_VARIABLE)
  183. typeDefinition = &item->typeDefinition.nodeId;
  184. else /* UA_NODECLASS_VARIABLETYPE */
  185. typeDefinition = &item->parentNodeId.nodeId;
  186. /* Replace an empty typeDefinition with the most permissive default */
  187. if(UA_NodeId_isNull(typeDefinition))
  188. typeDefinition = &baseDataVariableType;
  189. const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)
  190. UA_Nodestore_get(server, typeDefinition);
  191. if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE)
  192. return UA_STATUSCODE_BADTYPEMISMATCH;
  193. /* If no value is set, see if the vt provides one and copy it. This needs to
  194. * be done before copying the datatype from the vt, as setting the datatype
  195. * triggers a typecheck. */
  196. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  197. if(!attributes->value.type) {
  198. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  199. "AddNodes: No value given; Copy the value"
  200. "from the TypeDefinition");
  201. UA_DataValue vt_value;
  202. UA_DataValue_init(&vt_value);
  203. retval = readValueAttribute(server, session,
  204. (const UA_VariableNode*)vt, &vt_value);
  205. if(retval == UA_STATUSCODE_GOOD && vt_value.hasValue) {
  206. retval = UA_Variant_copy(&vt_value.value, &node->value.data.value.value);
  207. node->value.data.value.hasValue = true;
  208. }
  209. UA_DataValue_deleteMembers(&vt_value);
  210. }
  211. /* If no datatype is given, use the datatype of the vt */
  212. if(retval == UA_STATUSCODE_GOOD && UA_NodeId_isNull(&node->dataType)) {
  213. UA_LOG_INFO_SESSION(server->config.logger, session, "AddNodes: "
  214. "No datatype given; Copy the datatype attribute "
  215. "from the TypeDefinition");
  216. retval = UA_NodeId_copy(&vt->dataType, &node->dataType);
  217. }
  218. /* TODO: If the vt has arraydimensions but this variable does not, copy */
  219. UA_Nodestore_release(server, (const UA_Node*)vt);
  220. return retval;
  221. }
  222. /* Search for an instance of "browseName" in node searchInstance. Used during
  223. * copyChildNodes to find overwritable/mergable nodes. Does not touch
  224. * outInstanceNodeId if no child is found. */
  225. static UA_StatusCode
  226. findChildByBrowsename(UA_Server *server, UA_Session *session,
  227. const UA_NodeId *searchInstance,
  228. const UA_QualifiedName *browseName,
  229. UA_NodeId *outInstanceNodeId) {
  230. UA_BrowseDescription bd;
  231. UA_BrowseDescription_init(&bd);
  232. bd.nodeId = *searchInstance;
  233. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  234. bd.includeSubtypes = true;
  235. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  236. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  237. bd.resultMask = UA_BROWSERESULTMASK_NODECLASS | UA_BROWSERESULTMASK_BROWSENAME;
  238. UA_BrowseResult br;
  239. UA_BrowseResult_init(&br);
  240. Service_Browse_single(server, session, NULL, &bd, 0, &br);
  241. if(br.statusCode != UA_STATUSCODE_GOOD)
  242. return br.statusCode;
  243. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  244. for(size_t i = 0; i < br.referencesSize; ++i) {
  245. UA_ReferenceDescription *rd = &br.references[i];
  246. if(rd->browseName.namespaceIndex == browseName->namespaceIndex &&
  247. UA_String_equal(&rd->browseName.name, &browseName->name)) {
  248. retval = UA_NodeId_copy(&rd->nodeId.nodeId, outInstanceNodeId);
  249. break;
  250. }
  251. }
  252. UA_BrowseResult_deleteMembers(&br);
  253. return retval;
  254. }
  255. static const UA_NodeId mandatoryId =
  256. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_MODELLINGRULE_MANDATORY}};
  257. static const UA_NodeId hasModellingRuleId =
  258. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASMODELLINGRULE}};
  259. static UA_Boolean
  260. isMandatoryChild(UA_Server *server, UA_Session *session,
  261. const UA_NodeId *childNodeId) {
  262. /* Get the child */
  263. const UA_Node *child = UA_Nodestore_get(server, childNodeId);
  264. if(!child)
  265. return false;
  266. /* Look for the reference making the child mandatory */
  267. for(size_t i = 0; i < child->referencesSize; ++i) {
  268. UA_NodeReferenceKind *refs = &child->references[i];
  269. if(!UA_NodeId_equal(&hasModellingRuleId, &refs->referenceTypeId))
  270. continue;
  271. if(refs->isInverse)
  272. continue;
  273. for(size_t j = 0; j < refs->targetIdsSize; ++j) {
  274. if(UA_NodeId_equal(&mandatoryId, &refs->targetIds[j].nodeId)) {
  275. UA_Nodestore_release(server, child);
  276. return true;
  277. }
  278. }
  279. }
  280. UA_Nodestore_release(server, child);
  281. return false;
  282. }
  283. static UA_StatusCode
  284. copyChildNodes(UA_Server *server, UA_Session *session,
  285. const UA_NodeId *sourceNodeId,
  286. const UA_NodeId *destinationNodeId);
  287. static void
  288. addReference(UA_Server *server, UA_Session *session,
  289. const UA_AddReferencesItem *item, UA_StatusCode *retval);
  290. static UA_StatusCode
  291. copyChildNode(UA_Server *server, UA_Session *session,
  292. const UA_NodeId *destinationNodeId,
  293. const UA_ReferenceDescription *rd) {
  294. UA_NodeId existingChild = UA_NODEID_NULL;
  295. UA_StatusCode retval =
  296. findChildByBrowsename(server, session, destinationNodeId,
  297. &rd->browseName, &existingChild);
  298. if(retval != UA_STATUSCODE_GOOD)
  299. return retval;
  300. /* Have a child with that browseName. Try to deep-copy missing members. */
  301. if(!UA_NodeId_isNull(&existingChild)) {
  302. if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
  303. rd->nodeClass == UA_NODECLASS_OBJECT)
  304. retval = copyChildNodes(server, session, &rd->nodeId.nodeId, &existingChild);
  305. UA_NodeId_deleteMembers(&existingChild);
  306. return retval;
  307. }
  308. /* Is the child mandatory? If not, skip */
  309. if(!isMandatoryChild(server, session, &rd->nodeId.nodeId))
  310. return UA_STATUSCODE_GOOD;
  311. /* No existing child with that browsename. Create it. */
  312. if(rd->nodeClass == UA_NODECLASS_METHOD) {
  313. /* Add a reference to the method in the objecttype */
  314. UA_AddReferencesItem newItem;
  315. UA_AddReferencesItem_init(&newItem);
  316. newItem.sourceNodeId = *destinationNodeId;
  317. newItem.referenceTypeId = rd->referenceTypeId;
  318. newItem.isForward = true;
  319. newItem.targetNodeId = rd->nodeId;
  320. newItem.targetNodeClass = UA_NODECLASS_METHOD;
  321. addReference(server, session, &newItem, &retval);
  322. return retval;
  323. }
  324. /* Node exists and is a variable or object. Instantiate missing mandatory
  325. * children */
  326. if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
  327. rd->nodeClass == UA_NODECLASS_OBJECT) {
  328. /* Get the node */
  329. UA_Node *node;
  330. retval = UA_Nodestore_getCopy(server, &rd->nodeId.nodeId, &node);
  331. if(retval != UA_STATUSCODE_GOOD)
  332. return retval;
  333. /* Get the type */
  334. const UA_Node *type = getNodeType(server, node);
  335. const UA_NodeId *typeId;
  336. if(type)
  337. typeId = &type->nodeId;
  338. else
  339. typeId = &UA_NODEID_NULL;
  340. /* Reset the NodeId (random numeric id will be assigned in the nodestore) */
  341. UA_NodeId_deleteMembers(&node->nodeId);
  342. node->nodeId.namespaceIndex = destinationNodeId->namespaceIndex;
  343. /* Remove references, they are re-created from scratch in addnode_finish */
  344. /* TODO: Be more clever in removing references that are re-added during
  345. * addnode_finish. That way, we can call addnode_finish also on children that were
  346. * manually added by the user during addnode_begin and addnode_finish. */
  347. UA_Node_deleteReferences(node);
  348. /* Add the node to the nodestore */
  349. UA_NodeId newNodeId;
  350. retval = UA_Nodestore_insert(server, node, &newNodeId);
  351. if(retval != UA_STATUSCODE_GOOD) {
  352. UA_Nodestore_release(server, type);
  353. return retval;
  354. }
  355. /* Call addnode_finish, this recursively adds members, the type
  356. * definition and so on */
  357. retval = Operation_addNode_finish(server, session, &newNodeId, destinationNodeId,
  358. &rd->referenceTypeId, typeId);
  359. UA_NodeId_deleteMembers(&newNodeId);
  360. UA_Nodestore_release(server, type);
  361. }
  362. return retval;
  363. }
  364. /* Copy any children of Node sourceNodeId to another node destinationNodeId. */
  365. static UA_StatusCode
  366. copyChildNodes(UA_Server *server, UA_Session *session,
  367. const UA_NodeId *sourceNodeId, const UA_NodeId *destinationNodeId) {
  368. /* Browse to get all children of the source */
  369. UA_BrowseDescription bd;
  370. UA_BrowseDescription_init(&bd);
  371. bd.nodeId = *sourceNodeId;
  372. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  373. bd.includeSubtypes = true;
  374. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  375. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  376. bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS |
  377. UA_BROWSERESULTMASK_BROWSENAME;
  378. UA_BrowseResult br;
  379. UA_BrowseResult_init(&br);
  380. Service_Browse_single(server, session, NULL, &bd, 0, &br);
  381. if(br.statusCode != UA_STATUSCODE_GOOD)
  382. return br.statusCode;
  383. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  384. for(size_t i = 0; i < br.referencesSize; ++i) {
  385. UA_ReferenceDescription *rd = &br.references[i];
  386. retval |= copyChildNode(server, session, destinationNodeId, rd);
  387. }
  388. UA_BrowseResult_deleteMembers(&br);
  389. return retval;
  390. }
  391. static UA_StatusCode
  392. addChildren(UA_Server *server, UA_Session *session,
  393. const UA_Node *node, const UA_Node *type) {
  394. /* Get the hierarchy of the type and all its supertypes */
  395. UA_NodeId *hierarchy = NULL;
  396. size_t hierarchySize = 0;
  397. UA_StatusCode retval = getTypeHierarchy(&server->config.nodestore, &type->nodeId,
  398. &hierarchy, &hierarchySize);
  399. if(retval != UA_STATUSCODE_GOOD)
  400. return retval;
  401. /* Copy members of the type and supertypes (and instantiate them) */
  402. for(size_t i = 0; i < hierarchySize; ++i)
  403. retval |= copyChildNodes(server, session, &hierarchy[i], &node->nodeId);
  404. UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
  405. return retval;
  406. }
  407. /* Calls the global destructor internally of the global constructor succeeds and
  408. * the type-level constructor fails. */
  409. static UA_StatusCode callConstructors(UA_Server *server, UA_Session *session,
  410. const UA_Node *node, const UA_Node *type) {
  411. /* Get the node type constructor */
  412. const UA_NodeTypeLifecycle *lifecycle = NULL;
  413. if(node->nodeClass == UA_NODECLASS_OBJECT) {
  414. const UA_ObjectTypeNode *ot = (const UA_ObjectTypeNode*)type;
  415. lifecycle = &ot->lifecycle;
  416. } else if(node->nodeClass == UA_NODECLASS_VARIABLE) {
  417. const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)type;
  418. lifecycle = &vt->lifecycle;
  419. }
  420. /* Call the global constructor */
  421. void *context = node->context;
  422. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  423. if(server->config.nodeLifecycle.constructor)
  424. retval = server->config.nodeLifecycle.constructor(server, &session->sessionId,
  425. session->sessionHandle,
  426. &node->nodeId, &context);
  427. /* Call the type constructor */
  428. if(retval == UA_STATUSCODE_GOOD && lifecycle && lifecycle->constructor)
  429. retval = lifecycle->constructor(server, &session->sessionId,
  430. session->sessionHandle, &type->nodeId,
  431. type->context, &node->nodeId, &context);
  432. /* Set the context *and* mark the node as constructed */
  433. if(retval == UA_STATUSCODE_GOOD)
  434. retval = UA_Server_editNode(server, &adminSession, &node->nodeId,
  435. (UA_EditNodeCallback)editNodeContext,
  436. context);
  437. /* Fail. Call the global destructor. */
  438. if(retval != UA_STATUSCODE_GOOD && server->config.nodeLifecycle.destructor)
  439. server->config.nodeLifecycle.destructor(server, &session->sessionId,
  440. session->sessionHandle,
  441. &node->nodeId, context);
  442. return retval;
  443. }
  444. static UA_StatusCode
  445. addTypeDefRef(UA_Server *server, UA_Session *session,
  446. const UA_Node *node, const UA_Node *type) {
  447. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  448. UA_AddReferencesItem addref;
  449. UA_AddReferencesItem_init(&addref);
  450. addref.sourceNodeId = node->nodeId;
  451. addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  452. addref.isForward = true;
  453. addref.targetNodeId.nodeId = type->nodeId;
  454. addReference(server, session, &addref, &retval);
  455. return retval;
  456. }
  457. static UA_StatusCode
  458. addParentRef(UA_Server *server, UA_Session *session,
  459. const UA_NodeId *nodeId,
  460. const UA_NodeId *referenceTypeId,
  461. const UA_NodeId *parentNodeId) {
  462. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  463. UA_AddReferencesItem ref_item;
  464. UA_AddReferencesItem_init(&ref_item);
  465. ref_item.sourceNodeId = *nodeId;
  466. ref_item.referenceTypeId = *referenceTypeId;
  467. ref_item.isForward = false;
  468. ref_item.targetNodeId.nodeId = *parentNodeId;
  469. addReference(server, session, &ref_item, &retval);
  470. return retval;
  471. }
  472. /************/
  473. /* Add Node */
  474. /************/
  475. /* Prepare the node, then add it to the nodestore */
  476. UA_StatusCode
  477. Operation_addNode_begin(UA_Server *server, UA_Session *session,
  478. const UA_AddNodesItem *item, void *nodeContext,
  479. UA_NodeId *outNewNodeId) {
  480. /* Check the namespaceindex */
  481. if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) {
  482. UA_LOG_INFO_SESSION(server->config.logger, session,
  483. "AddNodes: Namespace invalid");
  484. return UA_STATUSCODE_BADNODEIDINVALID;
  485. }
  486. if(item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED &&
  487. item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
  488. UA_LOG_INFO_SESSION(server->config.logger, session,
  489. "AddNodes: Node attributes invalid");
  490. return UA_STATUSCODE_BADINTERNALERROR;
  491. }
  492. /* Create a node */
  493. UA_Node *node = UA_Nodestore_new(server, item->nodeClass);
  494. if(!node) {
  495. UA_LOG_INFO_SESSION(server->config.logger, session,
  496. "AddNodes: Node could not create a node "
  497. "in the nodestore");
  498. return UA_STATUSCODE_BADOUTOFMEMORY;
  499. }
  500. /* Fill the node */
  501. node->context = nodeContext;
  502. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  503. retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
  504. retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
  505. retval |= UA_Node_setAttributes(node, item->nodeAttributes.content.decoded.data,
  506. item->nodeAttributes.content.decoded.type);
  507. if(retval != UA_STATUSCODE_GOOD) {
  508. UA_LOG_INFO_SESSION(server->config.logger, session,
  509. "AddNodes: Node could not create a node "
  510. "with error code %s",
  511. UA_StatusCode_name(retval));
  512. UA_Nodestore_delete(server, node);
  513. return retval;
  514. }
  515. if(server->bootstrapNS0)
  516. goto finished_checks;
  517. /* Use attributes from the typedefinition */
  518. if(node->nodeClass == UA_NODECLASS_VARIABLE ||
  519. node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
  520. /* Use attributes from the type. The value and value constraints are the
  521. * same for the variable and variabletype attribute structs. */
  522. retval = useVariableTypeAttributes(server, session,
  523. (UA_VariableNode*)node, item);
  524. if(retval != UA_STATUSCODE_GOOD) {
  525. UA_LOG_INFO_SESSION(server->config.logger, session,
  526. "AddNodes: Using attributes from the variable type "
  527. "failed with error code %s",
  528. UA_StatusCode_name(retval));
  529. UA_Nodestore_delete(server, node);
  530. return retval;
  531. }
  532. }
  533. finished_checks:
  534. /* Add the node to the nodestore */
  535. retval = UA_Nodestore_insert(server, node, outNewNodeId);
  536. if(retval != UA_STATUSCODE_GOOD) {
  537. UA_LOG_INFO_SESSION(server->config.logger, session,
  538. "AddNodes: Node could not add the new node "
  539. "to the nodestore with error code %s",
  540. UA_StatusCode_name(retval));
  541. }
  542. return retval;
  543. }
  544. static void
  545. removeDeconstructedNode(UA_Server *server, UA_Session *session,
  546. const UA_Node *node, UA_Boolean removeTargetRefs);
  547. static const UA_NodeId hasSubtype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
  548. /* Children, references, type-checking, constructors. */
  549. UA_StatusCode
  550. Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
  551. const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
  552. const UA_NodeId *typeDefinitionId) {
  553. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  554. const UA_Node *type = NULL;
  555. /* Get the node */
  556. const UA_Node *node = UA_Nodestore_get(server, nodeId);
  557. if(!node)
  558. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  559. /* Use the typeDefinition as parent for type-nodes */
  560. if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
  561. node->nodeClass == UA_NODECLASS_OBJECTTYPE ||
  562. node->nodeClass == UA_NODECLASS_REFERENCETYPE ||
  563. node->nodeClass == UA_NODECLASS_DATATYPE) {
  564. if (UA_NodeId_equal(referenceTypeId, &UA_NODEID_NULL))
  565. referenceTypeId = &hasSubtype;
  566. const UA_Node *parentNode = UA_Nodestore_get(server, parentNodeId);
  567. if (parentNode) {
  568. if (parentNode->nodeClass == node->nodeClass)
  569. typeDefinitionId = parentNodeId;
  570. UA_Nodestore_release(server, parentNode);
  571. }
  572. }
  573. if(server->bootstrapNS0)
  574. goto get_type;
  575. /* Check parent reference. Objects may have no parent. */
  576. retval = checkParentReference(server, session, node->nodeClass,
  577. parentNodeId, referenceTypeId);
  578. if(retval != UA_STATUSCODE_GOOD) {
  579. UA_LOG_INFO_SESSION(server->config.logger, session,
  580. "AddNodes: The parent reference is invalid");
  581. UA_Nodestore_release(server, node);
  582. UA_Server_deleteNode(server, *nodeId, true);
  583. return retval;
  584. }
  585. /* Replace empty typeDefinition with the most permissive default */
  586. if((node->nodeClass == UA_NODECLASS_VARIABLE ||
  587. node->nodeClass == UA_NODECLASS_OBJECT) &&
  588. UA_NodeId_isNull(typeDefinitionId)) {
  589. UA_LOG_INFO_SESSION(server->config.logger, session,
  590. "AddNodes: No TypeDefinition; Use the default "
  591. "TypeDefinition for the Variable/Object");
  592. if(node->nodeClass == UA_NODECLASS_VARIABLE)
  593. typeDefinitionId = &baseDataVariableType;
  594. else
  595. typeDefinitionId = &baseObjectType;
  596. }
  597. get_type:
  598. /* Get the node type. There must be a typedefinition for variables, objects
  599. * and type-nodes. See the above checks. */
  600. if(!UA_NodeId_isNull(typeDefinitionId)) {
  601. /* Get the type node */
  602. type = UA_Nodestore_get(server, typeDefinitionId);
  603. if(!type) {
  604. UA_LOG_INFO_SESSION(server->config.logger, session,
  605. "AddNodes: Node type not found in nodestore");
  606. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  607. goto cleanup;
  608. }
  609. /* See if the type has the correct node class. For type-nodes, we know
  610. * that type has the same nodeClass from checkParentReference. */
  611. if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_VARIABLE) {
  612. if(type->nodeClass != UA_NODECLASS_VARIABLETYPE ||
  613. ((const UA_VariableTypeNode*)type)->isAbstract) {
  614. /* Abstract variable is allowed if parent is a children of a base data variable */
  615. const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
  616. /* A variable may be of an object type which again is below BaseObjectType */
  617. const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  618. const UA_NodeId refs[] = {
  619. UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
  620. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)
  621. };
  622. if(!isNodeInTree(&server->config.nodestore, parentNodeId,
  623. &variableTypes, refs , 2) &&
  624. !isNodeInTree(&server->config.nodestore, parentNodeId,
  625. &objectTypes, refs , 2)) {
  626. UA_LOG_INFO_SESSION(server->config.logger, session,
  627. "AddNodes: Type of variable node must "
  628. "be VariableType and not cannot be abstract");
  629. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  630. goto cleanup;
  631. }
  632. }
  633. }
  634. if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_OBJECT) {
  635. if(type->nodeClass != UA_NODECLASS_OBJECTTYPE ||
  636. ((const UA_ObjectTypeNode*)type)->isAbstract) {
  637. /* Object node created of an abstract ObjectType. Only allowed if within BaseObjectType folder */
  638. const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  639. const UA_NodeId refs[] = {
  640. UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
  641. UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)
  642. };
  643. if(!isNodeInTree(&server->config.nodestore, parentNodeId,
  644. &objectTypes, refs , 2)) {
  645. UA_LOG_INFO_SESSION(server->config.logger, session,
  646. "AddNodes: Type of object node must "
  647. "be ObjectType and not be abstract");
  648. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  649. goto cleanup;
  650. }
  651. }
  652. }
  653. }
  654. /* Check if all attributes hold the constraints of the type now. The initial
  655. * attributes must type-check. The constructor might change the attributes
  656. * again. Then, the changes are type-checked by the normal write service. */
  657. if(type && (node->nodeClass == UA_NODECLASS_VARIABLE ||
  658. node->nodeClass == UA_NODECLASS_VARIABLETYPE)) {
  659. retval = typeCheckVariableNode(server, session,
  660. (const UA_VariableNode*)node,
  661. (const UA_VariableTypeNode*)type, parentNodeId);
  662. if(retval != UA_STATUSCODE_GOOD) {
  663. UA_LOG_INFO_SESSION(server->config.logger, session,
  664. "AddNodes: Type-checking the variable node "
  665. "failed with error code %s", UA_StatusCode_name(retval));
  666. goto cleanup;
  667. }
  668. }
  669. /* Instantiate variables and objects */
  670. if(node->nodeClass == UA_NODECLASS_VARIABLE ||
  671. node->nodeClass == UA_NODECLASS_OBJECT) {
  672. UA_assert(type != NULL); /* see above */
  673. /* Add (mandatory) child nodes from the type definition */
  674. if (!server->bootstrapNS0) {
  675. retval = addChildren(server, session, node, type);
  676. if(retval != UA_STATUSCODE_GOOD) {
  677. UA_LOG_INFO_SESSION(server->config.logger, session,
  678. "AddNodes: Adding child nodes failed with error code %s",
  679. UA_StatusCode_name(retval));
  680. goto cleanup;
  681. }
  682. }
  683. /* Add a hasTypeDefinition reference */
  684. retval = addTypeDefRef(server, session, node, type);
  685. if(retval != UA_STATUSCODE_GOOD) {
  686. UA_LOG_INFO_SESSION(server->config.logger, session,
  687. "AddNodes: Adding a reference to the type "
  688. "definition failed with error code %s",
  689. UA_StatusCode_name(retval));
  690. goto cleanup;
  691. }
  692. }
  693. /* Add reference to the parent */
  694. if(!UA_NodeId_isNull(parentNodeId)) {
  695. if (UA_NodeId_isNull(referenceTypeId)) {
  696. UA_LOG_INFO_SESSION(server->config.logger, session,
  697. "AddNodes: Reference to parent cannot be null");
  698. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  699. goto cleanup;
  700. }
  701. retval = addParentRef(server, session, nodeId, referenceTypeId, parentNodeId);
  702. if(retval != UA_STATUSCODE_GOOD) {
  703. UA_LOG_INFO_SESSION(server->config.logger, session,
  704. "AddNodes: Adding reference to parent failed");
  705. goto cleanup;
  706. }
  707. }
  708. /* Call the constructor(s) */
  709. retval = callConstructors(server, session, node, type);
  710. if(retval != UA_STATUSCODE_GOOD) {
  711. UA_LOG_INFO_SESSION(server->config.logger, session,
  712. "AddNodes: Calling the node constructor(s) failed "
  713. "with status code %s", UA_StatusCode_name(retval));
  714. }
  715. cleanup:
  716. if(type)
  717. UA_Nodestore_release(server, type);
  718. if(retval != UA_STATUSCODE_GOOD)
  719. removeDeconstructedNode(server, session, node, true);
  720. UA_Nodestore_release(server, node);
  721. return retval;
  722. }
  723. static void
  724. Operation_addNode(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
  725. void *nodeContext, UA_AddNodesResult *result) {
  726. /* Do not check access for server */
  727. if(session != &adminSession && server->config.accessControl.allowAddNode &&
  728. !server->config.accessControl.allowAddNode(&session->sessionId, session->sessionHandle, item)) {
  729. result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
  730. return;
  731. }
  732. result->statusCode = Operation_addNode_begin(server, session, item, nodeContext,
  733. &result->addedNodeId);
  734. if(result->statusCode != UA_STATUSCODE_GOOD)
  735. return;
  736. /* AddNodes_finish */
  737. result->statusCode =
  738. Operation_addNode_finish(server, session, &result->addedNodeId,
  739. &item->parentNodeId.nodeId, &item->referenceTypeId,
  740. &item->typeDefinition.nodeId);
  741. /* If finishing failed, the node was deleted */
  742. if(result->statusCode != UA_STATUSCODE_GOOD)
  743. UA_NodeId_deleteMembers(&result->addedNodeId);
  744. }
  745. static void
  746. Service_AddNode(UA_Server *server, UA_Session *session,
  747. const UA_AddNodesItem *item,
  748. UA_AddNodesResult *result) {
  749. Operation_addNode(server, session, item, NULL, result);
  750. }
  751. void
  752. Service_AddNodes(UA_Server *server, UA_Session *session,
  753. const UA_AddNodesRequest *request,
  754. UA_AddNodesResponse *response) {
  755. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  756. "Processing AddNodesRequest");
  757. response->responseHeader.serviceResult =
  758. UA_Server_processServiceOperations(server, session,
  759. (UA_ServiceOperation)Service_AddNode,
  760. &request->nodesToAddSize, &UA_TYPES[UA_TYPES_ADDNODESITEM],
  761. &response->resultsSize, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
  762. }
  763. UA_StatusCode
  764. __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
  765. const UA_NodeId *requestedNewNodeId,
  766. const UA_NodeId *parentNodeId,
  767. const UA_NodeId *referenceTypeId,
  768. const UA_QualifiedName browseName,
  769. const UA_NodeId *typeDefinition,
  770. const UA_NodeAttributes *attr,
  771. const UA_DataType *attributeType,
  772. void *nodeContext, UA_NodeId *outNewNodeId) {
  773. /* Create the AddNodesItem */
  774. UA_AddNodesItem item;
  775. UA_AddNodesItem_init(&item);
  776. item.nodeClass = nodeClass;
  777. item.requestedNewNodeId.nodeId = *requestedNewNodeId;
  778. item.browseName = browseName;
  779. item.parentNodeId.nodeId = *parentNodeId;
  780. item.referenceTypeId = *referenceTypeId;
  781. item.typeDefinition.nodeId = *typeDefinition;
  782. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  783. item.nodeAttributes.content.decoded.type = attributeType;
  784. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr;
  785. /* Call the normal addnodes service */
  786. UA_AddNodesResult result;
  787. UA_AddNodesResult_init(&result);
  788. Operation_addNode(server, &adminSession, &item, nodeContext, &result);
  789. if(outNewNodeId)
  790. *outNewNodeId = result.addedNodeId;
  791. else
  792. UA_NodeId_deleteMembers(&result.addedNodeId);
  793. return result.statusCode;
  794. }
  795. UA_StatusCode
  796. UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
  797. const UA_NodeId requestedNewNodeId,
  798. const UA_QualifiedName browseName,
  799. const UA_NodeId typeDefinition,
  800. const void *attr, const UA_DataType *attributeType,
  801. void *nodeContext, UA_NodeId *outNewNodeId) {
  802. UA_AddNodesItem item;
  803. UA_AddNodesItem_init(&item);
  804. item.nodeClass = nodeClass;
  805. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  806. item.browseName = browseName;
  807. item.typeDefinition.nodeId = typeDefinition;
  808. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  809. item.nodeAttributes.content.decoded.type = attributeType;
  810. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr;
  811. return Operation_addNode_begin(server, &adminSession, &item,
  812. nodeContext, outNewNodeId);
  813. }
  814. UA_StatusCode
  815. UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
  816. const UA_NodeId parentNodeId,
  817. const UA_NodeId referenceTypeId,
  818. const UA_NodeId typeDefinitionId) {
  819. return Operation_addNode_finish(server, &adminSession, &nodeId, &parentNodeId,
  820. &referenceTypeId, &typeDefinitionId);
  821. }
  822. /****************/
  823. /* Delete Nodes */
  824. /****************/
  825. static void
  826. deleteReference(UA_Server *server, UA_Session *session,
  827. const UA_DeleteReferencesItem *item,
  828. UA_StatusCode *retval);
  829. /* Remove references to this node (in the other nodes) */
  830. static void
  831. removeIncomingReferences(UA_Server *server, UA_Session *session,
  832. const UA_Node *node) {
  833. UA_DeleteReferencesItem item;
  834. UA_DeleteReferencesItem_init(&item);
  835. item.targetNodeId.nodeId = node->nodeId;
  836. item.deleteBidirectional = false;
  837. UA_StatusCode dummy;
  838. for(size_t i = 0; i < node->referencesSize; ++i) {
  839. UA_NodeReferenceKind *refs = &node->references[i];
  840. item.isForward = refs->isInverse;
  841. item.referenceTypeId = refs->referenceTypeId;
  842. for(size_t j = 0; j < refs->targetIdsSize; ++j) {
  843. item.sourceNodeId = refs->targetIds[j].nodeId;
  844. deleteReference(server, session, &item, &dummy);
  845. }
  846. }
  847. }
  848. static void
  849. deconstructNode(UA_Server *server, UA_Session *session,
  850. const UA_Node *node) {
  851. /* Call the type-level destructor */
  852. void *context = node->context; /* No longer needed after this function */
  853. if(node->nodeClass == UA_NODECLASS_OBJECT ||
  854. node->nodeClass == UA_NODECLASS_VARIABLE) {
  855. const UA_Node *type = getNodeType(server, node);
  856. if(type) {
  857. const UA_NodeTypeLifecycle *lifecycle;
  858. if(node->nodeClass == UA_NODECLASS_OBJECT)
  859. lifecycle = &((const UA_ObjectTypeNode*)type)->lifecycle;
  860. else
  861. lifecycle = &((const UA_VariableTypeNode*)type)->lifecycle;
  862. if(lifecycle->destructor)
  863. lifecycle->destructor(server,
  864. &session->sessionId, session->sessionHandle,
  865. &type->nodeId, type->context,
  866. &node->nodeId, &context);
  867. UA_Nodestore_release(server, type);
  868. }
  869. }
  870. /* Call the global destructor */
  871. if(server->config.nodeLifecycle.destructor)
  872. server->config.nodeLifecycle.destructor(server, &session->sessionId,
  873. session->sessionHandle,
  874. &node->nodeId, context);
  875. }
  876. static void
  877. deleteNodeOperation(UA_Server *server, UA_Session *session,
  878. const UA_DeleteNodesItem *item, UA_StatusCode *result);
  879. static void
  880. removeChildren(UA_Server *server, UA_Session *session,
  881. const UA_Node *node) {
  882. /* Browse to get all children of the node */
  883. UA_BrowseDescription bd;
  884. UA_BrowseDescription_init(&bd);
  885. bd.nodeId = node->nodeId;
  886. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  887. bd.includeSubtypes = true;
  888. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  889. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  890. bd.resultMask = UA_BROWSERESULTMASK_NONE;
  891. UA_BrowseResult br;
  892. UA_BrowseResult_init(&br);
  893. Service_Browse_single(server, session, NULL, &bd, 0, &br);
  894. if(br.statusCode != UA_STATUSCODE_GOOD)
  895. return;
  896. UA_DeleteNodesItem item;
  897. item.deleteTargetReferences = true;
  898. /* Remove every child */
  899. for(size_t i = 0; i < br.referencesSize; ++i) {
  900. UA_ReferenceDescription *rd = &br.references[i];
  901. item.nodeId = rd->nodeId.nodeId;
  902. UA_StatusCode retval;
  903. deleteNodeOperation(server, session, &item, &retval);
  904. }
  905. UA_BrowseResult_deleteMembers(&br);
  906. }
  907. static void
  908. removeDeconstructedNode(UA_Server *server, UA_Session *session,
  909. const UA_Node *node, UA_Boolean removeTargetRefs) {
  910. /* Remove all children of the node */
  911. removeChildren(server, session, node);
  912. /* Remove references to the node (not the references going out, as the node
  913. * will be deleted anyway) */
  914. if(removeTargetRefs)
  915. removeIncomingReferences(server, session, node);
  916. /* Remove the node in the nodestore */
  917. UA_Nodestore_remove(server, &node->nodeId);
  918. }
  919. static void
  920. deleteNodeOperation(UA_Server *server, UA_Session *session,
  921. const UA_DeleteNodesItem *item, UA_StatusCode *result) {
  922. /* Do not check access for server */
  923. if(session != &adminSession && server->config.accessControl.allowDeleteNode &&
  924. !server->config.accessControl.allowDeleteNode(&session->sessionId, session->sessionHandle, item)) {
  925. *result = UA_STATUSCODE_BADUSERACCESSDENIED;
  926. return;
  927. }
  928. const UA_Node *node = UA_Nodestore_get(server, &item->nodeId);
  929. if(!node) {
  930. *result = UA_STATUSCODE_BADNODEIDUNKNOWN;
  931. return;
  932. }
  933. if(UA_Node_hasSubTypeOrInstances(node)) {
  934. UA_LOG_INFO_SESSION(server->config.logger, session,
  935. "Delete Nodes: Cannot delete a type node "
  936. "with active instances or subtypes");
  937. UA_Nodestore_release(server, node);
  938. *result = UA_STATUSCODE_BADINTERNALERROR;
  939. return;
  940. }
  941. /* TODO: Check if the information model consistency is violated */
  942. /* TODO: Check if the node is a mandatory child of a parent */
  943. deconstructNode(server, session, node);
  944. removeDeconstructedNode(server, session, node, item->deleteTargetReferences);
  945. UA_Nodestore_release(server, node);
  946. }
  947. void Service_DeleteNodes(UA_Server *server, UA_Session *session,
  948. const UA_DeleteNodesRequest *request,
  949. UA_DeleteNodesResponse *response) {
  950. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  951. "Processing DeleteNodesRequest");
  952. response->responseHeader.serviceResult =
  953. UA_Server_processServiceOperations(server, session,
  954. (UA_ServiceOperation)deleteNodeOperation,
  955. &request->nodesToDeleteSize,
  956. &UA_TYPES[UA_TYPES_DELETENODESITEM],
  957. &response->resultsSize,
  958. &UA_TYPES[UA_TYPES_STATUSCODE]);
  959. }
  960. UA_StatusCode
  961. UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
  962. UA_Boolean deleteReferences) {
  963. UA_DeleteNodesItem item;
  964. item.deleteTargetReferences = deleteReferences;
  965. item.nodeId = nodeId;
  966. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  967. deleteNodeOperation(server, &adminSession, &item, &retval);
  968. return retval;
  969. }
  970. /******************/
  971. /* Add References */
  972. /******************/
  973. static UA_StatusCode
  974. addOneWayReference(UA_Server *server, UA_Session *session,
  975. UA_Node *node, const UA_AddReferencesItem *item) {
  976. return UA_Node_addReference(node, item);
  977. }
  978. static UA_StatusCode
  979. deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
  980. const UA_DeleteReferencesItem *item) {
  981. return UA_Node_deleteReference(node, item);
  982. }
  983. static void
  984. addReference(UA_Server *server, UA_Session *session,
  985. const UA_AddReferencesItem *item, UA_StatusCode *retval) {
  986. /* Do not check access for server */
  987. if(session != &adminSession && server->config.accessControl.allowAddReference &&
  988. !server->config.accessControl. allowAddReference(&session->sessionId, session->sessionHandle, item)) {
  989. *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
  990. return;
  991. }
  992. /* Currently no expandednodeids are allowed */
  993. if(item->targetServerUri.length > 0) {
  994. *retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
  995. return;
  996. }
  997. /* Add the first direction */
  998. *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  999. (UA_EditNodeCallback)addOneWayReference, item);
  1000. if(*retval != UA_STATUSCODE_GOOD)
  1001. return;
  1002. /* Add the second direction */
  1003. UA_AddReferencesItem secondItem;
  1004. UA_AddReferencesItem_init(&secondItem);
  1005. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  1006. secondItem.referenceTypeId = item->referenceTypeId;
  1007. secondItem.isForward = !item->isForward;
  1008. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  1009. /* keep default secondItem.targetNodeClass = UA_NODECLASS_UNSPECIFIED */
  1010. *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  1011. (UA_EditNodeCallback)addOneWayReference, &secondItem);
  1012. /* remove reference if the second direction failed */
  1013. if(*retval != UA_STATUSCODE_GOOD) {
  1014. UA_DeleteReferencesItem deleteItem;
  1015. deleteItem.sourceNodeId = item->sourceNodeId;
  1016. deleteItem.referenceTypeId = item->referenceTypeId;
  1017. deleteItem.isForward = item->isForward;
  1018. deleteItem.targetNodeId = item->targetNodeId;
  1019. deleteItem.deleteBidirectional = false;
  1020. /* ignore returned status code */
  1021. UA_Server_editNode(server, session, &item->sourceNodeId,
  1022. (UA_EditNodeCallback)deleteOneWayReference, &deleteItem);
  1023. }
  1024. }
  1025. void Service_AddReferences(UA_Server *server, UA_Session *session,
  1026. const UA_AddReferencesRequest *request,
  1027. UA_AddReferencesResponse *response) {
  1028. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  1029. "Processing AddReferencesRequest");
  1030. response->responseHeader.serviceResult =
  1031. UA_Server_processServiceOperations(server, session,
  1032. (UA_ServiceOperation) addReference,
  1033. &request->referencesToAddSize,
  1034. &UA_TYPES[UA_TYPES_ADDREFERENCESITEM],
  1035. &response->resultsSize,
  1036. &UA_TYPES[UA_TYPES_STATUSCODE]);
  1037. }
  1038. UA_StatusCode
  1039. UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
  1040. const UA_NodeId refTypeId,
  1041. const UA_ExpandedNodeId targetId,
  1042. UA_Boolean isForward) {
  1043. UA_AddReferencesItem item;
  1044. UA_AddReferencesItem_init(&item);
  1045. item.sourceNodeId = sourceId;
  1046. item.referenceTypeId = refTypeId;
  1047. item.isForward = isForward;
  1048. item.targetNodeId = targetId;
  1049. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1050. addReference(server, &adminSession, &item, &retval);
  1051. return retval;
  1052. }
  1053. /*********************/
  1054. /* Delete References */
  1055. /*********************/
  1056. static void
  1057. deleteReference(UA_Server *server, UA_Session *session,
  1058. const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
  1059. /* Do not check access for server */
  1060. if(session != &adminSession && server->config.accessControl.allowDeleteReference &&
  1061. !server->config.accessControl.allowDeleteReference(&session->sessionId, session->sessionHandle, item)) {
  1062. *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
  1063. return;
  1064. }
  1065. // TODO: Check consistency constraints, remove the references.
  1066. *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  1067. (UA_EditNodeCallback)deleteOneWayReference, item);
  1068. if(*retval != UA_STATUSCODE_GOOD)
  1069. return;
  1070. if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
  1071. return;
  1072. UA_DeleteReferencesItem secondItem;
  1073. UA_DeleteReferencesItem_init(&secondItem);
  1074. secondItem.isForward = !item->isForward;
  1075. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  1076. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  1077. secondItem.referenceTypeId = item->referenceTypeId;
  1078. *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  1079. (UA_EditNodeCallback)deleteOneWayReference,
  1080. &secondItem);
  1081. }
  1082. void
  1083. Service_DeleteReferences(UA_Server *server, UA_Session *session,
  1084. const UA_DeleteReferencesRequest *request,
  1085. UA_DeleteReferencesResponse *response) {
  1086. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  1087. "Processing DeleteReferencesRequest");
  1088. response->responseHeader.serviceResult =
  1089. UA_Server_processServiceOperations(server, session,
  1090. (UA_ServiceOperation) deleteReference,
  1091. &request->referencesToDeleteSize,
  1092. &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM],
  1093. &response->resultsSize,
  1094. &UA_TYPES[UA_TYPES_STATUSCODE]);
  1095. }
  1096. UA_StatusCode
  1097. UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
  1098. const UA_NodeId referenceTypeId, UA_Boolean isForward,
  1099. const UA_ExpandedNodeId targetNodeId,
  1100. UA_Boolean deleteBidirectional) {
  1101. UA_DeleteReferencesItem item;
  1102. item.sourceNodeId = sourceNodeId;
  1103. item.referenceTypeId = referenceTypeId;
  1104. item.isForward = isForward;
  1105. item.targetNodeId = targetNodeId;
  1106. item.deleteBidirectional = deleteBidirectional;
  1107. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1108. deleteReference(server, &adminSession, &item, &retval);
  1109. return retval;
  1110. }
  1111. /**********************/
  1112. /* Set Value Callback */
  1113. /**********************/
  1114. static UA_StatusCode
  1115. setValueCallback(UA_Server *server, UA_Session *session,
  1116. UA_VariableNode *node, UA_ValueCallback *callback) {
  1117. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1118. return UA_STATUSCODE_BADNODECLASSINVALID;
  1119. node->value.data.callback = *callback;
  1120. return UA_STATUSCODE_GOOD;
  1121. }
  1122. UA_StatusCode
  1123. UA_Server_setVariableNode_valueCallback(UA_Server *server,
  1124. const UA_NodeId nodeId,
  1125. const UA_ValueCallback callback) {
  1126. return UA_Server_editNode(server, &adminSession, &nodeId,
  1127. (UA_EditNodeCallback)setValueCallback, &callback);
  1128. }
  1129. /***************************************************/
  1130. /* Special Handling of Variables with Data Sources */
  1131. /***************************************************/
  1132. UA_StatusCode
  1133. UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  1134. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  1135. const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
  1136. const UA_VariableAttributes attr, const UA_DataSource dataSource,
  1137. void *nodeContext, UA_NodeId *outNewNodeId) {
  1138. UA_AddNodesItem item;
  1139. UA_AddNodesItem_init(&item);
  1140. item.nodeClass = UA_NODECLASS_VARIABLE;
  1141. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  1142. item.browseName = browseName;
  1143. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  1144. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr;
  1145. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
  1146. UA_NodeId newNodeId;
  1147. UA_Boolean deleteNodeId = UA_FALSE;
  1148. if(!outNewNodeId) {
  1149. newNodeId = UA_NODEID_NULL;
  1150. outNewNodeId = &newNodeId;
  1151. deleteNodeId = UA_TRUE;
  1152. }
  1153. UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, &item,
  1154. nodeContext, outNewNodeId);
  1155. if(retval != UA_STATUSCODE_GOOD)
  1156. return retval;
  1157. retval = UA_Server_setVariableNode_dataSource(server, *outNewNodeId, dataSource);
  1158. if(retval == UA_STATUSCODE_GOOD)
  1159. retval = Operation_addNode_finish(server, &adminSession, outNewNodeId,
  1160. &parentNodeId, &referenceTypeId, &typeDefinition);
  1161. if(retval != UA_STATUSCODE_GOOD || deleteNodeId)
  1162. UA_NodeId_deleteMembers(outNewNodeId);
  1163. return retval;
  1164. }
  1165. static UA_StatusCode
  1166. setDataSource(UA_Server *server, UA_Session *session,
  1167. UA_VariableNode* node, UA_DataSource *dataSource) {
  1168. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1169. return UA_STATUSCODE_BADNODECLASSINVALID;
  1170. if(node->valueSource == UA_VALUESOURCE_DATA)
  1171. UA_DataValue_deleteMembers(&node->value.data.value);
  1172. node->value.dataSource = *dataSource;
  1173. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  1174. return UA_STATUSCODE_GOOD;
  1175. }
  1176. UA_StatusCode
  1177. UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  1178. const UA_DataSource dataSource) {
  1179. return UA_Server_editNode(server, &adminSession, &nodeId,
  1180. (UA_EditNodeCallback)setDataSource,
  1181. &dataSource);
  1182. }
  1183. /************************************/
  1184. /* Special Handling of Method Nodes */
  1185. /************************************/
  1186. #ifdef UA_ENABLE_METHODCALLS
  1187. static const UA_NodeId hasproperty = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASPROPERTY}};
  1188. static const UA_NodeId propertytype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_PROPERTYTYPE}};
  1189. UA_StatusCode
  1190. UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
  1191. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  1192. UA_MethodCallback method,
  1193. size_t inputArgumentsSize, const UA_Argument* inputArguments,
  1194. size_t outputArgumentsSize, const UA_Argument* outputArguments) {
  1195. /* Browse to see which argument nodes exist */
  1196. UA_BrowseDescription bd;
  1197. UA_BrowseDescription_init(&bd);
  1198. bd.nodeId = nodeId;
  1199. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
  1200. bd.includeSubtypes = false;
  1201. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  1202. bd.nodeClassMask = UA_NODECLASS_VARIABLE;
  1203. bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;
  1204. UA_BrowseResult br;
  1205. UA_BrowseResult_init(&br);
  1206. Service_Browse_single(server, &adminSession, NULL, &bd, 0, &br);
  1207. UA_StatusCode retval = br.statusCode;
  1208. if(retval != UA_STATUSCODE_GOOD) {
  1209. UA_Server_deleteNode(server, nodeId, true);
  1210. UA_BrowseResult_deleteMembers(&br);
  1211. return retval;
  1212. }
  1213. /* Filter out the argument nodes */
  1214. UA_NodeId inputArgsId = UA_NODEID_NULL;
  1215. UA_NodeId outputArgsId = UA_NODEID_NULL;
  1216. const UA_NodeId newArgsId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
  1217. const UA_QualifiedName inputArgsName = UA_QUALIFIEDNAME(0, "InputArguments");
  1218. const UA_QualifiedName outputArgsName = UA_QUALIFIEDNAME(0, "OutputArguments");
  1219. for(size_t i = 0; i < br.referencesSize; i++) {
  1220. UA_ReferenceDescription *rd = &br.references[i];
  1221. if(rd->browseName.namespaceIndex == 0 &&
  1222. UA_String_equal(&rd->browseName.name, &inputArgsName.name))
  1223. inputArgsId = rd->nodeId.nodeId;
  1224. else if(rd->browseName.namespaceIndex == 0 &&
  1225. UA_String_equal(&rd->browseName.name, &outputArgsName.name))
  1226. outputArgsId = rd->nodeId.nodeId;
  1227. }
  1228. /* Add the Input Arguments VariableNode */
  1229. if(inputArgumentsSize > 0 && UA_NodeId_isNull(&inputArgsId)) {
  1230. UA_VariableAttributes inputargs = UA_VariableAttributes_default;
  1231. inputargs.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
  1232. /* UAExpert creates a monitoreditem on inputarguments ... */
  1233. inputargs.minimumSamplingInterval = 100000.0f;
  1234. inputargs.valueRank = 1;
  1235. inputargs.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
  1236. /* dirty-cast, but is treated as const ... */
  1237. UA_Variant_setArray(&inputargs.value, (void*)(uintptr_t)inputArguments,
  1238. inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  1239. retval = UA_Server_addVariableNode(server, newArgsId, nodeId, hasproperty,
  1240. inputArgsName, propertytype, inputargs,
  1241. NULL, &inputArgsId);
  1242. }
  1243. /* Add the Output Arguments VariableNode */
  1244. if(outputArgumentsSize > 0 && UA_NodeId_isNull(&outputArgsId)) {
  1245. UA_VariableAttributes outputargs = UA_VariableAttributes_default;
  1246. outputargs.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
  1247. /* UAExpert creates a monitoreditem on outputarguments ... */
  1248. outputargs.minimumSamplingInterval = 100000.0f;
  1249. outputargs.valueRank = 1;
  1250. outputargs.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
  1251. /* dirty-cast, but is treated as const ... */
  1252. UA_Variant_setArray(&outputargs.value, (void*)(uintptr_t)outputArguments,
  1253. outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  1254. retval |= UA_Server_addVariableNode(server, newArgsId, nodeId, hasproperty,
  1255. outputArgsName, propertytype, outputargs,
  1256. NULL, &outputArgsId);
  1257. }
  1258. retval |= UA_Server_setMethodNode_callback(server, nodeId, method);
  1259. /* Call finish to add the parent reference */
  1260. retval |= Operation_addNode_finish(server, &adminSession, &nodeId, &parentNodeId,
  1261. &referenceTypeId, &UA_NODEID_NULL);
  1262. if(retval != UA_STATUSCODE_GOOD) {
  1263. UA_Server_deleteNode(server, nodeId, true);
  1264. UA_Server_deleteNode(server, inputArgsId, true);
  1265. UA_Server_deleteNode(server, outputArgsId, true);
  1266. }
  1267. UA_BrowseResult_deleteMembers(&br);
  1268. return retval;
  1269. }
  1270. UA_StatusCode
  1271. UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  1272. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  1273. const UA_QualifiedName browseName, const UA_MethodAttributes attr,
  1274. UA_MethodCallback method,
  1275. size_t inputArgumentsSize, const UA_Argument* inputArguments,
  1276. size_t outputArgumentsSize, const UA_Argument* outputArguments,
  1277. void *nodeContext, UA_NodeId *outNewNodeId) {
  1278. UA_AddNodesItem item;
  1279. UA_AddNodesItem_init(&item);
  1280. item.nodeClass = UA_NODECLASS_METHOD;
  1281. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  1282. item.browseName = browseName;
  1283. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  1284. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr;
  1285. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_METHODATTRIBUTES];
  1286. UA_NodeId newId;
  1287. if(!outNewNodeId) {
  1288. UA_NodeId_init(&newId);
  1289. outNewNodeId = &newId;
  1290. }
  1291. UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, &item,
  1292. nodeContext, outNewNodeId);
  1293. if(retval != UA_STATUSCODE_GOOD)
  1294. return retval;
  1295. retval = UA_Server_addMethodNode_finish(server, *outNewNodeId,
  1296. parentNodeId, referenceTypeId, method,
  1297. inputArgumentsSize, inputArguments,
  1298. outputArgumentsSize, outputArguments);
  1299. if(outNewNodeId == &newId)
  1300. UA_NodeId_deleteMembers(&newId);
  1301. return retval;
  1302. }
  1303. static UA_StatusCode
  1304. editMethodCallback(UA_Server *server, UA_Session* session,
  1305. UA_Node* node, void* handle) {
  1306. if(node->nodeClass != UA_NODECLASS_METHOD)
  1307. return UA_STATUSCODE_BADNODECLASSINVALID;
  1308. UA_MethodNode *mnode = (UA_MethodNode*) node;
  1309. mnode->method = (UA_MethodCallback)(uintptr_t)handle;
  1310. return UA_STATUSCODE_GOOD;
  1311. }
  1312. UA_StatusCode
  1313. UA_Server_setMethodNode_callback(UA_Server *server,
  1314. const UA_NodeId methodNodeId,
  1315. UA_MethodCallback methodCallback) {
  1316. return UA_Server_editNode(server, &adminSession, &methodNodeId,
  1317. (UA_EditNodeCallback)editMethodCallback,
  1318. (void*)(uintptr_t)methodCallback);
  1319. }
  1320. #endif
  1321. /************************/
  1322. /* Lifecycle Management */
  1323. /************************/
  1324. static UA_StatusCode
  1325. setNodeTypeLifecycle(UA_Server *server, UA_Session *session,
  1326. UA_Node* node, UA_NodeTypeLifecycle *lifecycle) {
  1327. if(node->nodeClass == UA_NODECLASS_OBJECTTYPE) {
  1328. UA_ObjectTypeNode *ot = (UA_ObjectTypeNode*)node;
  1329. ot->lifecycle = *lifecycle;
  1330. return UA_STATUSCODE_GOOD;
  1331. }
  1332. if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
  1333. UA_VariableTypeNode *vt = (UA_VariableTypeNode*)node;
  1334. vt->lifecycle = *lifecycle;
  1335. return UA_STATUSCODE_GOOD;
  1336. }
  1337. return UA_STATUSCODE_BADNODECLASSINVALID;
  1338. }
  1339. UA_StatusCode
  1340. UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
  1341. UA_NodeTypeLifecycle lifecycle) {
  1342. return UA_Server_editNode(server, &adminSession, &nodeId,
  1343. (UA_EditNodeCallback)setNodeTypeLifecycle,
  1344. &lifecycle);
  1345. }