ua_services_nodemanagement.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #include "ua_util.h"
  2. #include "ua_server_internal.h"
  3. #include "ua_services.h"
  4. #include "ua_statuscodes.h"
  5. #include "ua_nodestore.h"
  6. #include "ua_session.h"
  7. #include "ua_types_generated_encoding_binary.h"
  8. #define COPY_STANDARDATTRIBUTES do { \
  9. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) { \
  10. vnode->displayName = attr.displayName; \
  11. UA_LocalizedText_init(&attr.displayName); \
  12. } \
  13. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DESCRIPTION) { \
  14. vnode->description = attr.description; \
  15. UA_LocalizedText_init(&attr.description); \
  16. } \
  17. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_WRITEMASK) \
  18. vnode->writeMask = attr.writeMask; \
  19. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERWRITEMASK) \
  20. vnode->userWriteMask = attr.userWriteMask; \
  21. } while(0)
  22. static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
  23. if(attributes->typeId.identifier.numeric !=
  24. UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES].typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY)
  25. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  26. UA_VariableAttributes attr;
  27. size_t pos = 0;
  28. // todo return more informative error codes from decodeBinary
  29. if(UA_VariableAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
  30. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  31. UA_VariableNode *vnode = UA_VariableNode_new();
  32. if(!vnode) {
  33. UA_VariableAttributes_deleteMembers(&attr);
  34. return UA_STATUSCODE_BADOUTOFMEMORY;
  35. }
  36. // now copy all the attributes. This potentially removes them from the decoded attributes.
  37. COPY_STANDARDATTRIBUTES;
  38. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ACCESSLEVEL)
  39. vnode->accessLevel = attr.accessLevel;
  40. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL)
  41. vnode->userAccessLevel = attr.userAccessLevel;
  42. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING)
  43. vnode->historizing = attr.historizing;
  44. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL)
  45. vnode->minimumSamplingInterval = attr.minimumSamplingInterval;
  46. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
  47. vnode->valueRank = attr.valueRank;
  48. // don't use extra dimension spec. This comes from the value.
  49. /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) { */
  50. /* vnode->arrayDimensionsSize = attr.arrayDimensionsSize; */
  51. /* vnode->arrayDimensions = attr.arrayDimensions; */
  52. /* attr.arrayDimensionsSize = -1; */
  53. /* attr.arrayDimensions = UA_NULL; */
  54. /* } */
  55. // don't use the extra type id. This comes from the value.
  56. /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE || */
  57. /* attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) { */
  58. /* vnode->dataType = attr.dataType; */
  59. /* UA_NodeId_init(&attr.dataType); */
  60. /* } */
  61. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
  62. vnode->value.variant.value = attr.value;
  63. UA_Variant_init(&attr.value);
  64. }
  65. UA_VariableAttributes_deleteMembers(&attr);
  66. *new_node = (UA_Node*)vnode;
  67. return UA_STATUSCODE_GOOD;
  68. }
  69. static UA_StatusCode parseObjectNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
  70. if(attributes->typeId.identifier.numeric !=
  71. UA_TYPES[UA_TYPES_OBJECTATTRIBUTES].typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY)
  72. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  73. UA_ObjectAttributes attr;
  74. size_t pos = 0;
  75. // todo return more informative error codes from decodeBinary
  76. if (UA_ObjectAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
  77. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  78. UA_ObjectNode *vnode = UA_ObjectNode_new();
  79. if(!vnode) {
  80. UA_ObjectAttributes_deleteMembers(&attr);
  81. return UA_STATUSCODE_BADOUTOFMEMORY;
  82. }
  83. // now copy all the attributes. This potentially removes them from the decoded attributes.
  84. COPY_STANDARDATTRIBUTES;
  85. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_EVENTNOTIFIER)
  86. vnode->eventNotifier = attr.eventNotifier;
  87. UA_ObjectAttributes_deleteMembers(&attr);
  88. *new_node = (UA_Node*) vnode;
  89. return UA_STATUSCODE_GOOD;
  90. }
  91. static UA_StatusCode parseReferenceTypeNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
  92. UA_ReferenceTypeAttributes attr;
  93. size_t pos = 0;
  94. // todo return more informative error codes from decodeBinary
  95. if(UA_ReferenceTypeAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
  96. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  97. UA_ReferenceTypeNode *vnode = UA_ReferenceTypeNode_new();
  98. if(!vnode) {
  99. UA_ReferenceTypeAttributes_deleteMembers(&attr);
  100. return UA_STATUSCODE_BADOUTOFMEMORY;
  101. }
  102. // now copy all the attributes. This potentially removes them from the decoded attributes.
  103. COPY_STANDARDATTRIBUTES;
  104. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ISABSTRACT)
  105. vnode->isAbstract = attr.isAbstract;
  106. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_SYMMETRIC)
  107. vnode->symmetric = attr.symmetric;
  108. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_INVERSENAME) {
  109. vnode->inverseName = attr.inverseName;
  110. attr.inverseName.text.length = -1;
  111. attr.inverseName.text.data = UA_NULL;
  112. attr.inverseName.locale.length = -1;
  113. attr.inverseName.locale.data = UA_NULL;
  114. }
  115. UA_ReferenceTypeAttributes_deleteMembers(&attr);
  116. *new_node = (UA_Node*) vnode;
  117. return UA_STATUSCODE_GOOD;
  118. }
  119. static UA_StatusCode parseObjectTypeNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
  120. UA_ObjectTypeAttributes attr;
  121. size_t pos = 0;
  122. // todo return more informative error codes from decodeBinary
  123. if(UA_ObjectTypeAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
  124. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  125. UA_ObjectTypeNode *vnode = UA_ObjectTypeNode_new();
  126. if(!vnode) {
  127. UA_ObjectTypeAttributes_deleteMembers(&attr);
  128. return UA_STATUSCODE_BADOUTOFMEMORY;
  129. }
  130. // now copy all the attributes. This potentially removes them from the decoded attributes.
  131. COPY_STANDARDATTRIBUTES;
  132. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ISABSTRACT) {
  133. vnode->isAbstract = attr.isAbstract;
  134. }
  135. UA_ObjectTypeAttributes_deleteMembers(&attr);
  136. *new_node = (UA_Node*) vnode;
  137. return UA_STATUSCODE_GOOD;
  138. }
  139. static UA_StatusCode parseViewNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
  140. UA_ViewAttributes attr;
  141. size_t pos = 0;
  142. // todo return more informative error codes from decodeBinary
  143. if(UA_ViewAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
  144. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  145. UA_ViewNode *vnode = UA_ViewNode_new();
  146. if(!vnode) {
  147. UA_ViewAttributes_deleteMembers(&attr);
  148. return UA_STATUSCODE_BADOUTOFMEMORY;
  149. }
  150. // now copy all the attributes. This potentially removes them from the decoded attributes.
  151. COPY_STANDARDATTRIBUTES;
  152. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS)
  153. vnode->containsNoLoops = attr.containsNoLoops;
  154. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_EVENTNOTIFIER)
  155. vnode->eventNotifier = attr.eventNotifier;
  156. UA_ViewAttributes_deleteMembers(&attr);
  157. *new_node = (UA_Node*) vnode;
  158. return UA_STATUSCODE_GOOD;
  159. }
  160. static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
  161. UA_AddNodesResult *result) {
  162. // adding nodes to ns0 is not allowed over the wire
  163. if(item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
  164. result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
  165. return;
  166. }
  167. // parse the node
  168. UA_Node *node = UA_NULL;
  169. switch (item->nodeClass) {
  170. case UA_NODECLASS_OBJECT:
  171. result->statusCode = parseObjectNode(&item->nodeAttributes, &node);
  172. break;
  173. case UA_NODECLASS_OBJECTTYPE:
  174. result->statusCode = parseObjectTypeNode(&item->nodeAttributes, &node);
  175. break;
  176. case UA_NODECLASS_REFERENCETYPE:
  177. result->statusCode = parseReferenceTypeNode(&item->nodeAttributes, &node);
  178. break;
  179. case UA_NODECLASS_VARIABLE:
  180. result->statusCode = parseVariableNode(&item->nodeAttributes, &node);
  181. break;
  182. default:
  183. result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
  184. }
  185. if(result->statusCode != UA_STATUSCODE_GOOD)
  186. return;
  187. // The BrowseName was not included with the NodeAttribute ExtensionObject
  188. UA_QualifiedName_init(&(node->browseName));
  189. UA_QualifiedName_copy(&(item->browseName), &(node->browseName));
  190. UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
  191. // add the node
  192. *result = UA_Server_addNodeWithSession(server, session, node, item->parentNodeId,
  193. item->referenceTypeId);
  194. if(result->statusCode != UA_STATUSCODE_GOOD) {
  195. switch (node->nodeClass) {
  196. case UA_NODECLASS_OBJECT:
  197. UA_ObjectNode_delete((UA_ObjectNode*)node);
  198. break;
  199. case UA_NODECLASS_OBJECTTYPE:
  200. UA_ObjectTypeNode_delete((UA_ObjectTypeNode*)node);
  201. break;
  202. case UA_NODECLASS_REFERENCETYPE:
  203. UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode*)node);
  204. break;
  205. case UA_NODECLASS_VARIABLE:
  206. UA_VariableNode_delete((UA_VariableNode*)node);
  207. break;
  208. default:
  209. UA_assert(UA_FALSE);
  210. }
  211. }
  212. }
  213. static UA_StatusCode deleteNode(UA_Server *server, UA_NodeId nodeId, UA_Boolean deleteReferences) {
  214. const UA_Node *delNode = UA_NodeStore_get(server->nodestore, &nodeId);
  215. if (!delNode)
  216. return UA_STATUSCODE_BADNODEIDINVALID;
  217. // Find and remove all References to this node if so requested.
  218. if(deleteReferences == UA_TRUE) {
  219. UA_DeleteReferencesItem *delItem = UA_DeleteReferencesItem_new();
  220. delItem->deleteBidirectional = UA_TRUE; // WARNING: Current semantics in deleteOneWayReference is 'delete forward or inverse'
  221. UA_NodeId_copy(&nodeId, &delItem->targetNodeId.nodeId);
  222. for(int i=0; i<delNode->referencesSize; i++) {
  223. UA_NodeId_copy(&delNode->references[i].targetId.nodeId, &delItem->sourceNodeId);
  224. UA_NodeId_deleteMembers(&delItem->sourceNodeId);
  225. }
  226. UA_DeleteReferencesItem_delete(delItem);
  227. }
  228. UA_NodeStore_release(delNode);
  229. return UA_NodeStore_remove(server->nodestore, &nodeId);
  230. }
  231. void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
  232. UA_AddNodesResponse *response) {
  233. if(request->nodesToAddSize <= 0) {
  234. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  235. return;
  236. }
  237. size_t size = request->nodesToAddSize;
  238. response->results = UA_Array_new(&UA_TYPES[UA_TYPES_ADDNODESRESULT], size);
  239. if(!response->results) {
  240. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  241. return;
  242. }
  243. #ifdef UA_EXTERNAL_NAMESPACES
  244. #ifdef NO_ALLOCA
  245. UA_Boolean isExternal[size];
  246. UA_UInt32 indices[size];
  247. #else
  248. UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
  249. UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
  250. #endif /*NO_ALLOCA */
  251. UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
  252. for(size_t j = 0; j <server->externalNamespacesSize; j++) {
  253. size_t indexSize = 0;
  254. for(size_t i = 0;i < size;i++) {
  255. if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex !=
  256. server->externalNamespaces[j].index)
  257. continue;
  258. isExternal[i] = UA_TRUE;
  259. indices[indexSize] = i;
  260. indexSize++;
  261. }
  262. if(indexSize == 0)
  263. continue;
  264. UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
  265. ens->addNodes(ens->ensHandle, &request->requestHeader, request->nodesToAdd,
  266. indices, indexSize, response->results, response->diagnosticInfos);
  267. }
  268. #endif
  269. response->resultsSize = size;
  270. for(size_t i = 0;i < size;i++) {
  271. #ifdef UA_EXTERNAL_NAMESPACES
  272. if(!isExternal[i])
  273. #endif
  274. addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
  275. }
  276. }
  277. void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
  278. UA_AddReferencesResponse *response) {
  279. if(request->referencesToAddSize <= 0) {
  280. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  281. return;
  282. }
  283. size_t size = request->referencesToAddSize;
  284. if(!(response->results = UA_malloc(sizeof(UA_StatusCode) * size))) {
  285. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  286. return;
  287. }
  288. response->resultsSize = size;
  289. UA_memset(response->results, UA_STATUSCODE_GOOD, sizeof(UA_StatusCode) * size);
  290. #ifdef UA_EXTERNAL_NAMESPACES
  291. #ifdef NO_ALLOCA
  292. UA_Boolean isExternal[size];
  293. UA_UInt32 indices[size];
  294. #else
  295. UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
  296. UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
  297. #endif /*NO_ALLOCA */
  298. UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
  299. for(size_t j = 0; j < server->externalNamespacesSize; j++) {
  300. size_t indicesSize = 0;
  301. for(size_t i = 0;i < size;i++) {
  302. if(request->referencesToAdd[i].sourceNodeId.namespaceIndex
  303. != server->externalNamespaces[j].index)
  304. continue;
  305. isExternal[i] = UA_TRUE;
  306. indices[indicesSize] = i;
  307. indicesSize++;
  308. }
  309. if (indicesSize == 0)
  310. continue;
  311. UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
  312. ens->addReferences(ens->ensHandle, &request->requestHeader, request->referencesToAdd,
  313. indices, indicesSize, response->results, response->diagnosticInfos);
  314. }
  315. #endif
  316. response->resultsSize = size;
  317. for(UA_Int32 i = 0; i < response->resultsSize; i++) {
  318. #ifdef UA_EXTERNAL_NAMESPACES
  319. if(!isExternal[i])
  320. #endif
  321. UA_Server_addReferenceWithSession(server, session, &request->referencesToAdd[i]);
  322. }
  323. }
  324. void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
  325. UA_DeleteNodesResponse *response) {
  326. UA_StatusCode retval = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
  327. response->resultsSize = request->nodesToDeleteSize;
  328. response->results = (UA_StatusCode *) UA_malloc(sizeof(UA_StatusCode) * request->nodesToDeleteSize);
  329. UA_DeleteNodesItem *item;
  330. for(int i=0; i<request->nodesToDeleteSize; i++) {
  331. item = &request->nodesToDelete[i];
  332. response->results[i] = deleteNode(server, item->nodeId, item->deleteTargetReferences);
  333. }
  334. response->responseHeader.serviceResult = retval;
  335. }
  336. void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
  337. UA_DeleteReferencesResponse *response) {
  338. UA_StatusCode retval = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
  339. response->responseHeader.serviceResult = retval;
  340. }