ua_services_nodemanagement.c 62 KB

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