ua_services_nodemanagement.c 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802
  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. *
  5. * Copyright 2014-2017 (c) Julius Pfrommer, Fraunhofer IOSB
  6. * Copyright 2014-2017 (c) Florian Palm
  7. * Copyright 2015-2016 (c) Sten Grüner
  8. * Copyright 2015-2016 (c) Chris Iatrou
  9. * Copyright 2015-2016 (c) Oleksiy Vasylyev
  10. * Copyright 2017 (c) Julian Grothoff
  11. * Copyright 2016 (c) LEvertz
  12. * Copyright 2016 (c) Lorenz Haas
  13. * Copyright 2017 (c) frax2222
  14. * Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH
  15. * Copyright 2017 (c) Christian von Arnim
  16. * Copyright 2017 (c) Henrik Norrman
  17. */
  18. #include "ua_server_internal.h"
  19. #include "ua_services.h"
  20. /*********************/
  21. /* Edit Node Context */
  22. /*********************/
  23. UA_StatusCode
  24. UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
  25. void **nodeContext) {
  26. const UA_Node *node = UA_Nodestore_get(server, &nodeId);
  27. if(!node)
  28. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  29. *nodeContext = node->context;
  30. UA_Nodestore_release(server, node);
  31. return UA_STATUSCODE_GOOD;
  32. }
  33. static UA_StatusCode
  34. editNodeContext(UA_Server *server, UA_Session* session,
  35. UA_Node* node, void *context) {
  36. node->context = context;
  37. return UA_STATUSCODE_GOOD;
  38. }
  39. UA_StatusCode
  40. UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
  41. void *nodeContext) {
  42. UA_StatusCode retval =
  43. UA_Server_editNode(server, &adminSession, &nodeId,
  44. (UA_EditNodeCallback)editNodeContext, nodeContext);
  45. return retval;
  46. }
  47. /**********************/
  48. /* Consistency Checks */
  49. /**********************/
  50. #define UA_PARENT_REFERENCES_COUNT 2
  51. const UA_NodeId parentReferences[UA_PARENT_REFERENCES_COUNT] = {
  52. {
  53. 0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}
  54. },
  55. {
  56. 0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}
  57. }
  58. };
  59. /* Check if the requested parent node exists, has the right node class and is
  60. * referenced with an allowed (hierarchical) reference type. For "type" nodes,
  61. * only hasSubType references are allowed. */
  62. static UA_StatusCode
  63. checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeClass,
  64. const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
  65. /* Objects do not need a parent (e.g. mandatory/optional modellingrules) */
  66. if(nodeClass == UA_NODECLASS_OBJECT && UA_NodeId_isNull(parentNodeId) &&
  67. UA_NodeId_isNull(referenceTypeId))
  68. return UA_STATUSCODE_GOOD;
  69. /* Omit checks during bootstrap */
  70. if(server->bootstrapNS0)
  71. return UA_STATUSCODE_GOOD;
  72. /* See if the parent exists */
  73. const UA_Node *parent = UA_Nodestore_get(server, parentNodeId);
  74. if(!parent) {
  75. UA_LOG_INFO_SESSION(server->config.logger, session,
  76. "AddNodes: Parent node not found");
  77. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  78. }
  79. UA_NodeClass parentNodeClass = parent->nodeClass;
  80. UA_Nodestore_release(server, parent);
  81. /* Check the referencetype exists */
  82. const UA_ReferenceTypeNode *referenceType = (const UA_ReferenceTypeNode*)
  83. UA_Nodestore_get(server, referenceTypeId);
  84. if(!referenceType) {
  85. UA_LOG_INFO_SESSION(server->config.logger, session,
  86. "AddNodes: Reference type to the parent not found");
  87. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  88. }
  89. /* Check if the referencetype is a reference type node */
  90. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  91. UA_LOG_INFO_SESSION(server->config.logger, session,
  92. "AddNodes: Reference type to the parent invalid");
  93. UA_Nodestore_release(server, (const UA_Node*)referenceType);
  94. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  95. }
  96. UA_Boolean referenceTypeIsAbstract = referenceType->isAbstract;
  97. UA_Nodestore_release(server, (const UA_Node*)referenceType);
  98. /* Check that the reference type is not abstract */
  99. if(referenceTypeIsAbstract == true) {
  100. UA_LOG_INFO_SESSION(server->config.logger, session,
  101. "AddNodes: Abstract reference type to the parent not allowed");
  102. return UA_STATUSCODE_BADREFERENCENOTALLOWED;
  103. }
  104. /* Check hassubtype relation for type nodes */
  105. if(nodeClass == UA_NODECLASS_DATATYPE ||
  106. nodeClass == UA_NODECLASS_VARIABLETYPE ||
  107. nodeClass == UA_NODECLASS_OBJECTTYPE ||
  108. nodeClass == UA_NODECLASS_REFERENCETYPE) {
  109. /* type needs hassubtype reference to the supertype */
  110. if(!UA_NodeId_equal(referenceTypeId, &subtypeId)) {
  111. UA_LOG_INFO_SESSION(server->config.logger, session,
  112. "AddNodes: New type node need to have a "
  113. "HasSubType reference");
  114. return UA_STATUSCODE_BADREFERENCENOTALLOWED;
  115. }
  116. /* supertype needs to be of the same node type */
  117. if(parentNodeClass != nodeClass) {
  118. UA_LOG_INFO_SESSION(server->config.logger, session,
  119. "AddNodes: New type node needs to be of the same "
  120. "node type as the parent");
  121. return UA_STATUSCODE_BADPARENTNODEIDINVALID;
  122. }
  123. return UA_STATUSCODE_GOOD;
  124. }
  125. /* Test if the referencetype is hierarchical */
  126. const UA_NodeId hierarchicalReference =
  127. UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
  128. if(!isNodeInTree(&server->config.nodestore, referenceTypeId,
  129. &hierarchicalReference, &subtypeId, 1)) {
  130. UA_LOG_INFO_SESSION(server->config.logger, session,
  131. "AddNodes: Reference type is not hierarchical");
  132. return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  133. }
  134. return UA_STATUSCODE_GOOD;
  135. }
  136. static UA_StatusCode
  137. typeCheckVariableNode(UA_Server *server, UA_Session *session,
  138. const UA_VariableNode *node,
  139. const UA_VariableTypeNode *vt,
  140. const UA_NodeId *parentNodeId) {
  141. /* The value might come from a datasource, so we perform a
  142. * regular read. */
  143. UA_DataValue value;
  144. UA_DataValue_init(&value);
  145. UA_StatusCode retval = readValueAttribute(server, session, node, &value);
  146. if(retval != UA_STATUSCODE_GOOD)
  147. return retval;
  148. /* Check the datatype against the vt */
  149. if(!compatibleDataType(server, &node->dataType, &vt->dataType, false))
  150. return UA_STATUSCODE_BADTYPEMISMATCH;
  151. /* Get the array dimensions */
  152. size_t arrayDims = node->arrayDimensionsSize;
  153. if(arrayDims == 0 && value.hasValue && value.value.type &&
  154. !UA_Variant_isScalar(&value.value)) {
  155. arrayDims = 1; /* No array dimensions on an array implies one dimension */
  156. }
  157. /* Check valueRank against array dimensions */
  158. if(!(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
  159. ((const UA_VariableTypeNode*)node)->isAbstract && node->valueRank == 0) &&
  160. !compatibleValueRankArrayDimensions(node->valueRank, arrayDims))
  161. return UA_STATUSCODE_BADTYPEMISMATCH;
  162. /* If variable node is created below BaseObjectType and has its default valueRank of -2,
  163. * skip the test */
  164. const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  165. // TODO handle subtypes of parent reference types
  166. if(node->valueRank != vt->valueRank &&
  167. node->valueRank != UA_VariableAttributes_default.valueRank &&
  168. !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, parentReferences, UA_PARENT_REFERENCES_COUNT)) {
  169. /* Check valueRank against the vt */
  170. if(!compatibleValueRanks(node->valueRank, vt->valueRank))
  171. return UA_STATUSCODE_BADTYPEMISMATCH;
  172. }
  173. /* Check array dimensions against the vt */
  174. if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions,
  175. node->arrayDimensionsSize, node->arrayDimensions))
  176. return UA_STATUSCODE_BADTYPEMISMATCH;
  177. /* Typecheck the value */
  178. if(!server->bootstrapNS0 && value.hasValue) {
  179. /* If the type-check failed write the same value again. The
  180. * write-service tries to convert to the correct type... */
  181. if(!compatibleValue(server, &node->dataType, node->valueRank,
  182. node->arrayDimensionsSize, node->arrayDimensions,
  183. &value.value, NULL))
  184. retval = UA_Server_writeValue(server, node->nodeId, value.value);
  185. UA_DataValue_deleteMembers(&value);
  186. }
  187. return retval;
  188. }
  189. /********************/
  190. /* Instantiate Node */
  191. /********************/
  192. static const UA_NodeId baseDataVariableType =
  193. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEDATAVARIABLETYPE}};
  194. static const UA_NodeId baseObjectType =
  195. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEOBJECTTYPE}};
  196. /* Use attributes from the variable type wherever required */
  197. static UA_StatusCode
  198. useVariableTypeAttributes(UA_Server *server, UA_Session *session,
  199. UA_VariableNode *node, const UA_AddNodesItem *item) {
  200. const UA_VariableAttributes *attributes = (const UA_VariableAttributes*)
  201. item->nodeAttributes.content.decoded.data;
  202. /* Select the type definition */
  203. const UA_NodeId *typeDefinition;
  204. if(node->nodeClass == UA_NODECLASS_VARIABLE)
  205. typeDefinition = &item->typeDefinition.nodeId;
  206. else /* UA_NODECLASS_VARIABLETYPE */
  207. typeDefinition = &item->parentNodeId.nodeId;
  208. /* Replace an empty typeDefinition with the most permissive default */
  209. if(UA_NodeId_isNull(typeDefinition))
  210. typeDefinition = &baseDataVariableType;
  211. const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)
  212. UA_Nodestore_get(server, typeDefinition);
  213. if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE) {
  214. UA_Nodestore_release(server, (const UA_Node*)vt);
  215. return UA_STATUSCODE_BADTYPEMISMATCH;
  216. }
  217. /* If no value is set, see if the vt provides one and copy it. This needs to
  218. * be done before copying the datatype from the vt, as setting the datatype
  219. * triggers a typecheck. */
  220. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  221. if(!attributes->value.type) {
  222. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  223. "AddNodes: No value given; Copy the value"
  224. "from the TypeDefinition");
  225. UA_DataValue vt_value;
  226. UA_DataValue_init(&vt_value);
  227. retval = readValueAttribute(server, session,
  228. (const UA_VariableNode*)vt, &vt_value);
  229. if(retval == UA_STATUSCODE_GOOD && vt_value.hasValue) {
  230. retval = UA_Variant_copy(&vt_value.value, &node->value.data.value.value);
  231. node->value.data.value.hasValue = true;
  232. }
  233. UA_DataValue_deleteMembers(&vt_value);
  234. }
  235. /* If no datatype is given, use the datatype of the vt */
  236. if(retval == UA_STATUSCODE_GOOD && UA_NodeId_isNull(&node->dataType)) {
  237. UA_LOG_INFO_SESSION(server->config.logger, session, "AddNodes: "
  238. "No datatype given; Copy the datatype attribute "
  239. "from the TypeDefinition");
  240. retval = UA_NodeId_copy(&vt->dataType, &node->dataType);
  241. }
  242. /* TODO: If the vt has arraydimensions but this variable does not, copy */
  243. UA_Nodestore_release(server, (const UA_Node*)vt);
  244. return retval;
  245. }
  246. /* Search for an instance of "browseName" in node searchInstance. Used during
  247. * copyChildNodes to find overwritable/mergable nodes. Does not touch
  248. * outInstanceNodeId if no child is found. */
  249. static UA_StatusCode
  250. findChildByBrowsename(UA_Server *server, UA_Session *session,
  251. const UA_NodeId *searchInstance,
  252. const UA_QualifiedName *browseName,
  253. UA_NodeId *outInstanceNodeId) {
  254. UA_BrowseDescription bd;
  255. UA_BrowseDescription_init(&bd);
  256. bd.nodeId = *searchInstance;
  257. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  258. bd.includeSubtypes = true;
  259. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  260. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  261. bd.resultMask = UA_BROWSERESULTMASK_NODECLASS | UA_BROWSERESULTMASK_BROWSENAME;
  262. UA_BrowseResult br;
  263. UA_BrowseResult_init(&br);
  264. UA_UInt32 maxrefs = 0;
  265. Operation_Browse(server, session, &maxrefs, &bd, &br);
  266. if(br.statusCode != UA_STATUSCODE_GOOD)
  267. return br.statusCode;
  268. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  269. for(size_t i = 0; i < br.referencesSize; ++i) {
  270. UA_ReferenceDescription *rd = &br.references[i];
  271. if(rd->browseName.namespaceIndex == browseName->namespaceIndex &&
  272. UA_String_equal(&rd->browseName.name, &browseName->name)) {
  273. retval = UA_NodeId_copy(&rd->nodeId.nodeId, outInstanceNodeId);
  274. break;
  275. }
  276. }
  277. UA_BrowseResult_deleteMembers(&br);
  278. return retval;
  279. }
  280. static const UA_NodeId mandatoryId =
  281. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_MODELLINGRULE_MANDATORY}};
  282. static const UA_NodeId hasModellingRuleId =
  283. {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASMODELLINGRULE}};
  284. static UA_Boolean
  285. isMandatoryChild(UA_Server *server, UA_Session *session,
  286. const UA_NodeId *childNodeId) {
  287. /* Get the child */
  288. const UA_Node *child = UA_Nodestore_get(server, childNodeId);
  289. if(!child)
  290. return false;
  291. /* Look for the reference making the child mandatory */
  292. for(size_t i = 0; i < child->referencesSize; ++i) {
  293. UA_NodeReferenceKind *refs = &child->references[i];
  294. if(!UA_NodeId_equal(&hasModellingRuleId, &refs->referenceTypeId))
  295. continue;
  296. if(refs->isInverse)
  297. continue;
  298. for(size_t j = 0; j < refs->targetIdsSize; ++j) {
  299. if(UA_NodeId_equal(&mandatoryId, &refs->targetIds[j].nodeId)) {
  300. UA_Nodestore_release(server, child);
  301. return true;
  302. }
  303. }
  304. }
  305. UA_Nodestore_release(server, child);
  306. return false;
  307. }
  308. static UA_StatusCode
  309. copyChildNodes(UA_Server *server, UA_Session *session,
  310. const UA_NodeId *sourceNodeId,
  311. const UA_NodeId *destinationNodeId);
  312. static void
  313. Operation_addReference(UA_Server *server, UA_Session *session, void *context,
  314. const UA_AddReferencesItem *item, UA_StatusCode *retval);
  315. /*
  316. * This method only deletes references from the node which are not matching any type in the given array.
  317. * Could be used to e.g. delete all the references, except 'HASMODELINGRULE'
  318. */
  319. static void deleteReferencesSubset(UA_Node *node, size_t referencesSkipSize, UA_NodeId* referencesSkip) {
  320. if(referencesSkipSize == 0) {
  321. UA_Node_deleteReferences(node);
  322. return;
  323. }
  324. /* Let's count if there are references left. If not just delete all the references.
  325. * It's faster */
  326. size_t newSize = 0;
  327. for(size_t i = 0; i < node->referencesSize; ++i) {
  328. for(size_t j = 0; j < referencesSkipSize; j++) {
  329. if(UA_NodeId_equal(&node->references[i].referenceTypeId, &referencesSkip[j])) {
  330. newSize++;
  331. }
  332. }
  333. }
  334. if(newSize == 0) {
  335. UA_Node_deleteReferences(node);
  336. return;
  337. }
  338. /* Now copy the remaining references to a new array */
  339. UA_NodeReferenceKind *newReferences = (UA_NodeReferenceKind *)UA_malloc(sizeof(UA_NodeReferenceKind) * (newSize));
  340. size_t curr = 0;
  341. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  342. for(size_t i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; ++i) {
  343. for(size_t j = 0; j < referencesSkipSize; j++) {
  344. if(!UA_NodeId_equal(&node->references[i].referenceTypeId, &referencesSkip[j]))
  345. continue;
  346. // copy the reference
  347. UA_NodeReferenceKind *srefs = &node->references[i];
  348. UA_NodeReferenceKind *drefs = &newReferences[curr++];
  349. drefs->isInverse = srefs->isInverse;
  350. retval = UA_NodeId_copy(&srefs->referenceTypeId, &drefs->referenceTypeId);
  351. if(retval != UA_STATUSCODE_GOOD)
  352. break;
  353. retval = UA_Array_copy(srefs->targetIds, srefs->targetIdsSize,
  354. (void**)&drefs->targetIds,
  355. &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
  356. if(retval != UA_STATUSCODE_GOOD)
  357. break;
  358. drefs->targetIdsSize = srefs->targetIdsSize;
  359. break;
  360. }
  361. if(retval != UA_STATUSCODE_GOOD) {
  362. for(size_t k=0; k<i; k++) {
  363. UA_NodeReferenceKind *refs = &newReferences[i];
  364. for(size_t j = 0; j < refs->targetIdsSize; ++j)
  365. UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j]);
  366. UA_Array_delete(refs->targetIds, refs->targetIdsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
  367. UA_NodeId_deleteMembers(&refs->referenceTypeId);
  368. }
  369. }
  370. }
  371. UA_Node_deleteReferences(node);
  372. if(retval == UA_STATUSCODE_GOOD) {
  373. node->references = newReferences;
  374. node->referencesSize = newSize;
  375. } else {
  376. UA_free(newReferences);
  377. }
  378. }
  379. static UA_StatusCode
  380. addParentAndTypeRef(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, const UA_NodeId *parentNodeId,
  381. const UA_NodeId *referenceTypeId, const UA_NodeId *typeDefinitionId);
  382. static UA_StatusCode
  383. copyChildNode(UA_Server *server, UA_Session *session,
  384. const UA_NodeId *destinationNodeId,
  385. const UA_ReferenceDescription *rd) {
  386. UA_NodeId existingChild = UA_NODEID_NULL;
  387. UA_StatusCode retval =
  388. findChildByBrowsename(server, session, destinationNodeId,
  389. &rd->browseName, &existingChild);
  390. if(retval != UA_STATUSCODE_GOOD)
  391. return retval;
  392. /* Have a child with that browseName. Try to deep-copy missing members. */
  393. if(!UA_NodeId_isNull(&existingChild)) {
  394. if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
  395. rd->nodeClass == UA_NODECLASS_OBJECT)
  396. retval = copyChildNodes(server, session, &rd->nodeId.nodeId, &existingChild);
  397. UA_NodeId_deleteMembers(&existingChild);
  398. return retval;
  399. }
  400. /* Is the child mandatory? If not, skip */
  401. if(!isMandatoryChild(server, session, &rd->nodeId.nodeId))
  402. return UA_STATUSCODE_GOOD;
  403. /* No existing child with that browsename. Create it. */
  404. if(rd->nodeClass == UA_NODECLASS_METHOD) {
  405. /* Add a reference to the method in the objecttype */
  406. UA_AddReferencesItem newItem;
  407. UA_AddReferencesItem_init(&newItem);
  408. newItem.sourceNodeId = *destinationNodeId;
  409. newItem.referenceTypeId = rd->referenceTypeId;
  410. newItem.isForward = true;
  411. newItem.targetNodeId = rd->nodeId;
  412. newItem.targetNodeClass = UA_NODECLASS_METHOD;
  413. Operation_addReference(server, session, NULL, &newItem, &retval);
  414. return retval;
  415. }
  416. /* Node exists and is a variable or object. Instantiate missing mandatory
  417. * children */
  418. if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
  419. rd->nodeClass == UA_NODECLASS_OBJECT) {
  420. /* Get the node */
  421. UA_Node *node;
  422. retval = UA_Nodestore_getCopy(server, &rd->nodeId.nodeId, &node);
  423. if(retval != UA_STATUSCODE_GOOD)
  424. return retval;
  425. /* Get the type */
  426. const UA_Node *type = getNodeType(server, node);
  427. const UA_NodeId *typeId;
  428. if(type)
  429. typeId = &type->nodeId;
  430. else
  431. typeId = &UA_NODEID_NULL;
  432. /* Reset the NodeId (random numeric id will be assigned in the nodestore) */
  433. UA_NodeId_deleteMembers(&node->nodeId);
  434. node->nodeId.namespaceIndex = destinationNodeId->namespaceIndex;
  435. /* Remove references, they are re-created from scratch in addnode_finish */
  436. /* TODO: Be more clever in removing references that are re-added during
  437. * addnode_finish. That way, we can call addnode_finish also on children that were
  438. * manually added by the user during addnode_begin and addnode_finish. */
  439. /* For now we keep all the modelling rule references and delete all others */
  440. UA_NodeId modellingRuleReferenceId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE);
  441. deleteReferencesSubset(node, 1, &modellingRuleReferenceId);
  442. /* Add the node to the nodestore */
  443. UA_NodeId newNodeId;
  444. retval = UA_Nodestore_insert(server, node, &newNodeId);
  445. if(retval != UA_STATUSCODE_GOOD) {
  446. UA_Nodestore_release(server, type);
  447. return retval;
  448. }
  449. /* Add all the children of this child to the new child node to make sure we take
  450. * the values from the nearest inherited object first.
  451. * The call to addNode_finish will then only add the children from the type and
  452. * thus skip the direct children of rd->nodeId.nodeId
  453. */
  454. copyChildNodes(server, session, &rd->nodeId.nodeId, &newNodeId);
  455. /* Add the parent reference */
  456. /* we pass the nodeId instead of node to make sure the refcount
  457. * is increased and other calls can not delete the node in the meantime */
  458. retval = addParentAndTypeRef(server, session, &newNodeId, destinationNodeId,
  459. &rd->referenceTypeId, typeId);
  460. if(retval != UA_STATUSCODE_GOOD) {
  461. UA_Nodestore_delete(server, node);
  462. UA_Nodestore_release(server, type);
  463. return retval;
  464. }
  465. /* Call addnode_finish, this recursively adds additional members, the type
  466. * definition and so on of the base type of this child, if they are not yet
  467. * in the destination */
  468. retval |= Operation_addNode_finish(server, session, &newNodeId);
  469. UA_NodeId_deleteMembers(&newNodeId);
  470. UA_Nodestore_release(server, type);
  471. }
  472. return retval;
  473. }
  474. /* Copy any children of Node sourceNodeId to another node destinationNodeId. */
  475. static UA_StatusCode
  476. copyChildNodes(UA_Server *server, UA_Session *session,
  477. const UA_NodeId *sourceNodeId, const UA_NodeId *destinationNodeId) {
  478. /* Browse to get all children of the source */
  479. UA_BrowseDescription bd;
  480. UA_BrowseDescription_init(&bd);
  481. bd.nodeId = *sourceNodeId;
  482. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  483. bd.includeSubtypes = true;
  484. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  485. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  486. bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS |
  487. UA_BROWSERESULTMASK_BROWSENAME;
  488. UA_BrowseResult br;
  489. UA_BrowseResult_init(&br);
  490. UA_UInt32 maxrefs = 0;
  491. Operation_Browse(server, session, &maxrefs, &bd, &br);
  492. if(br.statusCode != UA_STATUSCODE_GOOD)
  493. return br.statusCode;
  494. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  495. for(size_t i = 0; i < br.referencesSize; ++i) {
  496. UA_ReferenceDescription *rd = &br.references[i];
  497. retval |= copyChildNode(server, session, destinationNodeId, rd);
  498. }
  499. UA_BrowseResult_deleteMembers(&br);
  500. return retval;
  501. }
  502. static UA_StatusCode
  503. addChildren(UA_Server *server, UA_Session *session,
  504. const UA_Node *node, const UA_Node *type) {
  505. /* Get the hierarchy of the type and all its supertypes */
  506. UA_NodeId *hierarchy = NULL;
  507. size_t hierarchySize = 0;
  508. UA_StatusCode retval = getTypeHierarchy(&server->config.nodestore, &type->nodeId,
  509. &hierarchy, &hierarchySize);
  510. if(retval != UA_STATUSCODE_GOOD)
  511. return retval;
  512. /* Copy members of the type and supertypes (and instantiate them) */
  513. for(size_t i = 0; i < hierarchySize; ++i)
  514. retval |= copyChildNodes(server, session, &hierarchy[i], &node->nodeId);
  515. UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
  516. return retval;
  517. }
  518. /* Calls the global destructor internally of the global constructor succeeds and
  519. * the type-level constructor fails. */
  520. static UA_StatusCode callConstructors(UA_Server *server, UA_Session *session,
  521. const UA_Node *node, const UA_Node *type) {
  522. /* Get the node type constructor */
  523. const UA_NodeTypeLifecycle *lifecycle = NULL;
  524. if(node->nodeClass == UA_NODECLASS_OBJECT) {
  525. const UA_ObjectTypeNode *ot = (const UA_ObjectTypeNode*)type;
  526. lifecycle = &ot->lifecycle;
  527. } else if(node->nodeClass == UA_NODECLASS_VARIABLE) {
  528. const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)type;
  529. lifecycle = &vt->lifecycle;
  530. }
  531. /* Call the global constructor */
  532. void *context = node->context;
  533. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  534. if(server->config.nodeLifecycle.constructor)
  535. retval = server->config.nodeLifecycle.constructor(server, &session->sessionId,
  536. session->sessionHandle,
  537. &node->nodeId, &context);
  538. /* Call the type constructor */
  539. if(retval == UA_STATUSCODE_GOOD && lifecycle && lifecycle->constructor)
  540. retval = lifecycle->constructor(server, &session->sessionId,
  541. session->sessionHandle, &type->nodeId,
  542. type->context, &node->nodeId, &context);
  543. /* Set the context *and* mark the node as constructed */
  544. if(retval == UA_STATUSCODE_GOOD)
  545. retval = UA_Server_editNode(server, &adminSession, &node->nodeId,
  546. (UA_EditNodeCallback)editNodeContext,
  547. context);
  548. /* Fail. Call the global destructor. */
  549. if(retval != UA_STATUSCODE_GOOD && server->config.nodeLifecycle.destructor)
  550. server->config.nodeLifecycle.destructor(server, &session->sessionId,
  551. session->sessionHandle,
  552. &node->nodeId, context);
  553. return retval;
  554. }
  555. static UA_StatusCode
  556. addTypeDefRef(UA_Server *server, UA_Session *session,
  557. const UA_Node *node, const UA_Node *type) {
  558. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  559. UA_AddReferencesItem addref;
  560. UA_AddReferencesItem_init(&addref);
  561. addref.sourceNodeId = node->nodeId;
  562. addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  563. addref.isForward = true;
  564. addref.targetNodeId.nodeId = type->nodeId;
  565. Operation_addReference(server, session, NULL, &addref, &retval);
  566. return retval;
  567. }
  568. static UA_StatusCode
  569. getTypeDef(UA_Server *server, const UA_Node *node, UA_NodeId **typeDefinitionId) {
  570. UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
  571. for (size_t i=0; i< node->referencesSize; i++) {
  572. if (node->references[i].isInverse == UA_FALSE && UA_NodeId_equal(&node->references[i].referenceTypeId, &hasTypeDef) &&
  573. node->references[i].targetIdsSize > 0) {
  574. *typeDefinitionId = &node->references[i].targetIds[0].nodeId;
  575. return UA_STATUSCODE_GOOD;
  576. }
  577. }
  578. return UA_STATUSCODE_BADNOTFOUND;
  579. }
  580. static UA_StatusCode
  581. addParentRef(UA_Server *server, UA_Session *session,
  582. const UA_NodeId *nodeId,
  583. const UA_NodeId *referenceTypeId,
  584. const UA_NodeId *parentNodeId) {
  585. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  586. UA_AddReferencesItem ref_item;
  587. UA_AddReferencesItem_init(&ref_item);
  588. ref_item.sourceNodeId = *nodeId;
  589. ref_item.referenceTypeId = *referenceTypeId;
  590. ref_item.isForward = false;
  591. ref_item.targetNodeId.nodeId = *parentNodeId;
  592. Operation_addReference(server, session, NULL, &ref_item, &retval);
  593. return retval;
  594. }
  595. /************/
  596. /* Add Node */
  597. /************/
  598. static void
  599. removeDeconstructedNode(UA_Server *server, UA_Session *session,
  600. const UA_Node *node, UA_Boolean removeTargetRefs);
  601. static const UA_NodeId hasSubtype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
  602. static UA_StatusCode
  603. addParentAndTypeRef(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, const UA_NodeId *parentNodeId,
  604. const UA_NodeId *referenceTypeId, const UA_NodeId *typeDefinitionId) {
  605. const UA_Node *node = UA_Nodestore_get(server, nodeId);
  606. if (!node)
  607. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  608. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  609. const UA_Node *type = NULL;
  610. /* Use the typeDefinition as parent for type-nodes */
  611. if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
  612. node->nodeClass == UA_NODECLASS_OBJECTTYPE ||
  613. node->nodeClass == UA_NODECLASS_REFERENCETYPE ||
  614. node->nodeClass == UA_NODECLASS_DATATYPE) {
  615. if(UA_NodeId_equal(referenceTypeId, &UA_NODEID_NULL))
  616. referenceTypeId = &hasSubtype;
  617. const UA_Node *parentNode = UA_Nodestore_get(server, parentNodeId);
  618. if(parentNode) {
  619. if(parentNode->nodeClass == node->nodeClass)
  620. typeDefinitionId = parentNodeId;
  621. UA_Nodestore_release(server, parentNode);
  622. }
  623. }
  624. if(server->bootstrapNS0)
  625. goto get_type;
  626. /* Check parent reference. Objects may have no parent. */
  627. retval = checkParentReference(server, session, node->nodeClass,
  628. parentNodeId, referenceTypeId);
  629. if(retval != UA_STATUSCODE_GOOD) {
  630. UA_LOG_INFO_SESSION(server->config.logger, session,
  631. "AddNodes: The parent reference is invalid");
  632. goto cleanup;
  633. }
  634. /* Replace empty typeDefinition with the most permissive default */
  635. if((node->nodeClass == UA_NODECLASS_VARIABLE ||
  636. node->nodeClass == UA_NODECLASS_OBJECT) &&
  637. UA_NodeId_isNull(typeDefinitionId)) {
  638. UA_LOG_INFO_SESSION(server->config.logger, session,
  639. "AddNodes: No TypeDefinition; Use the default "
  640. "TypeDefinition for the Variable/Object");
  641. if(node->nodeClass == UA_NODECLASS_VARIABLE)
  642. typeDefinitionId = &baseDataVariableType;
  643. else
  644. typeDefinitionId = &baseObjectType;
  645. }
  646. get_type:
  647. /* Get the node type. There must be a typedefinition for variables, objects
  648. * and type-nodes. See the above checks. */
  649. if(!UA_NodeId_isNull(typeDefinitionId)) {
  650. /* Get the type node */
  651. type = UA_Nodestore_get(server, typeDefinitionId);
  652. if(!type) {
  653. UA_LOG_INFO_SESSION(server->config.logger, session,
  654. "AddNodes: Node type not found in nodestore");
  655. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  656. goto cleanup;
  657. }
  658. UA_Boolean typeOk = UA_FALSE;
  659. switch(node->nodeClass) {
  660. case UA_NODECLASS_DATATYPE:
  661. typeOk = type->nodeClass == UA_NODECLASS_DATATYPE;
  662. break;
  663. case UA_NODECLASS_METHOD:
  664. typeOk = type->nodeClass == UA_NODECLASS_METHOD;
  665. break;
  666. case UA_NODECLASS_OBJECT:
  667. typeOk = type->nodeClass == UA_NODECLASS_OBJECTTYPE;
  668. break;
  669. case UA_NODECLASS_OBJECTTYPE:
  670. typeOk = type->nodeClass == UA_NODECLASS_OBJECTTYPE;
  671. break;
  672. case UA_NODECLASS_REFERENCETYPE:
  673. typeOk = type->nodeClass == UA_NODECLASS_REFERENCETYPE;
  674. break;
  675. case UA_NODECLASS_VARIABLE:
  676. typeOk = type->nodeClass == UA_NODECLASS_VARIABLETYPE;
  677. break;
  678. case UA_NODECLASS_VARIABLETYPE:
  679. typeOk = type->nodeClass == UA_NODECLASS_VARIABLETYPE;
  680. break;
  681. case UA_NODECLASS_VIEW:
  682. typeOk = type->nodeClass == UA_NODECLASS_VIEW;
  683. break;
  684. default:
  685. typeOk = UA_FALSE;
  686. }
  687. if(!typeOk) {
  688. UA_LOG_INFO_SESSION(server->config.logger, session,
  689. "AddNodes: Type does not match node class");
  690. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  691. goto cleanup;
  692. }
  693. /* See if the type has the correct node class. For type-nodes, we know
  694. * that type has the same nodeClass from checkParentReference. */
  695. if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_VARIABLE) {
  696. if(((const UA_VariableTypeNode*)type)->isAbstract) {
  697. /* Abstract variable is allowed if parent is a children of a base data variable */
  698. const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
  699. /* A variable may be of an object type which again is below BaseObjectType */
  700. const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  701. // TODO handle subtypes of parent reference types
  702. if(!isNodeInTree(&server->config.nodestore, parentNodeId, &variableTypes, parentReferences, UA_PARENT_REFERENCES_COUNT) &&
  703. !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, parentReferences, UA_PARENT_REFERENCES_COUNT)) {
  704. UA_LOG_INFO_SESSION(server->config.logger, session,
  705. "AddNodes: Type of variable node must "
  706. "be VariableType and not cannot be abstract");
  707. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  708. goto cleanup;
  709. }
  710. }
  711. }
  712. if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_OBJECT) {
  713. if(((const UA_ObjectTypeNode*)type)->isAbstract) {
  714. /* Object node created of an abstract ObjectType. Only allowed if within BaseObjectType folder */
  715. const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
  716. // TODO handle subtypes of parent reference types
  717. if(!isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, parentReferences, UA_PARENT_REFERENCES_COUNT)) {
  718. UA_LOG_INFO_SESSION(server->config.logger, session,
  719. "AddNodes: Type of object node must "
  720. "be ObjectType and not be abstract");
  721. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  722. goto cleanup;
  723. }
  724. }
  725. }
  726. }
  727. /* Check if all attributes hold the constraints of the type now. The initial
  728. * attributes must type-check. The constructor might change the attributes
  729. * again. Then, the changes are type-checked by the normal write service. */
  730. if(type && (node->nodeClass == UA_NODECLASS_VARIABLE ||
  731. node->nodeClass == UA_NODECLASS_VARIABLETYPE)) {
  732. retval = typeCheckVariableNode(server, session,
  733. (const UA_VariableNode*)node,
  734. (const UA_VariableTypeNode*)type, parentNodeId);
  735. if(retval != UA_STATUSCODE_GOOD) {
  736. UA_LOG_INFO_SESSION(server->config.logger, session,
  737. "AddNodes: Type-checking the variable node "
  738. "failed with error code %s", UA_StatusCode_name(retval));
  739. goto cleanup;
  740. }
  741. }
  742. /* Add reference to the parent */
  743. if(!UA_NodeId_isNull(parentNodeId)) {
  744. if(UA_NodeId_isNull(referenceTypeId)) {
  745. UA_LOG_INFO_SESSION(server->config.logger, session,
  746. "AddNodes: Reference to parent cannot be null");
  747. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  748. goto cleanup;
  749. }
  750. retval = addParentRef(server, session, &node->nodeId, referenceTypeId, parentNodeId);
  751. if(retval != UA_STATUSCODE_GOOD) {
  752. UA_LOG_INFO_SESSION(server->config.logger, session,
  753. "AddNodes: Adding reference to parent failed");
  754. goto cleanup;
  755. }
  756. }
  757. /* Instantiate variables and objects */
  758. if(node->nodeClass == UA_NODECLASS_VARIABLE ||
  759. node->nodeClass == UA_NODECLASS_OBJECT) {
  760. UA_assert(type != NULL); /* see above */
  761. /* Add a hasTypeDefinition reference */
  762. retval = addTypeDefRef(server, session, node, type);
  763. if(retval != UA_STATUSCODE_GOOD) {
  764. UA_LOG_INFO_SESSION(server->config.logger, session,
  765. "AddNodes: Adding a reference to the type "
  766. "definition failed with error code %s",
  767. UA_StatusCode_name(retval));
  768. goto cleanup;
  769. }
  770. }
  771. cleanup:
  772. UA_Nodestore_release(server, node);
  773. if(type)
  774. UA_Nodestore_release(server, type);
  775. if(retval != UA_STATUSCODE_GOOD)
  776. UA_Server_deleteNode(server, *nodeId, UA_TRUE);
  777. return retval;
  778. }
  779. /* Prepare the node, then add it to the nodestore */
  780. UA_StatusCode
  781. Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
  782. const UA_AddNodesItem *item, const UA_NodeId *parentNodeId,
  783. const UA_NodeId *referenceTypeId, UA_NodeId *outNewNodeId) {
  784. /* Do not check access for server */
  785. if(session != &adminSession && server->config.accessControl.allowAddNode &&
  786. !server->config.accessControl.allowAddNode(server, &server->config.accessControl,
  787. &session->sessionId, session->sessionHandle, item)) {
  788. return UA_STATUSCODE_BADUSERACCESSDENIED;
  789. }
  790. /* Check the namespaceindex */
  791. if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) {
  792. UA_LOG_INFO_SESSION(server->config.logger, session,
  793. "AddNodes: Namespace invalid");
  794. return UA_STATUSCODE_BADNODEIDINVALID;
  795. }
  796. if(item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED &&
  797. item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
  798. UA_LOG_INFO_SESSION(server->config.logger, session,
  799. "AddNodes: Node attributes invalid");
  800. return UA_STATUSCODE_BADINTERNALERROR;
  801. }
  802. /* Create a node */
  803. UA_Node *node = UA_Nodestore_new(server, item->nodeClass);
  804. if(!node) {
  805. UA_LOG_INFO_SESSION(server->config.logger, session,
  806. "AddNodes: Node could not create a node "
  807. "in the nodestore");
  808. return UA_STATUSCODE_BADOUTOFMEMORY;
  809. }
  810. /* Fill the node */
  811. node->context = nodeContext;
  812. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  813. retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
  814. retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
  815. retval |= UA_Node_setAttributes(node, item->nodeAttributes.content.decoded.data,
  816. item->nodeAttributes.content.decoded.type);
  817. if(retval != UA_STATUSCODE_GOOD) {
  818. UA_LOG_INFO_SESSION(server->config.logger, session,
  819. "AddNodes: Node could not create a node "
  820. "with error code %s",
  821. UA_StatusCode_name(retval));
  822. UA_Nodestore_delete(server, node);
  823. return retval;
  824. }
  825. if(server->bootstrapNS0)
  826. goto finished_checks;
  827. /* Use attributes from the typedefinition */
  828. if(node->nodeClass == UA_NODECLASS_VARIABLE ||
  829. node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
  830. /* Use attributes from the type. The value and value constraints are the
  831. * same for the variable and variabletype attribute structs. */
  832. retval = useVariableTypeAttributes(server, session,
  833. (UA_VariableNode*)node, item);
  834. if(retval != UA_STATUSCODE_GOOD) {
  835. UA_LOG_INFO_SESSION(server->config.logger, session,
  836. "AddNodes: Using attributes from the variable type "
  837. "failed with error code %s",
  838. UA_StatusCode_name(retval));
  839. UA_Nodestore_delete(server, node);
  840. return retval;
  841. }
  842. }
  843. finished_checks:
  844. /* Add the node to the nodestore */
  845. retval = UA_Nodestore_insert(server, node, outNewNodeId);
  846. if(retval != UA_STATUSCODE_GOOD) {
  847. UA_LOG_INFO_SESSION(server->config.logger, session,
  848. "AddNodes: Node could not add the new node "
  849. "to the nodestore with error code %s",
  850. UA_StatusCode_name(retval));
  851. return retval;
  852. }
  853. /* we pass the nodeId instead of node to make sure the refcount is
  854. * increased and other calls can not delete the node in the meantime */
  855. // TODO on multithreading `node` may already have been deleted
  856. retval = addParentAndTypeRef(server, session, &node->nodeId, parentNodeId, referenceTypeId, &item->typeDefinition.nodeId);
  857. if(retval != UA_STATUSCODE_GOOD) {
  858. UA_LOG_INFO_SESSION(server->config.logger, session,
  859. "AddNodes: Node could add parent references with error code %s",
  860. UA_StatusCode_name(retval));
  861. // the node is already deleted within addParentAndTypeRef
  862. }
  863. return retval;
  864. }
  865. /* Children, references, type-checking, constructors. */
  866. UA_StatusCode
  867. Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) {
  868. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  869. /* Get the node */
  870. const UA_Node *node = UA_Nodestore_get(server, nodeId);
  871. if(!node)
  872. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  873. const UA_Node *type = NULL;
  874. /* Instantiate variables and objects */
  875. if(node->nodeClass == UA_NODECLASS_VARIABLE ||
  876. node->nodeClass == UA_NODECLASS_OBJECT) {
  877. UA_NodeId *typeDefId;
  878. retval = getTypeDef(server, node, &typeDefId);
  879. if (retval != UA_STATUSCODE_GOOD) {
  880. UA_LOG_INFO_SESSION(server->config.logger, session,
  881. "AddNodes: Can not get type definition of node since it has no 'hasTypeDef' reference");
  882. goto cleanup;
  883. }
  884. /* Get the type node */
  885. type = UA_Nodestore_get(server, typeDefId);
  886. if(!type) {
  887. UA_LOG_INFO_SESSION(server->config.logger, session,
  888. "AddNodes: Node type not found in nodestore");
  889. retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
  890. goto cleanup;
  891. }
  892. /* Add (mandatory) child nodes from the type definition */
  893. if(!server->bootstrapNS0) {
  894. retval = addChildren(server, session, node, type);
  895. if(retval != UA_STATUSCODE_GOOD) {
  896. UA_LOG_INFO_SESSION(server->config.logger, session,
  897. "AddNodes: Adding child nodes failed with error code %s",
  898. UA_StatusCode_name(retval));
  899. goto cleanup;
  900. }
  901. }
  902. }
  903. /* Call the constructor(s) */
  904. retval = callConstructors(server, session, node, type);
  905. if(retval != UA_STATUSCODE_GOOD) {
  906. UA_LOG_INFO_SESSION(server->config.logger, session,
  907. "AddNodes: Calling the node constructor(s) failed "
  908. "with status code %s", UA_StatusCode_name(retval));
  909. }
  910. cleanup:
  911. if(type)
  912. UA_Nodestore_release(server, type);
  913. if(retval != UA_STATUSCODE_GOOD)
  914. removeDeconstructedNode(server, session, node, true);
  915. UA_Nodestore_release(server, node);
  916. return retval;
  917. }
  918. static void
  919. Operation_addNode(UA_Server *server, UA_Session *session, void *nodeContext,
  920. const UA_AddNodesItem *item, UA_AddNodesResult *result) {
  921. result->statusCode = Operation_addNode_begin(server, session, nodeContext,
  922. item, &item->parentNodeId.nodeId, &item->referenceTypeId, &result->addedNodeId);
  923. if(result->statusCode != UA_STATUSCODE_GOOD)
  924. return;
  925. /* AddNodes_finish */
  926. result->statusCode =
  927. Operation_addNode_finish(server, session, &result->addedNodeId);
  928. /* If finishing failed, the node was deleted */
  929. if(result->statusCode != UA_STATUSCODE_GOOD)
  930. UA_NodeId_deleteMembers(&result->addedNodeId);
  931. }
  932. void
  933. Service_AddNodes(UA_Server *server, UA_Session *session,
  934. const UA_AddNodesRequest *request,
  935. UA_AddNodesResponse *response) {
  936. UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing AddNodesRequest");
  937. if(server->config.maxNodesPerNodeManagement != 0 &&
  938. request->nodesToAddSize > server->config.maxNodesPerNodeManagement) {
  939. response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
  940. return;
  941. }
  942. response->responseHeader.serviceResult =
  943. UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_addNode, NULL,
  944. &request->nodesToAddSize, &UA_TYPES[UA_TYPES_ADDNODESITEM],
  945. &response->resultsSize, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
  946. }
  947. UA_StatusCode
  948. __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
  949. const UA_NodeId *requestedNewNodeId,
  950. const UA_NodeId *parentNodeId,
  951. const UA_NodeId *referenceTypeId,
  952. const UA_QualifiedName browseName,
  953. const UA_NodeId *typeDefinition,
  954. const UA_NodeAttributes *attr,
  955. const UA_DataType *attributeType,
  956. void *nodeContext, UA_NodeId *outNewNodeId) {
  957. /* Create the AddNodesItem */
  958. UA_AddNodesItem item;
  959. UA_AddNodesItem_init(&item);
  960. item.nodeClass = nodeClass;
  961. item.requestedNewNodeId.nodeId = *requestedNewNodeId;
  962. item.browseName = browseName;
  963. item.parentNodeId.nodeId = *parentNodeId;
  964. item.referenceTypeId = *referenceTypeId;
  965. item.typeDefinition.nodeId = *typeDefinition;
  966. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  967. item.nodeAttributes.content.decoded.type = attributeType;
  968. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr;
  969. /* Call the normal addnodes service */
  970. UA_AddNodesResult result;
  971. UA_AddNodesResult_init(&result);
  972. Operation_addNode(server, &adminSession, nodeContext, &item, &result);
  973. if(outNewNodeId)
  974. *outNewNodeId = result.addedNodeId;
  975. else
  976. UA_NodeId_deleteMembers(&result.addedNodeId);
  977. return result.statusCode;
  978. }
  979. UA_StatusCode
  980. UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
  981. const UA_NodeId requestedNewNodeId,
  982. const UA_NodeId parentNodeId,
  983. const UA_NodeId referenceTypeId,
  984. const UA_QualifiedName browseName,
  985. const UA_NodeId typeDefinition,
  986. const void *attr, const UA_DataType *attributeType,
  987. void *nodeContext, UA_NodeId *outNewNodeId) {
  988. UA_AddNodesItem item;
  989. UA_AddNodesItem_init(&item);
  990. item.nodeClass = nodeClass;
  991. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  992. item.browseName = browseName;
  993. item.typeDefinition.nodeId = typeDefinition;
  994. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  995. item.nodeAttributes.content.decoded.type = attributeType;
  996. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr;
  997. return Operation_addNode_begin(server, &adminSession, nodeContext,
  998. &item, &parentNodeId, &referenceTypeId,
  999. outNewNodeId);
  1000. }
  1001. UA_StatusCode
  1002. UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId) {
  1003. return Operation_addNode_finish(server, &adminSession, &nodeId);
  1004. }
  1005. /****************/
  1006. /* Delete Nodes */
  1007. /****************/
  1008. static void
  1009. Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
  1010. const UA_DeleteReferencesItem *item, UA_StatusCode *retval);
  1011. /* Remove references to this node (in the other nodes) */
  1012. static void
  1013. removeIncomingReferences(UA_Server *server, UA_Session *session,
  1014. const UA_Node *node) {
  1015. UA_DeleteReferencesItem item;
  1016. UA_DeleteReferencesItem_init(&item);
  1017. item.targetNodeId.nodeId = node->nodeId;
  1018. item.deleteBidirectional = false;
  1019. UA_StatusCode dummy;
  1020. for(size_t i = 0; i < node->referencesSize; ++i) {
  1021. UA_NodeReferenceKind *refs = &node->references[i];
  1022. item.isForward = refs->isInverse;
  1023. item.referenceTypeId = refs->referenceTypeId;
  1024. for(size_t j = 0; j < refs->targetIdsSize; ++j) {
  1025. item.sourceNodeId = refs->targetIds[j].nodeId;
  1026. Operation_deleteReference(server, session, NULL, &item, &dummy);
  1027. }
  1028. }
  1029. }
  1030. static void
  1031. deconstructNode(UA_Server *server, UA_Session *session,
  1032. const UA_Node *node) {
  1033. /* Call the type-level destructor */
  1034. void *context = node->context; /* No longer needed after this function */
  1035. if(node->nodeClass == UA_NODECLASS_OBJECT ||
  1036. node->nodeClass == UA_NODECLASS_VARIABLE) {
  1037. const UA_Node *type = getNodeType(server, node);
  1038. if(type) {
  1039. const UA_NodeTypeLifecycle *lifecycle;
  1040. if(node->nodeClass == UA_NODECLASS_OBJECT)
  1041. lifecycle = &((const UA_ObjectTypeNode*)type)->lifecycle;
  1042. else
  1043. lifecycle = &((const UA_VariableTypeNode*)type)->lifecycle;
  1044. if(lifecycle->destructor)
  1045. lifecycle->destructor(server,
  1046. &session->sessionId, session->sessionHandle,
  1047. &type->nodeId, type->context,
  1048. &node->nodeId, &context);
  1049. UA_Nodestore_release(server, type);
  1050. }
  1051. }
  1052. /* Call the global destructor */
  1053. if(server->config.nodeLifecycle.destructor)
  1054. server->config.nodeLifecycle.destructor(server, &session->sessionId,
  1055. session->sessionHandle,
  1056. &node->nodeId, context);
  1057. }
  1058. static void
  1059. deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
  1060. const UA_DeleteNodesItem *item, UA_StatusCode *result);
  1061. static void
  1062. removeChildren(UA_Server *server, UA_Session *session,
  1063. const UA_Node *node) {
  1064. /* Browse to get all children of the node */
  1065. UA_BrowseDescription bd;
  1066. UA_BrowseDescription_init(&bd);
  1067. bd.nodeId = node->nodeId;
  1068. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
  1069. bd.includeSubtypes = true;
  1070. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  1071. bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
  1072. bd.resultMask = UA_BROWSERESULTMASK_NONE;
  1073. UA_BrowseResult br;
  1074. UA_BrowseResult_init(&br);
  1075. UA_UInt32 maxrefs = 0;
  1076. Operation_Browse(server, session, &maxrefs, &bd, &br);
  1077. if(br.statusCode != UA_STATUSCODE_GOOD)
  1078. return;
  1079. UA_DeleteNodesItem item;
  1080. item.deleteTargetReferences = true;
  1081. /* Remove every child */
  1082. for(size_t i = 0; i < br.referencesSize; ++i) {
  1083. UA_ReferenceDescription *rd = &br.references[i];
  1084. // check for self-reference to avoid endless loop
  1085. if(UA_NodeId_equal(&node->nodeId, &rd->nodeId.nodeId))
  1086. continue;
  1087. item.nodeId = rd->nodeId.nodeId;
  1088. UA_StatusCode retval;
  1089. deleteNodeOperation(server, session, NULL, &item, &retval);
  1090. }
  1091. UA_BrowseResult_deleteMembers(&br);
  1092. }
  1093. static void
  1094. removeDeconstructedNode(UA_Server *server, UA_Session *session,
  1095. const UA_Node *node, UA_Boolean removeTargetRefs) {
  1096. /* Remove all children of the node */
  1097. removeChildren(server, session, node);
  1098. /* Remove references to the node (not the references going out, as the node
  1099. * will be deleted anyway) */
  1100. if(removeTargetRefs)
  1101. removeIncomingReferences(server, session, node);
  1102. /* Remove the node in the nodestore */
  1103. UA_Nodestore_remove(server, &node->nodeId);
  1104. }
  1105. static void
  1106. deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
  1107. const UA_DeleteNodesItem *item, UA_StatusCode *result) {
  1108. /* Do not check access for server */
  1109. if(session != &adminSession && server->config.accessControl.allowDeleteNode &&
  1110. !server->config.accessControl.allowDeleteNode(server, &server->config.accessControl,
  1111. &session->sessionId, session->sessionHandle, item)) {
  1112. *result = UA_STATUSCODE_BADUSERACCESSDENIED;
  1113. return;
  1114. }
  1115. const UA_Node *node = UA_Nodestore_get(server, &item->nodeId);
  1116. if(!node) {
  1117. *result = UA_STATUSCODE_BADNODEIDUNKNOWN;
  1118. return;
  1119. }
  1120. if(UA_Node_hasSubTypeOrInstances(node)) {
  1121. UA_LOG_INFO_SESSION(server->config.logger, session,
  1122. "Delete Nodes: Cannot delete a type node "
  1123. "with active instances or subtypes");
  1124. UA_Nodestore_release(server, node);
  1125. *result = UA_STATUSCODE_BADINTERNALERROR;
  1126. return;
  1127. }
  1128. /* TODO: Check if the information model consistency is violated */
  1129. /* TODO: Check if the node is a mandatory child of a parent */
  1130. deconstructNode(server, session, node);
  1131. removeDeconstructedNode(server, session, node, item->deleteTargetReferences);
  1132. UA_Nodestore_release(server, node);
  1133. }
  1134. void Service_DeleteNodes(UA_Server *server, UA_Session *session,
  1135. const UA_DeleteNodesRequest *request,
  1136. UA_DeleteNodesResponse *response) {
  1137. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  1138. "Processing DeleteNodesRequest");
  1139. if(server->config.maxNodesPerNodeManagement != 0 &&
  1140. request->nodesToDeleteSize > server->config.maxNodesPerNodeManagement) {
  1141. response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
  1142. return;
  1143. }
  1144. response->responseHeader.serviceResult =
  1145. UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)deleteNodeOperation, NULL,
  1146. &request->nodesToDeleteSize, &UA_TYPES[UA_TYPES_DELETENODESITEM],
  1147. &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
  1148. }
  1149. UA_StatusCode
  1150. UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
  1151. UA_Boolean deleteReferences) {
  1152. UA_DeleteNodesItem item;
  1153. item.deleteTargetReferences = deleteReferences;
  1154. item.nodeId = nodeId;
  1155. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1156. deleteNodeOperation(server, &adminSession, NULL, &item, &retval);
  1157. return retval;
  1158. }
  1159. /******************/
  1160. /* Add References */
  1161. /******************/
  1162. static UA_StatusCode
  1163. addOneWayReference(UA_Server *server, UA_Session *session,
  1164. UA_Node *node, const UA_AddReferencesItem *item) {
  1165. return UA_Node_addReference(node, item);
  1166. }
  1167. static UA_StatusCode
  1168. deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
  1169. const UA_DeleteReferencesItem *item) {
  1170. return UA_Node_deleteReference(node, item);
  1171. }
  1172. static void
  1173. Operation_addReference(UA_Server *server, UA_Session *session, void *context,
  1174. const UA_AddReferencesItem *item, UA_StatusCode *retval) {
  1175. /* Do not check access for server */
  1176. if(session != &adminSession && server->config.accessControl.allowAddReference &&
  1177. !server->config.accessControl.allowAddReference(server, &server->config.accessControl,
  1178. &session->sessionId, session->sessionHandle, item)) {
  1179. *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
  1180. return;
  1181. }
  1182. /* Currently no expandednodeids are allowed */
  1183. if(item->targetServerUri.length > 0) {
  1184. *retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
  1185. return;
  1186. }
  1187. /* Add the first direction */
  1188. *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  1189. (UA_EditNodeCallback)addOneWayReference,
  1190. /* cast away const because callback uses const anyway */
  1191. (UA_AddReferencesItem *)(uintptr_t)item);
  1192. UA_Boolean firstExisted = UA_FALSE;
  1193. if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
  1194. *retval = UA_STATUSCODE_GOOD;
  1195. firstExisted = UA_TRUE;
  1196. } else if(*retval != UA_STATUSCODE_GOOD)
  1197. return;
  1198. /* Add the second direction */
  1199. UA_AddReferencesItem secondItem;
  1200. UA_AddReferencesItem_init(&secondItem);
  1201. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  1202. secondItem.referenceTypeId = item->referenceTypeId;
  1203. secondItem.isForward = !item->isForward;
  1204. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  1205. /* keep default secondItem.targetNodeClass = UA_NODECLASS_UNSPECIFIED */
  1206. *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  1207. (UA_EditNodeCallback)addOneWayReference, &secondItem);
  1208. /* remove reference if the second direction failed */
  1209. UA_Boolean secondExisted = UA_FALSE;
  1210. if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
  1211. *retval = UA_STATUSCODE_GOOD;
  1212. secondExisted = UA_TRUE;
  1213. } else if(*retval != UA_STATUSCODE_GOOD && !firstExisted) {
  1214. UA_DeleteReferencesItem deleteItem;
  1215. deleteItem.sourceNodeId = item->sourceNodeId;
  1216. deleteItem.referenceTypeId = item->referenceTypeId;
  1217. deleteItem.isForward = item->isForward;
  1218. deleteItem.targetNodeId = item->targetNodeId;
  1219. deleteItem.deleteBidirectional = false;
  1220. /* ignore returned status code */
  1221. UA_Server_editNode(server, session, &item->sourceNodeId,
  1222. (UA_EditNodeCallback)deleteOneWayReference, &deleteItem);
  1223. }
  1224. /* Calculate common duplicate reference not allowed result and set bad result
  1225. * if BOTH directions already existed */
  1226. if(firstExisted && secondExisted)
  1227. *retval = UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED;
  1228. }
  1229. void Service_AddReferences(UA_Server *server, UA_Session *session,
  1230. const UA_AddReferencesRequest *request,
  1231. UA_AddReferencesResponse *response) {
  1232. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  1233. "Processing AddReferencesRequest");
  1234. if(server->config.maxNodesPerNodeManagement != 0 &&
  1235. request->referencesToAddSize > server->config.maxNodesPerNodeManagement) {
  1236. response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
  1237. return;
  1238. }
  1239. response->responseHeader.serviceResult =
  1240. UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_addReference, NULL,
  1241. &request->referencesToAddSize, &UA_TYPES[UA_TYPES_ADDREFERENCESITEM],
  1242. &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
  1243. }
  1244. UA_StatusCode
  1245. UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
  1246. const UA_NodeId refTypeId,
  1247. const UA_ExpandedNodeId targetId,
  1248. UA_Boolean isForward) {
  1249. UA_AddReferencesItem item;
  1250. UA_AddReferencesItem_init(&item);
  1251. item.sourceNodeId = sourceId;
  1252. item.referenceTypeId = refTypeId;
  1253. item.isForward = isForward;
  1254. item.targetNodeId = targetId;
  1255. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1256. Operation_addReference(server, &adminSession, NULL, &item, &retval);
  1257. return retval;
  1258. }
  1259. /*********************/
  1260. /* Delete References */
  1261. /*********************/
  1262. static void
  1263. Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
  1264. const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
  1265. /* Do not check access for server */
  1266. if(session != &adminSession && server->config.accessControl.allowDeleteReference &&
  1267. !server->config.accessControl.allowDeleteReference(server, &server->config.accessControl,
  1268. &session->sessionId, session->sessionHandle, item)) {
  1269. *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
  1270. return;
  1271. }
  1272. // TODO: Check consistency constraints, remove the references.
  1273. *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
  1274. (UA_EditNodeCallback)deleteOneWayReference,
  1275. /* cast away const qualifier because callback uses it anyway */
  1276. (UA_DeleteReferencesItem *)(uintptr_t)item);
  1277. if(*retval != UA_STATUSCODE_GOOD)
  1278. return;
  1279. if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
  1280. return;
  1281. UA_DeleteReferencesItem secondItem;
  1282. UA_DeleteReferencesItem_init(&secondItem);
  1283. secondItem.isForward = !item->isForward;
  1284. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  1285. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  1286. secondItem.referenceTypeId = item->referenceTypeId;
  1287. *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
  1288. (UA_EditNodeCallback)deleteOneWayReference,
  1289. &secondItem);
  1290. }
  1291. void
  1292. Service_DeleteReferences(UA_Server *server, UA_Session *session,
  1293. const UA_DeleteReferencesRequest *request,
  1294. UA_DeleteReferencesResponse *response) {
  1295. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  1296. "Processing DeleteReferencesRequest");
  1297. if(server->config.maxNodesPerNodeManagement != 0 &&
  1298. request->referencesToDeleteSize > server->config.maxNodesPerNodeManagement) {
  1299. response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
  1300. return;
  1301. }
  1302. response->responseHeader.serviceResult =
  1303. UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_deleteReference, NULL,
  1304. &request->referencesToDeleteSize, &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM],
  1305. &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
  1306. }
  1307. UA_StatusCode
  1308. UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
  1309. const UA_NodeId referenceTypeId, UA_Boolean isForward,
  1310. const UA_ExpandedNodeId targetNodeId,
  1311. UA_Boolean deleteBidirectional) {
  1312. UA_DeleteReferencesItem item;
  1313. item.sourceNodeId = sourceNodeId;
  1314. item.referenceTypeId = referenceTypeId;
  1315. item.isForward = isForward;
  1316. item.targetNodeId = targetNodeId;
  1317. item.deleteBidirectional = deleteBidirectional;
  1318. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  1319. Operation_deleteReference(server, &adminSession, NULL, &item, &retval);
  1320. return retval;
  1321. }
  1322. /**********************/
  1323. /* Set Value Callback */
  1324. /**********************/
  1325. static UA_StatusCode
  1326. setValueCallback(UA_Server *server, UA_Session *session,
  1327. UA_VariableNode *node, const UA_ValueCallback *callback) {
  1328. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1329. return UA_STATUSCODE_BADNODECLASSINVALID;
  1330. node->value.data.callback = *callback;
  1331. return UA_STATUSCODE_GOOD;
  1332. }
  1333. UA_StatusCode
  1334. UA_Server_setVariableNode_valueCallback(UA_Server *server,
  1335. const UA_NodeId nodeId,
  1336. const UA_ValueCallback callback) {
  1337. return UA_Server_editNode(server, &adminSession, &nodeId,
  1338. (UA_EditNodeCallback)setValueCallback,
  1339. /* cast away const because callback uses const anyway */
  1340. (UA_ValueCallback *)(uintptr_t) &callback);
  1341. }
  1342. /***************************************************/
  1343. /* Special Handling of Variables with Data Sources */
  1344. /***************************************************/
  1345. UA_StatusCode
  1346. UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
  1347. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
  1348. const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
  1349. const UA_VariableAttributes attr, const UA_DataSource dataSource,
  1350. void *nodeContext, UA_NodeId *outNewNodeId) {
  1351. UA_AddNodesItem item;
  1352. UA_AddNodesItem_init(&item);
  1353. item.nodeClass = UA_NODECLASS_VARIABLE;
  1354. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  1355. item.browseName = browseName;
  1356. UA_ExpandedNodeId typeDefinitionId;
  1357. UA_ExpandedNodeId_init(&typeDefinitionId);
  1358. typeDefinitionId.nodeId = typeDefinition;
  1359. item.typeDefinition = typeDefinitionId;
  1360. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  1361. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr;
  1362. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
  1363. UA_NodeId newNodeId;
  1364. UA_Boolean deleteNodeId = UA_FALSE;
  1365. if(!outNewNodeId) {
  1366. newNodeId = UA_NODEID_NULL;
  1367. outNewNodeId = &newNodeId;
  1368. deleteNodeId = UA_TRUE;
  1369. }
  1370. UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, nodeContext,
  1371. &item, &parentNodeId, &referenceTypeId, outNewNodeId);
  1372. if(retval != UA_STATUSCODE_GOOD)
  1373. return retval;
  1374. retval = UA_Server_setVariableNode_dataSource(server, *outNewNodeId, dataSource);
  1375. if(retval == UA_STATUSCODE_GOOD)
  1376. retval = Operation_addNode_finish(server, &adminSession, outNewNodeId);
  1377. if(retval != UA_STATUSCODE_GOOD || deleteNodeId)
  1378. UA_NodeId_deleteMembers(outNewNodeId);
  1379. return retval;
  1380. }
  1381. static UA_StatusCode
  1382. setDataSource(UA_Server *server, UA_Session *session,
  1383. UA_VariableNode* node, const UA_DataSource *dataSource) {
  1384. if(node->nodeClass != UA_NODECLASS_VARIABLE)
  1385. return UA_STATUSCODE_BADNODECLASSINVALID;
  1386. if(node->valueSource == UA_VALUESOURCE_DATA)
  1387. UA_DataValue_deleteMembers(&node->value.data.value);
  1388. node->value.dataSource = *dataSource;
  1389. node->valueSource = UA_VALUESOURCE_DATASOURCE;
  1390. return UA_STATUSCODE_GOOD;
  1391. }
  1392. UA_StatusCode
  1393. UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  1394. const UA_DataSource dataSource) {
  1395. return UA_Server_editNode(server, &adminSession, &nodeId,
  1396. (UA_EditNodeCallback)setDataSource,
  1397. /* casting away const because callback casts it back anyway */
  1398. (UA_DataSource *) (uintptr_t)&dataSource);
  1399. }
  1400. /************************************/
  1401. /* Special Handling of Method Nodes */
  1402. /************************************/
  1403. #ifdef UA_ENABLE_METHODCALLS
  1404. static const UA_NodeId hasproperty = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASPROPERTY}};
  1405. static const UA_NodeId propertytype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_PROPERTYTYPE}};
  1406. static UA_StatusCode
  1407. UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
  1408. UA_MethodCallback method,
  1409. const size_t inputArgumentsSize, const UA_Argument *inputArguments,
  1410. const UA_NodeId inputArgumentsRequestedNewNodeId,
  1411. UA_NodeId *inputArgumentsOutNewNodeId,
  1412. const size_t outputArgumentsSize, const UA_Argument *outputArguments,
  1413. const UA_NodeId outputArgumentsRequestedNewNodeId,
  1414. UA_NodeId *outputArgumentsOutNewNodeId) {
  1415. /* Browse to see which argument nodes exist */
  1416. UA_BrowseDescription bd;
  1417. UA_BrowseDescription_init(&bd);
  1418. bd.nodeId = nodeId;
  1419. bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
  1420. bd.includeSubtypes = false;
  1421. bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
  1422. bd.nodeClassMask = UA_NODECLASS_VARIABLE;
  1423. bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;
  1424. UA_BrowseResult br;
  1425. UA_BrowseResult_init(&br);
  1426. UA_UInt32 maxrefs = 0;
  1427. Operation_Browse(server, &adminSession, &maxrefs, &bd, &br);
  1428. UA_StatusCode retval = br.statusCode;
  1429. if(retval != UA_STATUSCODE_GOOD) {
  1430. UA_Server_deleteNode(server, nodeId, true);
  1431. UA_BrowseResult_deleteMembers(&br);
  1432. return retval;
  1433. }
  1434. /* Filter out the argument nodes */
  1435. UA_NodeId inputArgsId = UA_NODEID_NULL;
  1436. UA_NodeId outputArgsId = UA_NODEID_NULL;
  1437. const UA_QualifiedName inputArgsName = UA_QUALIFIEDNAME(0, "InputArguments");
  1438. const UA_QualifiedName outputArgsName = UA_QUALIFIEDNAME(0, "OutputArguments");
  1439. for(size_t i = 0; i < br.referencesSize; i++) {
  1440. UA_ReferenceDescription *rd = &br.references[i];
  1441. if(rd->browseName.namespaceIndex == 0 &&
  1442. UA_String_equal(&rd->browseName.name, &inputArgsName.name))
  1443. inputArgsId = rd->nodeId.nodeId;
  1444. else if(rd->browseName.namespaceIndex == 0 &&
  1445. UA_String_equal(&rd->browseName.name, &outputArgsName.name))
  1446. outputArgsId = rd->nodeId.nodeId;
  1447. }
  1448. /* Add the Input Arguments VariableNode */
  1449. if(inputArgumentsSize > 0 && UA_NodeId_isNull(&inputArgsId)) {
  1450. UA_VariableAttributes attr = UA_VariableAttributes_default;
  1451. char *name = "InputArguments";
  1452. attr.displayName = UA_LOCALIZEDTEXT("", name);
  1453. attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
  1454. attr.valueRank = 1;
  1455. UA_Variant_setArray(&attr.value, (void*)(uintptr_t) inputArguments,
  1456. inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  1457. retval |= UA_Server_addVariableNode(server, inputArgumentsRequestedNewNodeId, nodeId,
  1458. hasproperty, UA_QUALIFIEDNAME(0, name),
  1459. propertytype, attr, NULL, &inputArgsId);
  1460. }
  1461. /* Add the Output Arguments VariableNode */
  1462. if(outputArgumentsSize > 0 && UA_NodeId_isNull(&outputArgsId)) {
  1463. UA_VariableAttributes attr = UA_VariableAttributes_default;
  1464. char *name = "OutputArguments";
  1465. attr.displayName = UA_LOCALIZEDTEXT("", name);
  1466. attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
  1467. attr.valueRank = 1;
  1468. UA_Variant_setArray(&attr.value, (void*)(uintptr_t) outputArguments,
  1469. outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
  1470. retval |= UA_Server_addVariableNode(server, outputArgumentsRequestedNewNodeId, nodeId,
  1471. hasproperty, UA_QUALIFIEDNAME(0, name),
  1472. propertytype, attr, NULL, &outputArgsId);
  1473. }
  1474. retval |= UA_Server_setMethodNode_callback(server, nodeId, method);
  1475. /* Call finish to add the parent reference */
  1476. retval |= Operation_addNode_finish(server, &adminSession, &nodeId);
  1477. if(retval != UA_STATUSCODE_GOOD) {
  1478. UA_Server_deleteNode(server, nodeId, true);
  1479. UA_Server_deleteNode(server, inputArgsId, true);
  1480. UA_Server_deleteNode(server, outputArgsId, true);
  1481. } else {
  1482. if(inputArgumentsOutNewNodeId != NULL) {
  1483. UA_NodeId_copy(&inputArgsId, inputArgumentsOutNewNodeId);
  1484. }
  1485. if(outputArgumentsOutNewNodeId != NULL) {
  1486. UA_NodeId_copy(&outputArgsId, outputArgumentsOutNewNodeId);
  1487. }
  1488. }
  1489. UA_BrowseResult_deleteMembers(&br);
  1490. return retval;
  1491. }
  1492. UA_StatusCode
  1493. UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
  1494. UA_MethodCallback method,
  1495. size_t inputArgumentsSize, const UA_Argument* inputArguments,
  1496. size_t outputArgumentsSize, const UA_Argument* outputArguments) {
  1497. return UA_Server_addMethodNodeEx_finish(server, nodeId, method,
  1498. inputArgumentsSize, inputArguments, UA_NODEID_NULL, NULL,
  1499. outputArgumentsSize, outputArguments, UA_NODEID_NULL, NULL);
  1500. }
  1501. UA_StatusCode
  1502. UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId,
  1503. const UA_NodeId parentNodeId,
  1504. const UA_NodeId referenceTypeId,
  1505. const UA_QualifiedName browseName,
  1506. const UA_MethodAttributes attr, UA_MethodCallback method,
  1507. size_t inputArgumentsSize, const UA_Argument *inputArguments,
  1508. const UA_NodeId inputArgumentsRequestedNewNodeId,
  1509. UA_NodeId *inputArgumentsOutNewNodeId,
  1510. size_t outputArgumentsSize, const UA_Argument *outputArguments,
  1511. const UA_NodeId outputArgumentsRequestedNewNodeId,
  1512. UA_NodeId *outputArgumentsOutNewNodeId,
  1513. void *nodeContext, UA_NodeId *outNewNodeId) {
  1514. UA_AddNodesItem item;
  1515. UA_AddNodesItem_init(&item);
  1516. item.nodeClass = UA_NODECLASS_METHOD;
  1517. item.requestedNewNodeId.nodeId = requestedNewNodeId;
  1518. item.browseName = browseName;
  1519. item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  1520. item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)&attr;
  1521. item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_METHODATTRIBUTES];
  1522. UA_NodeId newId;
  1523. if(!outNewNodeId) {
  1524. UA_NodeId_init(&newId);
  1525. outNewNodeId = &newId;
  1526. }
  1527. UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, nodeContext,
  1528. &item, &parentNodeId, &referenceTypeId, outNewNodeId);
  1529. if(retval != UA_STATUSCODE_GOOD)
  1530. return retval;
  1531. retval = UA_Server_addMethodNodeEx_finish(server, *outNewNodeId, method,
  1532. inputArgumentsSize, inputArguments,
  1533. inputArgumentsRequestedNewNodeId,
  1534. inputArgumentsOutNewNodeId,
  1535. outputArgumentsSize, outputArguments,
  1536. outputArgumentsRequestedNewNodeId,
  1537. outputArgumentsOutNewNodeId);
  1538. if(outNewNodeId == &newId)
  1539. UA_NodeId_deleteMembers(&newId);
  1540. return retval;
  1541. }
  1542. static UA_StatusCode
  1543. editMethodCallback(UA_Server *server, UA_Session* session,
  1544. UA_Node* node, void* handle) {
  1545. if(node->nodeClass != UA_NODECLASS_METHOD)
  1546. return UA_STATUSCODE_BADNODECLASSINVALID;
  1547. UA_MethodNode *mnode = (UA_MethodNode*) node;
  1548. mnode->method = (UA_MethodCallback)(uintptr_t)handle;
  1549. return UA_STATUSCODE_GOOD;
  1550. }
  1551. UA_StatusCode
  1552. UA_Server_setMethodNode_callback(UA_Server *server,
  1553. const UA_NodeId methodNodeId,
  1554. UA_MethodCallback methodCallback) {
  1555. return UA_Server_editNode(server, &adminSession, &methodNodeId,
  1556. (UA_EditNodeCallback)editMethodCallback,
  1557. (void*)(uintptr_t)methodCallback);
  1558. }
  1559. #endif
  1560. /************************/
  1561. /* Lifecycle Management */
  1562. /************************/
  1563. static UA_StatusCode
  1564. setNodeTypeLifecycle(UA_Server *server, UA_Session *session,
  1565. UA_Node* node, UA_NodeTypeLifecycle *lifecycle) {
  1566. if(node->nodeClass == UA_NODECLASS_OBJECTTYPE) {
  1567. UA_ObjectTypeNode *ot = (UA_ObjectTypeNode*)node;
  1568. ot->lifecycle = *lifecycle;
  1569. return UA_STATUSCODE_GOOD;
  1570. }
  1571. if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
  1572. UA_VariableTypeNode *vt = (UA_VariableTypeNode*)node;
  1573. vt->lifecycle = *lifecycle;
  1574. return UA_STATUSCODE_GOOD;
  1575. }
  1576. return UA_STATUSCODE_BADNODECLASSINVALID;
  1577. }
  1578. UA_StatusCode
  1579. UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
  1580. UA_NodeTypeLifecycle lifecycle) {
  1581. return UA_Server_editNode(server, &adminSession, &nodeId,
  1582. (UA_EditNodeCallback)setNodeTypeLifecycle,
  1583. &lifecycle);
  1584. }