ua_services_nodemanagement.c 69 KB

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