ua_services_nodemanagement.c 13 KB

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