ua_services_nodemanagement.c 61 KB

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