ua_services_nodemanagement.c 55 KB

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