ua_services_nodemanagement.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. #include "ua_server_internal.h"
  2. #include "ua_services.h"
  3. #include "ua_namespace_0.h"
  4. #include "ua_statuscodes.h"
  5. #include "ua_nodestore.h"
  6. #include "ua_services_internal.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, UA_Node **new_node,
  24. 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) != UA_STATUSCODE_GOOD)
  31. return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
  32. UA_VariableNode *vnode = UA_VariableNode_new();
  33. if(!vnode) {
  34. UA_VariableAttributes_deleteMembers(&attr);
  35. return UA_STATUSCODE_BADOUTOFMEMORY;
  36. }
  37. // now copy all the attributes. This potentially removes them from the decoded attributes.
  38. COPY_STANDARDATTRIBUTES;
  39. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ACCESSLEVEL)
  40. vnode->accessLevel = attr.accessLevel;
  41. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL)
  42. vnode->userAccessLevel = attr.userAccessLevel;
  43. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING)
  44. vnode->historizing = attr.historizing;
  45. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL)
  46. vnode->minimumSamplingInterval = attr.minimumSamplingInterval;
  47. if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
  48. vnode->valueRank = attr.valueRank;
  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. 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->value = attr.value;
  62. UA_Variant_init(&attr.value);
  63. }
  64. UA_VariableAttributes_deleteMembers(&attr);
  65. *new_node = (UA_Node*)vnode;
  66. *vt = &UA_TYPES[UA_VARIABLENODE];
  67. return UA_STATUSCODE_GOOD;
  68. }
  69. UA_Int32 AddReference(UA_NodeStore *nodestore, UA_Node *node, UA_ReferenceNode *reference);
  70. /**
  71. If adding the node succeeds, the pointer will be set to zero. If the nodeid
  72. of the node is null (ns=0,i=0), a unique new nodeid will be assigned and
  73. returned in the AddNodesResult.
  74. */
  75. UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session, UA_Node **node,
  76. const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
  77. UA_AddNodesResult result;
  78. UA_AddNodesResult_init(&result);
  79. const UA_Node *parent;
  80. if(UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId, &parent) != UA_STATUSCODE_GOOD) {
  81. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  82. return result;
  83. }
  84. const UA_ReferenceTypeNode *referenceType;
  85. if(UA_NodeStore_get(server->nodestore, referenceTypeId, (const UA_Node**)&referenceType) != UA_STATUSCODE_GOOD) {
  86. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  87. goto ret;
  88. }
  89. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  90. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  91. goto ret2;
  92. }
  93. if(referenceType->isAbstract == UA_TRUE) {
  94. result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
  95. goto ret2;
  96. }
  97. // todo: test if the referenetype is hierarchical
  98. if(UA_NodeId_isNull(&(*node)->nodeId)) {
  99. if(UA_NodeStore_insert(server->nodestore, node,
  100. UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
  101. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  102. goto ret2;
  103. }
  104. result.addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
  105. } else {
  106. if(UA_NodeId_copy(&(*node)->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
  107. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  108. goto ret2;
  109. }
  110. if(UA_NodeStore_insert(server->nodestore, node, UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
  111. result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
  112. UA_NodeId_deleteMembers(&result.addedNodeId);
  113. goto ret2;
  114. }
  115. }
  116. UA_ReferenceNode ref;
  117. UA_ReferenceNode_init(&ref);
  118. ref.referenceTypeId = referenceType->nodeId; // is numeric
  119. ref.isInverse = UA_TRUE; // todo: check if they are all not inverse..
  120. ref.targetId.nodeId = parent->nodeId;
  121. AddReference(server->nodestore, *node, &ref);
  122. // todo: error handling. remove new node from nodestore
  123. UA_NodeStore_release(*node);
  124. *node = UA_NULL;
  125. ret2:
  126. UA_NodeStore_release((UA_Node*)referenceType);
  127. ret:
  128. UA_NodeStore_release(parent);
  129. return result;
  130. }
  131. static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
  132. UA_AddNodesResult *result) {
  133. if(item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
  134. // adding nodes to ns0 is not allowed over the wire
  135. result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
  136. return;
  137. }
  138. UA_Node *newNode;
  139. const UA_VTable_Entry *newNodeVT = UA_NULL;
  140. if(item->nodeClass == UA_NODECLASS_VARIABLE)
  141. result->statusCode = parseVariableNode(&item->nodeAttributes, &newNode, &newNodeVT);
  142. else // add more node types here..
  143. result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
  144. if(result->statusCode != UA_STATUSCODE_GOOD)
  145. return;
  146. *result = AddNode(server, session, &newNode, &item->parentNodeId, &item->referenceTypeId);
  147. if(result->statusCode != UA_STATUSCODE_GOOD)
  148. newNodeVT->delete(newNode);
  149. }
  150. void Service_AddNodes(UA_Server *server, UA_Session *session,
  151. const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
  152. if(request->nodesToAddSize <= 0) {
  153. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  154. return;
  155. }
  156. UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToAddSize, &UA_TYPES[UA_ADDNODESRESULT]);
  157. if(retval) {
  158. response->responseHeader.serviceResult = retval;
  159. return;
  160. }
  161. response->resultsSize = request->nodesToAddSize;
  162. for(int i = 0;i < request->nodesToAddSize;i++)
  163. addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
  164. }
  165. static UA_Int32 AddSingleReference(UA_Node *node, UA_ReferenceNode *reference) {
  166. // TODO: Check if reference already exists
  167. UA_Int32 count = node->referencesSize;
  168. UA_ReferenceNode *old_refs = node->references;
  169. UA_ReferenceNode *new_refs;
  170. if(count < 0) count = 0;
  171. if(!(new_refs = UA_alloc(sizeof(UA_ReferenceNode)*(count+1))))
  172. return UA_STATUSCODE_BADOUTOFMEMORY;
  173. UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
  174. if(UA_ReferenceNode_copy(reference, &new_refs[count]) != UA_STATUSCODE_GOOD) {
  175. UA_free(new_refs);
  176. return UA_STATUSCODE_BADOUTOFMEMORY;
  177. }
  178. node->references = new_refs;
  179. node->referencesSize = count+1;
  180. UA_free(old_refs);
  181. return UA_STATUSCODE_GOOD;
  182. }
  183. UA_Int32 AddReference(UA_NodeStore *nodestore, UA_Node *node, UA_ReferenceNode *reference) {
  184. UA_Int32 retval = AddSingleReference(node, reference);
  185. UA_Node *targetnode;
  186. UA_ReferenceNode inversereference;
  187. if(retval != UA_STATUSCODE_GOOD || nodestore == UA_NULL)
  188. return retval;
  189. // Do a copy every time?
  190. if(UA_NodeStore_get(nodestore, &reference->targetId.nodeId, (const UA_Node **)&targetnode) != UA_STATUSCODE_GOOD)
  191. return UA_STATUSCODE_BADINTERNALERROR;
  192. inversereference.referenceTypeId = reference->referenceTypeId;
  193. inversereference.isInverse = !reference->isInverse;
  194. inversereference.targetId.nodeId = node->nodeId;
  195. inversereference.targetId.namespaceUri = UA_STRING_NULL;
  196. inversereference.targetId.serverIndex = 0;
  197. retval = AddSingleReference(targetnode, &inversereference);
  198. UA_NodeStore_release(targetnode);
  199. return retval;
  200. }
  201. void Service_AddReferences(UA_Server *server, UA_Session *session,
  202. const UA_AddReferencesRequest *request,
  203. UA_AddReferencesResponse *response) {
  204. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
  205. }