ua_services_nodemanagement.c 56 KB

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