ua_services_nodemanagement.c 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430
  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. UA_StatusCode
  533. Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
  534. const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
  535. const UA_NodeId *typeDefinitionId, UA_Boolean overrideChecks) {
  536. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  537. const UA_Node *type = NULL;
  538. /* Get the node */
  539. const UA_Node *node = UA_Nodestore_get(server, nodeId);
  540. if(!node)
  541. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  542. if(overrideChecks)
  543. goto get_type;
  544. /* Use the typeDefinition as parent for type-nodes */
  545. if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
  546. node->nodeClass == UA_NODECLASS_OBJECTTYPE ||
  547. node->nodeClass == UA_NODECLASS_REFERENCETYPE ||
  548. node->nodeClass == UA_NODECLASS_DATATYPE) {
  549. referenceTypeId = &hasSubtype;
  550. typeDefinitionId = parentNodeId;
  551. }
  552. /* Check parent reference. Objects may have no parent. */
  553. retval = checkParentReference(server, session, node->nodeClass,
  554. parentNodeId, referenceTypeId);
  555. if(retval != UA_STATUSCODE_GOOD) {
  556. UA_LOG_INFO_SESSION(server->config.logger, session,
  557. "AddNodes: The parent reference is invalid");
  558. UA_Nodestore_release(server, node);
  559. UA_Server_deleteNode(server, *nodeId, true);
  560. return retval;
  561. }
  562. /* Replace empty typeDefinition with the most permissive default */
  563. if((node->nodeClass == UA_NODECLASS_VARIABLE ||
  564. node->nodeClass == UA_NODECLASS_OBJECT) &&
  565. UA_NodeId_isNull(typeDefinitionId)) {
  566. UA_LOG_INFO_SESSION(server->config.logger, session,
  567. "AddNodes: No TypeDefinition; Use the default "
  568. "TypeDefinition for the Variable/Object");
  569. if(node->nodeClass == UA_NODECLASS_VARIABLE)
  570. typeDefinitionId = &baseDataVariableType;
  571. else
  572. typeDefinitionId = &baseObjectType;
  573. }
  574. get_type:
  575. /* Get the node type. There must be a typedefinition for variables, objects
  576. * and type-nodes. See the above checks. */
  577. if(!UA_NodeId_isNull(typeDefinitionId)) {
  578. /* Get the type node */
  579. type = UA_Nodestore_get(server, typeDefinitionId);
  580. if(!type) {
  581. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  582. goto cleanup;
  583. }
  584. /* See if the type has the correct node class. For type-nodes, we know
  585. * that type has the same nodeClass from checkParentReference. */
  586. if(node->nodeClass == UA_NODECLASS_VARIABLE) {
  587. if(type->nodeClass != UA_NODECLASS_VARIABLETYPE ||
  588. ((const UA_VariableTypeNode*)type)->isAbstract) {
  589. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  590. goto cleanup;
  591. }
  592. }
  593. if(node->nodeClass == UA_NODECLASS_OBJECT) {
  594. if(type->nodeClass != UA_NODECLASS_OBJECTTYPE ||
  595. ((const UA_ObjectTypeNode*)type)->isAbstract) {
  596. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  597. goto cleanup;
  598. }
  599. }
  600. }
  601. /* Check if all attributes hold the constraints of the type now. The initial
  602. * attributes must type-check. The constructor might change the attributes
  603. * again. Then, the changes are type-checked by the normal write service. */
  604. if(type && (node->nodeClass == UA_NODECLASS_VARIABLE ||
  605. node->nodeClass == UA_NODECLASS_VARIABLETYPE)) {
  606. retval = typeCheckVariableNode(server, session,
  607. (const UA_VariableNode*)node,
  608. (const UA_VariableTypeNode*)type);
  609. if(retval != UA_STATUSCODE_GOOD) {
  610. UA_LOG_INFO_SESSION(server->config.logger, session,
  611. "AddNodes: Type-checking the variable node "
  612. "failed with error code %s", UA_StatusCode_name(retval));
  613. goto cleanup;
  614. }
  615. }
  616. /* Instantiate variables and objects */
  617. if(node->nodeClass == UA_NODECLASS_VARIABLE ||
  618. node->nodeClass == UA_NODECLASS_OBJECT) {
  619. UA_assert(type != NULL); /* see above */
  620. /* Add (mandatory) child nodes from the type definition */
  621. retval = addChildren(server, session, node, type);
  622. if(retval != UA_STATUSCODE_GOOD) {
  623. UA_LOG_INFO_SESSION(server->config.logger, session,
  624. "AddNodes: Adding child nodes failed with error code %s",
  625. UA_StatusCode_name(retval));
  626. goto cleanup;
  627. }
  628. /* Add a hasTypeDefinition reference */
  629. retval = addTypeDefRef(server, session, node, type);
  630. if(retval != UA_STATUSCODE_GOOD) {
  631. UA_LOG_INFO_SESSION(server->config.logger, session,
  632. "AddNodes: Adding a reference to the type "
  633. "definition failed with error code %s",
  634. UA_StatusCode_name(retval));
  635. goto cleanup;
  636. }
  637. }
  638. /* Add reference to the parent */
  639. if(!UA_NodeId_isNull(parentNodeId)) {
  640. retval = addParentRef(server, session, nodeId, referenceTypeId, parentNodeId);
  641. if(retval != UA_STATUSCODE_GOOD) {
  642. UA_LOG_INFO_SESSION(server->config.logger, session,
  643. "AddNodes: Adding reference to parent failed");
  644. goto cleanup;
  645. }
  646. }
  647. /* Call the constructor(s) */
  648. retval = callConstructors(server, session, node, type);
  649. if(retval != UA_STATUSCODE_GOOD) {
  650. UA_LOG_INFO_SESSION(server->config.logger, session,
  651. "AddNodes: Calling the node constructor(s) failed "
  652. "with status code %s", UA_StatusCode_name(retval));
  653. }
  654. cleanup:
  655. if(type)
  656. UA_Nodestore_release(server, type);
  657. if(retval != UA_STATUSCODE_GOOD)
  658. removeDeconstructedNode(server, session, node, true);
  659. UA_Nodestore_release(server, node);
  660. return retval;
  661. }
  662. static void
  663. Operation_addNode(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
  664. void *nodeContext, UA_AddNodesResult *result) {
  665. /* Do not check access for server */
  666. if(session != &adminSession && server->config.accessControl.allowAddNode &&
  667. !server->config.accessControl.allowAddNode(&session->sessionId, session->sessionHandle, item)) {
  668. result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
  669. return;
  670. }
  671. result->statusCode = Operation_addNode_begin(server, session, item, nodeContext,
  672. &result->addedNodeId, false);
  673. if(result->statusCode != UA_STATUSCODE_GOOD)
  674. return;
  675. result->statusCode =
  676. Operation_addNode_finish(server, session, &result->addedNodeId,
  677. &item->parentNodeId.nodeId, &item->referenceTypeId,
  678. &item->typeDefinition.nodeId, false);
  679. /* If finishing failed, the node was deleted */
  680. if(result->statusCode != UA_STATUSCODE_GOOD)
  681. UA_NodeId_deleteMembers(&result->addedNodeId);
  682. }
  683. static void
  684. Service_AddNode(UA_Server *server, UA_Session *session,
  685. const UA_AddNodesItem *item,
  686. UA_AddNodesResult *result) {
  687. Operation_addNode(server, session, item, NULL, result);
  688. }
  689. void
  690. Service_AddNodes(UA_Server *server, UA_Session *session,
  691. const UA_AddNodesRequest *request,
  692. UA_AddNodesResponse *response) {
  693. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  694. "Processing AddNodesRequest");
  695. response->responseHeader.serviceResult =
  696. UA_Server_processServiceOperations(server, session,
  697. (UA_ServiceOperation)Service_AddNode,
  698. &request->nodesToAddSize, &UA_TYPES[UA_TYPES_ADDNODESITEM],
  699. &response->resultsSize, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
  700. }
  701. UA_StatusCode
  702. __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
  703. const UA_NodeId *requestedNewNodeId,
  704. const UA_NodeId *parentNodeId,
  705. const UA_NodeId *referenceTypeId,
  706. const UA_QualifiedName browseName,
  707. const UA_NodeId *typeDefinition,
  708. const UA_NodeAttributes *attr,
  709. const UA_DataType *attributeType,
  710. void *nodeContext, UA_NodeId *outNewNodeId) {
  711. /* Create the AddNodesItem */
  712. UA_AddNodesItem item;
  713. UA_AddNodesItem_init(&item);
  714. item.requestedNewNodeId.nodeId = *requestedNewNodeId;
  715. item.browseName = browseName;
  716. item.nodeClass = nodeClass;
  717. item.parentNodeId.nodeId = *parentNodeId;
  718. item.referenceTypeId = *referenceTypeId;
  719. item.typeDefinition.nodeId = *typeDefinition;
  720. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  721. item.nodeAttributes.content.decoded.type =attributeType;
  722. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr;
  723. /* Call the normal addnodes service */
  724. UA_AddNodesResult result;
  725. UA_AddNodesResult_init(&result);
  726. Operation_addNode(server, &adminSession, &item, nodeContext, &result);
  727. if(outNewNodeId)
  728. *outNewNodeId = result.addedNodeId;
  729. else
  730. UA_NodeId_deleteMembers(&result.addedNodeId);
  731. return result.statusCode;
  732. }
  733. /****************/
  734. /* Delete Nodes */
  735. /****************/
  736. static void
  737. deleteReference(UA_Server *server, UA_Session *session,
  738. const UA_DeleteReferencesItem *item,
  739. UA_StatusCode *retval);
  740. /* Remove references to this node (in the other nodes) */
  741. static void
  742. removeIncomingReferences(UA_Server *server, UA_Session *session,
  743. const UA_Node *node) {
  744. UA_DeleteReferencesItem item;
  745. UA_DeleteReferencesItem_init(&item);
  746. item.targetNodeId.nodeId = node->nodeId;
  747. item.deleteBidirectional = false;
  748. UA_StatusCode dummy;
  749. for(size_t i = 0; i < node->referencesSize; ++i) {
  750. UA_NodeReferenceKind *refs = &node->references[i];
  751. item.isForward = refs->isInverse;
  752. item.referenceTypeId = refs->referenceTypeId;
  753. for(size_t j = 0; j < refs->targetIdsSize; ++j) {
  754. item.sourceNodeId = refs->targetIds[j].nodeId;
  755. deleteReference(server, session, &item, &dummy);
  756. }
  757. }
  758. }
  759. static void
  760. deconstructNode(UA_Server *server, UA_Session *session,
  761. const UA_Node *node) {
  762. /* Call the type-level destructor */
  763. void *context = node->context; /* No longer needed after this function */
  764. if(node->nodeClass == UA_NODECLASS_OBJECT ||
  765. node->nodeClass == UA_NODECLASS_VARIABLE) {
  766. const UA_Node *type = getNodeType(server, node);
  767. if(type) {
  768. const UA_NodeTypeLifecycle *lifecycle;
  769. if(node->nodeClass == UA_NODECLASS_OBJECT)
  770. lifecycle = &((const UA_ObjectTypeNode*)type)->lifecycle;
  771. else
  772. lifecycle = &((const UA_VariableTypeNode*)type)->lifecycle;
  773. if(lifecycle->destructor)
  774. lifecycle->destructor(server,
  775. &session->sessionId, session->sessionHandle,
  776. &type->nodeId, type->context,
  777. &node->nodeId, &context);
  778. UA_Nodestore_release(server, type);
  779. }
  780. }
  781. /* Call the global destructor */
  782. if(server->config.nodeLifecycle.destructor)
  783. server->config.nodeLifecycle.destructor(server, &session->sessionId,
  784. session->sessionHandle,
  785. &node->nodeId, context);
  786. }
  787. static void
  788. deleteNodeOperation(UA_Server *server, UA_Session *session,
  789. const UA_DeleteNodesItem *item, UA_StatusCode *result);
  790. static void
  791. removeChildren(UA_Server *server, UA_Session *session,
  792. const UA_Node *node) {
  793. /* Browse to get all children of the node */
  794. UA_BrowseDescription bd;
  795. UA_BrowseDescription_init(&bd);
  796. bd.nodeId = node->nodeId;
  797. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  798. bd.includeSubtypes = true;
  799. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  800. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  801. bd.resultMask = UA_BROWSERESULTMASK_NONE;
  802. UA_BrowseResult br;
  803. UA_BrowseResult_init(&br);
  804. Service_Browse_single(server, session, NULL, &bd, 0, &br);
  805. if(br.statusCode != UA_STATUSCODE_GOOD)
  806. return;
  807. UA_DeleteNodesItem item;
  808. item.deleteTargetReferences = true;
  809. /* Remove every child */
  810. for(size_t i = 0; i < br.referencesSize; ++i) {
  811. UA_ReferenceDescription *rd = &br.references[i];
  812. item.nodeId = rd->nodeId.nodeId;
  813. UA_StatusCode retval;
  814. deleteNodeOperation(server, session, &item, &retval);
  815. }
  816. UA_BrowseResult_deleteMembers(&br);
  817. }
  818. static void
  819. removeDeconstructedNode(UA_Server *server, UA_Session *session,
  820. const UA_Node *node, UA_Boolean removeTargetRefs) {
  821. /* Remove all children of the node */
  822. removeChildren(server, session, node);
  823. /* Remove references to the node (not the references going out, as the node
  824. * will be deleted anyway) */
  825. if(removeTargetRefs)
  826. removeIncomingReferences(server, session, node);
  827. /* Remove the node in the nodestore */
  828. UA_Nodestore_remove(server, &node->nodeId);
  829. }
  830. static void
  831. deleteNodeOperation(UA_Server *server, UA_Session *session,
  832. const UA_DeleteNodesItem *item, UA_StatusCode *result) {
  833. /* Do not check access for server */
  834. if(session != &adminSession && server->config.accessControl.allowDeleteNode &&
  835. !server->config.accessControl.allowDeleteNode(&session->sessionId, session->sessionHandle, item)) {
  836. *result = UA_STATUSCODE_BADUSERACCESSDENIED;
  837. return;
  838. }
  839. const UA_Node *node = UA_Nodestore_get(server, &item->nodeId);
  840. if(!node) {
  841. *result = UA_STATUSCODE_BADNODEIDUNKNOWN;
  842. return;
  843. }
  844. if(UA_Node_hasSubTypeOrInstances(node)) {
  845. UA_LOG_INFO_SESSION(server->config.logger, session,
  846. "Delete Nodes: Cannot delete a type node "
  847. "with active instances or subtypes");
  848. UA_Nodestore_release(server, node);
  849. *result = UA_STATUSCODE_BADINTERNALERROR;
  850. return;
  851. }
  852. /* TODO: Check if the information model consistency is violated */
  853. /* TODO: Check if the node is a mandatory child of a parent */
  854. deconstructNode(server, session, node);
  855. removeDeconstructedNode(server, session, node, item->deleteTargetReferences);
  856. UA_Nodestore_release(server, node);
  857. }
  858. void Service_DeleteNodes(UA_Server *server, UA_Session *session,
  859. const UA_DeleteNodesRequest *request,
  860. UA_DeleteNodesResponse *response) {
  861. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  862. "Processing DeleteNodesRequest");
  863. response->responseHeader.serviceResult =
  864. UA_Server_processServiceOperations(server, session,
  865. (UA_ServiceOperation)deleteNodeOperation,
  866. &request->nodesToDeleteSize,
  867. &UA_TYPES[UA_TYPES_DELETENODESITEM],
  868. &response->resultsSize,
  869. &UA_TYPES[UA_TYPES_STATUSCODE]);
  870. }
  871. UA_StatusCode
  872. UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
  873. UA_Boolean deleteReferences) {
  874. UA_DeleteNodesItem item;
  875. item.deleteTargetReferences = deleteReferences;
  876. item.nodeId = nodeId;
  877. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  878. deleteNodeOperation(server, &adminSession, &item, &retval);
  879. return retval;
  880. }
  881. /******************/
  882. /* Add References */
  883. /******************/
  884. static UA_StatusCode
  885. addOneWayReference(UA_Server *server, UA_Session *session,
  886. UA_Node *node, const UA_AddReferencesItem *item) {
  887. return UA_Node_addReference(node, item);
  888. }
  889. static UA_StatusCode
  890. deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
  891. const UA_DeleteReferencesItem *item) {
  892. return UA_Node_deleteReference(node, item);
  893. }
  894. static void
  895. addReference(UA_Server *server, UA_Session *session,
  896. const UA_AddReferencesItem *item, UA_StatusCode *retval) {
  897. /* Do not check access for server */
  898. if(session != &adminSession && server->config.accessControl.allowAddReference &&
  899. !server->config.accessControl. allowAddReference(&session->sessionId, session->sessionHandle, item)) {
  900. *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
  901. return;
  902. }
  903. /* Currently no expandednodeids are allowed */
  904. if(item->targetServerUri.length > 0) {
  905. *retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
  906. return;
  907. }
  908. /* Add the first direction */
  909. *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  910. (UA_EditNodeCallback)addOneWayReference, item);
  911. if(*retval != UA_STATUSCODE_GOOD)
  912. return;
  913. /* Add the second direction */
  914. UA_AddReferencesItem secondItem;
  915. UA_AddReferencesItem_init(&secondItem);
  916. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  917. secondItem.referenceTypeId = item->referenceTypeId;
  918. secondItem.isForward = !item->isForward;
  919. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  920. /* keep default secondItem.targetNodeClass = UA_NODECLASS_UNSPECIFIED */
  921. *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  922. (UA_EditNodeCallback)addOneWayReference, &secondItem);
  923. /* remove reference if the second direction failed */
  924. if(*retval != UA_STATUSCODE_GOOD) {
  925. UA_DeleteReferencesItem deleteItem;
  926. deleteItem.sourceNodeId = item->sourceNodeId;
  927. deleteItem.referenceTypeId = item->referenceTypeId;
  928. deleteItem.isForward = item->isForward;
  929. deleteItem.targetNodeId = item->targetNodeId;
  930. deleteItem.deleteBidirectional = false;
  931. /* ignore returned status code */
  932. UA_Server_editNode(server, session, &item->sourceNodeId,
  933. (UA_EditNodeCallback)deleteOneWayReference, &deleteItem);
  934. }
  935. }
  936. void Service_AddReferences(UA_Server *server, UA_Session *session,
  937. const UA_AddReferencesRequest *request,
  938. UA_AddReferencesResponse *response) {
  939. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  940. "Processing AddReferencesRequest");
  941. response->responseHeader.serviceResult =
  942. UA_Server_processServiceOperations(server, session,
  943. (UA_ServiceOperation) addReference,
  944. &request->referencesToAddSize,
  945. &UA_TYPES[UA_TYPES_ADDREFERENCESITEM],
  946. &response->resultsSize,
  947. &UA_TYPES[UA_TYPES_STATUSCODE]);
  948. }
  949. UA_StatusCode
  950. UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
  951. const UA_NodeId refTypeId,
  952. const UA_ExpandedNodeId targetId,
  953. UA_Boolean isForward) {
  954. UA_AddReferencesItem item;
  955. UA_AddReferencesItem_init(&item);
  956. item.sourceNodeId = sourceId;
  957. item.referenceTypeId = refTypeId;
  958. item.isForward = isForward;
  959. item.targetNodeId = targetId;
  960. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  961. addReference(server, &adminSession, &item, &retval);
  962. return retval;
  963. }
  964. /*********************/
  965. /* Delete References */
  966. /*********************/
  967. static void
  968. deleteReference(UA_Server *server, UA_Session *session,
  969. const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
  970. /* Do not check access for server */
  971. if(session != &adminSession && server->config.accessControl.allowDeleteReference &&
  972. !server->config.accessControl.allowDeleteReference(&session->sessionId, session->sessionHandle, item)) {
  973. *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
  974. return;
  975. }
  976. // TODO: Check consistency constraints, remove the references.
  977. *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  978. (UA_EditNodeCallback)deleteOneWayReference, item);
  979. if(*retval != UA_STATUSCODE_GOOD)
  980. return;
  981. if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
  982. return;
  983. UA_DeleteReferencesItem secondItem;
  984. UA_DeleteReferencesItem_init(&secondItem);
  985. secondItem.isForward = !item->isForward;
  986. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  987. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  988. secondItem.referenceTypeId = item->referenceTypeId;
  989. *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  990. (UA_EditNodeCallback)deleteOneWayReference,
  991. &secondItem);
  992. }
  993. void
  994. Service_DeleteReferences(UA_Server *server, UA_Session *session,
  995. const UA_DeleteReferencesRequest *request,
  996. UA_DeleteReferencesResponse *response) {
  997. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  998. "Processing DeleteReferencesRequest");
  999. response->responseHeader.serviceResult =
  1000. UA_Server_processServiceOperations(server, session,
  1001. (UA_ServiceOperation) deleteReference,
  1002. &request->referencesToDeleteSize,
  1003. &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM],
  1004. &response->resultsSize,
  1005. &UA_TYPES[UA_TYPES_STATUSCODE]);
  1006. }
  1007. UA_StatusCode
  1008. UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
  1009. const UA_NodeId referenceTypeId, UA_Boolean isForward,
  1010. const UA_ExpandedNodeId targetNodeId,
  1011. UA_Boolean deleteBidirectional) {
  1012. UA_DeleteReferencesItem item;
  1013. item.sourceNodeId = sourceNodeId;
  1014. item.referenceTypeId = referenceTypeId;
  1015. item.isForward = isForward;
  1016. item.targetNodeId = targetNodeId;
  1017. item.deleteBidirectional = deleteBidirectional;
  1018. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1019. deleteReference(server, &adminSession, &item, &retval);
  1020. return retval;
  1021. }
  1022. /**********************/
  1023. /* Set Value Callback */
  1024. /**********************/
  1025. static UA_StatusCode
  1026. setValueCallback(UA_Server *server, UA_Session *session,
  1027. UA_VariableNode *node, UA_ValueCallback *callback) {
  1028. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1029. return UA_STATUSCODE_BADNODECLASSINVALID;
  1030. node->value.data.callback = *callback;
  1031. return UA_STATUSCODE_GOOD;
  1032. }
  1033. UA_StatusCode
  1034. UA_Server_setVariableNode_valueCallback(UA_Server *server,
  1035. const UA_NodeId nodeId,
  1036. const UA_ValueCallback callback) {
  1037. return UA_Server_editNode(server, &adminSession, &nodeId,
  1038. (UA_EditNodeCallback)setValueCallback, &callback);
  1039. }
  1040. /***************************************************/
  1041. /* Special Handling of Variables with Data Sources */
  1042. /***************************************************/
  1043. UA_StatusCode
  1044. UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  1045. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  1046. const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
  1047. const UA_VariableAttributes attr, const UA_DataSource dataSource,
  1048. void *nodeContext, UA_NodeId *outNewNodeId) {
  1049. UA_AddNodesItem item;
  1050. UA_AddNodesItem_init(&item);
  1051. item.nodeClass = UA_NODECLASS_VARIABLE;
  1052. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  1053. item.browseName = browseName;
  1054. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  1055. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr;
  1056. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
  1057. UA_NodeId newNodeId;
  1058. UA_Boolean deleteNodeId = UA_FALSE;
  1059. if(!outNewNodeId) {
  1060. newNodeId = UA_NODEID_NULL;
  1061. outNewNodeId = &newNodeId;
  1062. deleteNodeId = UA_TRUE;
  1063. }
  1064. UA_StatusCode retval = Operation_addNode_begin(server, &adminSession,
  1065. &item, nodeContext, outNewNodeId, true);
  1066. if(retval != UA_STATUSCODE_GOOD)
  1067. return retval;
  1068. retval = UA_Server_setVariableNode_dataSource(server, *outNewNodeId, dataSource);
  1069. if(retval == UA_STATUSCODE_GOOD)
  1070. retval = Operation_addNode_finish(server, &adminSession, outNewNodeId,
  1071. &parentNodeId, &referenceTypeId,
  1072. &typeDefinition, false);
  1073. if(retval != UA_STATUSCODE_GOOD || deleteNodeId)
  1074. UA_NodeId_deleteMembers(outNewNodeId);
  1075. return UA_STATUSCODE_GOOD;
  1076. }
  1077. static UA_StatusCode
  1078. setDataSource(UA_Server *server, UA_Session *session,
  1079. UA_VariableNode* node, UA_DataSource *dataSource) {
  1080. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1081. return UA_STATUSCODE_BADNODECLASSINVALID;
  1082. if(node->valueSource == UA_VALUESOURCE_DATA)
  1083. UA_DataValue_deleteMembers(&node->value.data.value);
  1084. node->value.dataSource = *dataSource;
  1085. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  1086. return UA_STATUSCODE_GOOD;
  1087. }
  1088. UA_StatusCode
  1089. UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  1090. const UA_DataSource dataSource) {
  1091. return UA_Server_editNode(server, &adminSession, &nodeId,
  1092. (UA_EditNodeCallback)setDataSource,
  1093. &dataSource);
  1094. }
  1095. /************************************/
  1096. /* Special Handling of Method Nodes */
  1097. /************************************/
  1098. #ifdef UA_ENABLE_METHODCALLS
  1099. static const UA_NodeId hasproperty = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASPROPERTY}};
  1100. static const UA_NodeId propertytype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_PROPERTYTYPE}};
  1101. UA_StatusCode
  1102. UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
  1103. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  1104. UA_MethodCallback method,
  1105. size_t inputArgumentsSize, const UA_Argument* inputArguments,
  1106. size_t outputArgumentsSize, const UA_Argument* outputArguments) {
  1107. /* Browse to see which argument nodes exist */
  1108. UA_BrowseDescription bd;
  1109. UA_BrowseDescription_init(&bd);
  1110. bd.nodeId = nodeId;
  1111. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
  1112. bd.includeSubtypes = false;
  1113. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  1114. bd.nodeClassMask = UA_NODECLASS_VARIABLE;
  1115. bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;
  1116. UA_BrowseResult br;
  1117. UA_BrowseResult_init(&br);
  1118. Service_Browse_single(server, &adminSession, NULL, &bd, 0, &br);
  1119. UA_StatusCode retval = br.statusCode;
  1120. if(retval != UA_STATUSCODE_GOOD) {
  1121. UA_Server_deleteNode(server, nodeId, true);
  1122. UA_BrowseResult_deleteMembers(&br);
  1123. return retval;
  1124. }
  1125. /* Filter out the argument nodes */
  1126. UA_NodeId inputArgsId = UA_NODEID_NULL;
  1127. UA_NodeId outputArgsId = UA_NODEID_NULL;
  1128. const UA_NodeId newArgsId = UA_NODEID_NUMERIC(nodeId.namespaceIndex, 0);
  1129. const UA_QualifiedName inputArgsName = UA_QUALIFIEDNAME(0, "InputArguments");
  1130. const UA_QualifiedName outputArgsName = UA_QUALIFIEDNAME(0, "OutputArguments");
  1131. for(size_t i = 0; i < br.referencesSize; i++) {
  1132. UA_ReferenceDescription *rd = &br.references[i];
  1133. if(rd->browseName.namespaceIndex == 0 &&
  1134. UA_String_equal(&rd->browseName.name, &inputArgsName.name))
  1135. inputArgsId = rd->nodeId.nodeId;
  1136. else if(rd->browseName.namespaceIndex == 0 &&
  1137. UA_String_equal(&rd->browseName.name, &outputArgsName.name))
  1138. outputArgsId = rd->nodeId.nodeId;
  1139. }
  1140. /* Add the Input Arguments VariableNode */
  1141. if(inputArgumentsSize > 0 && UA_NodeId_isNull(&inputArgsId)) {
  1142. UA_VariableAttributes inputargs = UA_VariableAttributes_default;
  1143. inputargs.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
  1144. /* UAExpert creates a monitoreditem on inputarguments ... */
  1145. inputargs.minimumSamplingInterval = 100000.0f;
  1146. inputargs.valueRank = 1;
  1147. inputargs.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
  1148. /* dirty-cast, but is treated as const ... */
  1149. UA_Variant_setArray(&inputargs.value, (void*)(uintptr_t)inputArguments,
  1150. inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  1151. retval = UA_Server_addVariableNode(server, newArgsId, nodeId, hasproperty,
  1152. inputArgsName, propertytype, inputargs,
  1153. NULL, &inputArgsId);
  1154. }
  1155. /* Add the Output Arguments VariableNode */
  1156. if(outputArgumentsSize > 0 && UA_NodeId_isNull(&outputArgsId)) {
  1157. UA_VariableAttributes outputargs = UA_VariableAttributes_default;
  1158. outputargs.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
  1159. /* UAExpert creates a monitoreditem on outputarguments ... */
  1160. outputargs.minimumSamplingInterval = 100000.0f;
  1161. outputargs.valueRank = 1;
  1162. outputargs.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
  1163. /* dirty-cast, but is treated as const ... */
  1164. UA_Variant_setArray(&outputargs.value, (void*)(uintptr_t)outputArguments,
  1165. outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  1166. retval |= UA_Server_addVariableNode(server, newArgsId, nodeId, hasproperty,
  1167. outputArgsName, propertytype, outputargs,
  1168. NULL, &outputArgsId);
  1169. }
  1170. retval |= UA_Server_setMethodNode_callback(server, nodeId, method);
  1171. /* Call finish to add the parent reference */
  1172. retval |= Operation_addNode_finish(server, &adminSession, &nodeId, &parentNodeId,
  1173. &referenceTypeId, &UA_NODEID_NULL, false);
  1174. if(retval != UA_STATUSCODE_GOOD) {
  1175. UA_Server_deleteNode(server, nodeId, true);
  1176. UA_Server_deleteNode(server, inputArgsId, true);
  1177. UA_Server_deleteNode(server, outputArgsId, true);
  1178. }
  1179. UA_BrowseResult_deleteMembers(&br);
  1180. return retval;
  1181. }
  1182. UA_StatusCode
  1183. UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  1184. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  1185. const UA_QualifiedName browseName, const UA_MethodAttributes attr,
  1186. UA_MethodCallback method,
  1187. size_t inputArgumentsSize, const UA_Argument* inputArguments,
  1188. size_t outputArgumentsSize, const UA_Argument* outputArguments,
  1189. void *nodeContext, UA_NodeId *outNewNodeId) {
  1190. UA_AddNodesItem item;
  1191. UA_AddNodesItem_init(&item);
  1192. item.nodeClass = UA_NODECLASS_METHOD;
  1193. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  1194. item.browseName = browseName;
  1195. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  1196. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr;
  1197. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_METHODATTRIBUTES];
  1198. UA_NodeId newId;
  1199. if(!outNewNodeId) {
  1200. UA_NodeId_init(&newId);
  1201. outNewNodeId = &newId;
  1202. }
  1203. UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, &item,
  1204. nodeContext, outNewNodeId, false);
  1205. if(retval != UA_STATUSCODE_GOOD)
  1206. return retval;
  1207. retval = UA_Server_addMethodNode_finish(server, *outNewNodeId,
  1208. parentNodeId, referenceTypeId, method,
  1209. inputArgumentsSize, inputArguments,
  1210. outputArgumentsSize, outputArguments);
  1211. if(outNewNodeId == &newId)
  1212. UA_NodeId_deleteMembers(&newId);
  1213. return retval;
  1214. }
  1215. static UA_StatusCode
  1216. editMethodCallback(UA_Server *server, UA_Session* session,
  1217. UA_Node* node, void* handle) {
  1218. if(node->nodeClass != UA_NODECLASS_METHOD)
  1219. return UA_STATUSCODE_BADNODECLASSINVALID;
  1220. UA_MethodNode *mnode = (UA_MethodNode*) node;
  1221. mnode->method = (UA_MethodCallback)(uintptr_t)handle;
  1222. return UA_STATUSCODE_GOOD;
  1223. }
  1224. UA_StatusCode
  1225. UA_Server_setMethodNode_callback(UA_Server *server,
  1226. const UA_NodeId methodNodeId,
  1227. UA_MethodCallback methodCallback) {
  1228. return UA_Server_editNode(server, &adminSession, &methodNodeId,
  1229. (UA_EditNodeCallback)editMethodCallback,
  1230. (void*)(uintptr_t)methodCallback);
  1231. }
  1232. #endif
  1233. /************************/
  1234. /* Lifecycle Management */
  1235. /************************/
  1236. static UA_StatusCode
  1237. setNodeTypeLifecycle(UA_Server *server, UA_Session *session,
  1238. UA_Node* node, UA_NodeTypeLifecycle *lifecycle) {
  1239. if(node->nodeClass == UA_NODECLASS_OBJECTTYPE) {
  1240. UA_ObjectTypeNode *ot = (UA_ObjectTypeNode*)node;
  1241. ot->lifecycle = *lifecycle;
  1242. return UA_STATUSCODE_GOOD;
  1243. }
  1244. if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
  1245. UA_VariableTypeNode *vt = (UA_VariableTypeNode*)node;
  1246. vt->lifecycle = *lifecycle;
  1247. return UA_STATUSCODE_GOOD;
  1248. }
  1249. return UA_STATUSCODE_BADNODECLASSINVALID;
  1250. }
  1251. UA_StatusCode
  1252. UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
  1253. UA_NodeTypeLifecycle lifecycle) {
  1254. return UA_Server_editNode(server, &adminSession, &nodeId,
  1255. (UA_EditNodeCallback)setNodeTypeLifecycle,
  1256. &lifecycle);
  1257. }