ua_services_nodemanagement.c 13 KB

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