ua_services_nodemanagement.c 60 KB

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