ua_services_nodemanagement.c 64 KB

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