ua_services_nodemanagement.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. #include "ua_services.h"
  2. #include "ua_namespace_0.h"
  3. #include "ua_statuscodes.h"
  4. #include "nodestore/ua_nodestoreExample.h"
  5. #include "ua_services_internal.h"
  6. #include "ua_namespace_manager.h"
  7. #include "ua_session.h"
  8. #include "ua_util.h"
  9. #define COPY_STANDARDATTRIBUTES do { \
  10. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) { \
  11. vnode->displayName = attr.displayName; \
  12. UA_LocalizedText_init(&attr.displayName); \
  13. } \
  14. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DESCRIPTION) { \
  15. vnode->description = attr.description; \
  16. UA_LocalizedText_init(&attr.description); \
  17. } \
  18. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_WRITEMASK) \
  19. vnode->writeMask = attr.writeMask; \
  20. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERWRITEMASK) \
  21. vnode->userWriteMask = attr.userWriteMask; \
  22. } while(0)
  23. static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes,
  24. UA_Node **new_node, const UA_VTable_Entry **vt) {
  25. if (attributes->typeId.identifier.numeric != 357) // VariableAttributes_Encoding_DefaultBinary,357,Object
  26. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  27. UA_VariableAttributes attr;
  28. UA_UInt32 pos = 0;
  29. // todo return more informative error codes from decodeBinary
  30. if (UA_VariableAttributes_decodeBinary(&attributes->body, &pos, &attr)
  31. != UA_STATUSCODE_GOOD)
  32. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  33. UA_VariableNode *vnode;
  34. if (UA_VariableNode_new(&vnode) != UA_STATUSCODE_GOOD) {
  35. UA_VariableAttributes_deleteMembers(&attr);
  36. return UA_STATUSCODE_BADOUTOFMEMORY;
  37. }
  38. // now copy all the attributes. This potentially removes them from the decoded attributes.
  39. COPY_STANDARDATTRIBUTES;
  40. if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ACCESSLEVEL)
  41. vnode->accessLevel = attr.accessLevel;
  42. if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL)
  43. vnode->userAccessLevel = attr.userAccessLevel;
  44. if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING)
  45. vnode->historizing = attr.historizing;
  46. if (attr.specifiedAttributes
  47. & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL)
  48. vnode->minimumSamplingInterval = attr.minimumSamplingInterval;
  49. if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
  50. vnode->valueRank = attr.valueRank;
  51. if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) {
  52. vnode->arrayDimensionsSize = attr.arrayDimensionsSize;
  53. vnode->arrayDimensions = attr.arrayDimensions;
  54. attr.arrayDimensionsSize = -1;
  55. attr.arrayDimensions = UA_NULL;
  56. }
  57. if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE
  58. || attr.specifiedAttributes
  59. & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) {
  60. vnode->dataType = attr.dataType;
  61. UA_NodeId_init(&attr.dataType);
  62. }
  63. if (attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
  64. vnode->value = attr.value;
  65. UA_Variant_init(&attr.value);
  66. }
  67. UA_VariableAttributes_deleteMembers(&attr);
  68. *new_node = (UA_Node*) vnode;
  69. *vt = &UA_[UA_VARIABLENODE];
  70. return UA_STATUSCODE_GOOD;
  71. }
  72. UA_Int32 AddReference(UA_NodeStoreExample *nodestore, UA_Node *node,
  73. UA_ReferenceNode *reference);
  74. /**
  75. If adding the node succeeds, the pointer will be set to zero. If the nodeid
  76. of the node is null (ns=0,i=0), a unique new nodeid will be assigned and
  77. returned in the AddNodesResult.
  78. */
  79. UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session,
  80. UA_Node **node, UA_ExpandedNodeId *parentNodeId,
  81. UA_NodeId *referenceTypeId) {
  82. UA_AddNodesResult result;
  83. UA_AddNodesResult_init(&result);
  84. const UA_Node *parent;
  85. if (UA_NodeStoreExample_get(server->nodestore, &parentNodeId->nodeId,
  86. &parent) != UA_STATUSCODE_GOOD) {
  87. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  88. return result;
  89. }
  90. const UA_ReferenceTypeNode *referenceType;
  91. if (UA_NodeStoreExample_get(server->nodestore, referenceTypeId,
  92. (const UA_Node**) &referenceType) != UA_STATUSCODE_GOOD) {
  93. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  94. goto ret;
  95. }
  96. if (referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  97. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  98. goto ret2;
  99. }
  100. if (referenceType->isAbstract == UA_TRUE) {
  101. result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
  102. goto ret2;
  103. }
  104. // todo: test if the referenetype is hierarchical
  105. if (UA_NodeId_isNull(&(*node)->nodeId)) {
  106. if (UA_NodeStoreExample_insert(server->nodestore, node,
  107. UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED)
  108. != UA_STATUSCODE_GOOD) {
  109. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  110. goto ret2;
  111. }
  112. result.addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
  113. } else {
  114. if (UA_NodeId_copy(&(*node)->nodeId, &result.addedNodeId)
  115. != UA_STATUSCODE_GOOD) {
  116. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  117. goto ret2;
  118. }
  119. if (UA_NodeStoreExample_insert(server->nodestore, node,
  120. UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
  121. result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
  122. UA_NodeId_deleteMembers(&result.addedNodeId);
  123. goto ret2;
  124. }
  125. }
  126. UA_ReferenceNode ref;
  127. UA_ReferenceNode_init(&ref);
  128. ref.referenceTypeId = referenceType->nodeId; // is numeric
  129. ref.isInverse = UA_TRUE; // todo: check if they are all not inverse..
  130. ref.targetId.nodeId = parent->nodeId;
  131. AddReference(server->nodestore, *node, &ref);
  132. // todo: error handling. remove new node from nodestore
  133. UA_NodeStoreExample_releaseManagedNode(*node);
  134. *node = UA_NULL;
  135. ret2: UA_NodeStoreExample_releaseManagedNode((UA_Node*) referenceType);
  136. ret: UA_NodeStoreExample_releaseManagedNode(parent);
  137. return result;
  138. }
  139. static void addNodeFromAttributes(UA_Server *server, UA_Session *session,
  140. UA_AddNodesItem *item, UA_AddNodesResult *result) {
  141. if (item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
  142. // adding nodes to ns0 is not allowed over the wire
  143. result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
  144. return;
  145. }
  146. UA_Node *newNode;
  147. const UA_VTable_Entry *newNodeVT = UA_NULL;
  148. if (item->nodeClass == UA_NODECLASS_VARIABLE)
  149. result->statusCode = parseVariableNode(&item->nodeAttributes, &newNode,
  150. &newNodeVT);
  151. else
  152. // add more node types here..
  153. result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
  154. if (result->statusCode != UA_STATUSCODE_GOOD)
  155. return;
  156. *result = AddNode(server, session, &newNode, &item->parentNodeId,
  157. &item->referenceTypeId);
  158. if (result->statusCode != UA_STATUSCODE_GOOD)
  159. newNodeVT->delete(newNode);
  160. }
  161. void Service_AddNodes(UA_Server *server, UA_Session *session,
  162. const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
  163. UA_assert(server != UA_NULL && session != UA_NULL);
  164. if (request->nodesToAddSize <= 0) {
  165. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  166. return;
  167. }
  168. if (UA_Array_new((void **) &response->results, request->nodesToAddSize,
  169. &UA_[UA_ADDNODESRESULT]) != UA_STATUSCODE_GOOD) {
  170. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  171. return;
  172. }
  173. if (UA_Array_new((void **) &response->diagnosticInfos,
  174. request->nodesToAddSize, &UA_[UA_DIAGNOSTICINFO])
  175. != UA_STATUSCODE_GOOD) {
  176. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  177. return;
  178. }
  179. response->resultsSize = request->nodesToAddSize;
  180. UA_Int32 *numberOfFoundIndices;
  181. UA_UInt16 *associatedIndices;
  182. UA_UInt32 differentNamespaceIndexCount = 0;
  183. if (UA_Array_new((void **) &numberOfFoundIndices,
  184. request->nodesToAddSize, &UA_[UA_UINT32])
  185. != UA_STATUSCODE_GOOD) {
  186. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  187. return;
  188. }
  189. if (UA_Array_new((void **) &associatedIndices, request->nodesToAddSize,
  190. &UA_[UA_UINT16]) != UA_STATUSCODE_GOOD) {
  191. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  192. return;
  193. }
  194. // find out count of different namespace indices
  195. for (UA_Int32 i = 0; i < request->nodesToAddSize; i++) {
  196. for (UA_UInt32 j = 0; j <= differentNamespaceIndexCount; j++) {
  197. if (associatedIndices[j]
  198. == request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex) {
  199. if (j == 0) {
  200. differentNamespaceIndexCount++;
  201. }
  202. numberOfFoundIndices[j]++;
  203. break;
  204. } else if (j == (differentNamespaceIndexCount - 1)) {
  205. associatedIndices[j] =
  206. request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex;
  207. associatedIndices[j] = 1;
  208. differentNamespaceIndexCount++;
  209. }
  210. }
  211. }
  212. UA_UInt32 *addNodesIndices;
  213. if (UA_Array_new((void **) &addNodesIndices,
  214. request->nodesToAddSize, &UA_[UA_UINT32])
  215. != UA_STATUSCODE_GOOD) {
  216. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  217. return;
  218. }
  219. for (UA_UInt32 i = 0; i < differentNamespaceIndexCount; i++) {
  220. UA_Namespace *tmpNamespace;
  221. UA_NamespaceManager_getNamespace(server->namespaceManager,
  222. associatedIndices[i], &tmpNamespace);
  223. if (tmpNamespace != UA_NULL) {
  224. //build up index array for each read operation onto a different namespace
  225. UA_UInt32 n = 0;
  226. for (UA_Int32 j = 0; j < request->nodesToAddSize; j++) {
  227. if (request->nodesToAdd[j].requestedNewNodeId.nodeId.namespaceIndex
  228. == associatedIndices[i]) {
  229. addNodesIndices[n] = j;
  230. }
  231. }
  232. //call read for every namespace
  233. tmpNamespace->nodeStore->addNodes(request->nodesToAdd,
  234. addNodesIndices, numberOfFoundIndices[i],
  235. response->results, response->diagnosticInfos);
  236. // response->results[i] = service_read_node(server, &request->nodesToRead[i]);
  237. }
  238. }
  239. UA_free(addNodesIndices);
  240. UA_free(numberOfFoundIndices);
  241. UA_free(associatedIndices);
  242. /* if (request->nodesToAddSize <= 0) {
  243. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  244. return;
  245. }
  246. if (UA_Array_new((void **) &response->results, request->nodesToAddSize,
  247. &UA_[UA_ADDNODESRESULT]) != UA_STATUSCODE_GOOD) {
  248. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  249. return;
  250. }
  251. response->resultsSize = request->nodesToAddSize;
  252. for (int i = 0; i < request->nodesToAddSize; i++)
  253. addNodeFromAttributes(server, session, &request->nodesToAdd[i],
  254. &response->results[i]);
  255. */
  256. }
  257. static UA_Int32 AddSingleReference(UA_Node *node, UA_ReferenceNode *reference) {
  258. // TODO: Check if reference already exists
  259. UA_Int32 count = node->referencesSize;
  260. UA_ReferenceNode *old_refs = node->references;
  261. UA_ReferenceNode *new_refs;
  262. if (count < 0)
  263. count = 0;
  264. if (!(new_refs = UA_alloc(sizeof(UA_ReferenceNode) * (count + 1))))
  265. return UA_STATUSCODE_BADOUTOFMEMORY;
  266. UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode) * count);
  267. if (UA_ReferenceNode_copy(reference, &new_refs[count])
  268. != UA_STATUSCODE_GOOD) {
  269. UA_free(new_refs);
  270. return UA_STATUSCODE_BADOUTOFMEMORY;
  271. }
  272. node->references = new_refs;
  273. node->referencesSize = count + 1;
  274. UA_free(old_refs);
  275. return UA_STATUSCODE_GOOD;
  276. }
  277. UA_Int32 AddReference(UA_NodeStoreExample *nodestore, UA_Node *node,
  278. UA_ReferenceNode *reference) {
  279. UA_Int32 retval = AddSingleReference(node, reference);
  280. UA_Node *targetnode;
  281. UA_ReferenceNode inversereference;
  282. if (retval != UA_STATUSCODE_GOOD || nodestore == UA_NULL)
  283. return retval;
  284. // Do a copy every time?
  285. if (UA_NodeStoreExample_get(nodestore, &reference->targetId.nodeId,
  286. (const UA_Node **) &targetnode) != UA_STATUSCODE_GOOD)
  287. return UA_STATUSCODE_BADINTERNALERROR;
  288. inversereference.referenceTypeId = reference->referenceTypeId;
  289. inversereference.isInverse = !reference->isInverse;
  290. inversereference.targetId.nodeId = node->nodeId;
  291. inversereference.targetId.namespaceUri = UA_STRING_NULL;
  292. inversereference.targetId.serverIndex = 0;
  293. retval = AddSingleReference(targetnode, &inversereference);
  294. UA_NodeStoreExample_releaseManagedNode(targetnode);
  295. return retval;
  296. }
  297. void Service_AddReferences(UA_Server *server, UA_Session *session,
  298. const UA_AddReferencesRequest *request,
  299. UA_AddReferencesResponse *response) {
  300. if (request->referencesToAddSize <= 0) {
  301. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  302. return;
  303. }
  304. if (UA_Array_new((void **) &response->results, request->referencesToAddSize,
  305. &UA_[UA_STATUSCODE]) != UA_STATUSCODE_GOOD) {
  306. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  307. return;
  308. }
  309. if (UA_Array_new((void **) &response->diagnosticInfos,
  310. request->referencesToAddSize, &UA_[UA_DIAGNOSTICINFO])
  311. != UA_STATUSCODE_GOOD) {
  312. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  313. return;
  314. }
  315. response->resultsSize = request->referencesToAddSize;
  316. UA_Int32 *numberOfFoundIndices;
  317. UA_UInt16 *associatedIndices;
  318. UA_UInt32 differentNamespaceIndexCount = 0;
  319. if (UA_Array_new((void **) &numberOfFoundIndices,
  320. request->referencesToAddSize, &UA_[UA_UINT32])
  321. != UA_STATUSCODE_GOOD) {
  322. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  323. return;
  324. }
  325. if (UA_Array_new((void **) &associatedIndices, request->referencesToAddSize,
  326. &UA_[UA_UINT16]) != UA_STATUSCODE_GOOD) {
  327. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  328. return;
  329. }
  330. // find out count of different namespace indices
  331. for (UA_Int32 i = 0; i < request->referencesToAddSize; i++) {
  332. for (UA_UInt32 j = 0; j <= differentNamespaceIndexCount; j++) {
  333. if (associatedIndices[j]
  334. == request->referencesToAdd[i].sourceNodeId.namespaceIndex) {
  335. if (j == 0) {
  336. differentNamespaceIndexCount++;
  337. }
  338. numberOfFoundIndices[j]++;
  339. break;
  340. } else if (j == (differentNamespaceIndexCount - 1)) {
  341. associatedIndices[j] =
  342. request->referencesToAdd[i].sourceNodeId.namespaceIndex;
  343. associatedIndices[j] = 1;
  344. differentNamespaceIndexCount++;
  345. }
  346. }
  347. }
  348. UA_UInt32 *readValueIdIndices;
  349. if (UA_Array_new((void **) &readValueIdIndices,
  350. request->referencesToAddSize, &UA_[UA_UINT32])
  351. != UA_STATUSCODE_GOOD) {
  352. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  353. return;
  354. }
  355. for (UA_UInt32 i = 0; i < differentNamespaceIndexCount; i++) {
  356. UA_Namespace *tmpNamespace;
  357. UA_NamespaceManager_getNamespace(server->namespaceManager,
  358. associatedIndices[i], &tmpNamespace);
  359. if (tmpNamespace != UA_NULL) {
  360. //build up index array for each read operation onto a different namespace
  361. UA_UInt32 n = 0;
  362. for (UA_Int32 j = 0; j < request->referencesToAddSize; j++) {
  363. if (request->referencesToAdd[j].sourceNodeId.namespaceIndex
  364. == associatedIndices[i]) {
  365. readValueIdIndices[n] = j;
  366. }
  367. }
  368. //call read for every namespace
  369. tmpNamespace->nodeStore->addReferences(request->referencesToAdd,
  370. readValueIdIndices, numberOfFoundIndices[i],
  371. response->results, response->diagnosticInfos);
  372. // response->results[i] = service_read_node(server, &request->nodesToRead[i]);
  373. }
  374. }
  375. UA_free(readValueIdIndices);
  376. UA_free(numberOfFoundIndices);
  377. UA_free(associatedIndices);
  378. /*
  379. for(UA_Int32 i = 0;i < response->resultsSize;i++){
  380. response->results[i] = service_read_node(server, &request->nodesToRead[i]);
  381. }
  382. }
  383. */
  384. //response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
  385. }