ua_services_nodemanagement.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #include "ua_services.h"
  2. #include "ua_statuscodes.h"
  3. #include "ua_namespace.h"
  4. #include "ua_services_internal.h"
  5. #include "ua_stack_session.h"
  6. #define CHECKED_ACTION(ACTION, CLEAN_UP, GOTO) do { \
  7. status |= ACTION; \
  8. if(status != UA_SUCCESS) { \
  9. CLEAN_UP; \
  10. goto GOTO; \
  11. } } while(0) \
  12. static UA_AddNodesResult addSingleNode(Application *app, UA_AddNodesItem *item) {
  13. UA_AddNodesResult result;
  14. UA_AddNodesResult_init(&result);
  15. Namespace *parent_ns = UA_indexedList_findValue(app->namespaces, item->parentNodeId.nodeId.namespace);
  16. // TODO: search for namespaceUris and not only ns-ids.
  17. if(parent_ns == UA_NULL) {
  18. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  19. return result;
  20. }
  21. Namespace *ns = UA_NULL;
  22. UA_Boolean nodeid_isnull = UA_NodeId_isNull(&item->requestedNewNodeId.nodeId);
  23. if(nodeid_isnull) ns = parent_ns;
  24. else ns = UA_indexedList_findValue(app->namespaces, item->requestedNewNodeId.nodeId.namespace);
  25. if(ns == UA_NULL || item->requestedNewNodeId.nodeId.namespace == 0) {
  26. result.statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
  27. return result;
  28. }
  29. UA_Int32 status = UA_SUCCESS;
  30. const UA_Node *parent;
  31. Namespace_Entry_Lock *parent_lock = UA_NULL;
  32. CHECKED_ACTION(Namespace_get(parent_ns, &item->parentNodeId.nodeId, &parent, &parent_lock),
  33. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID, ret);
  34. if(!nodeid_isnull && Namespace_contains(ns, &item->requestedNewNodeId.nodeId)) {
  35. result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS;
  36. goto ret;
  37. }
  38. /**
  39. TODO:
  40. 1) Check for the remaining conditions
  41. Bad_ReferenceTypeIdInvalid See Table 166 for the description of this result code.
  42. Bad_ReferenceNotAllowed The reference could not be created because it violates constraints imposed by the data model.
  43. Bad_NodeClassInvalid See Table 166 for the description of this result code.
  44. Bad_BrowseNameInvalid See Table 166 for the description of this result code.
  45. Bad_BrowseNameDuplicated The browse name is not unique among nodes that share the same relationship with the parent.
  46. Bad_NodeAttributesInvalid The node Attributes are not valid for the node class.
  47. Bad_TypeDefinitionInvalid See Table 166 for the description of this result code.
  48. Bad_UserAccessDenied See Table 165 for the description of this result code
  49. 2) Parse the UA_Node from the ExtensionObject
  50. 3) Create a new entry in the namespace
  51. 4) Add the reference to the parent.
  52. */
  53. ret:
  54. Namespace_Entry_Lock_release(parent_lock);
  55. return result;
  56. }
  57. UA_Int32 Service_AddNodes(UA_Session session, const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
  58. Application *application;
  59. if(session == UA_NULL)
  60. return UA_ERROR; // TODO: Return error message
  61. UA_Session_getApplicationPointer(session,&application);
  62. if(application == UA_NULL)
  63. return UA_ERROR;
  64. UA_Int32 nodestoaddsize = request->nodesToAddSize;
  65. if(nodestoaddsize <= 0) {
  66. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  67. response->resultsSize = 0;
  68. return UA_SUCCESS;
  69. }
  70. response->resultsSize = nodestoaddsize;
  71. UA_alloc((void **)&response->results, sizeof(void *) * nodestoaddsize);
  72. for(int i = 0; i < nodestoaddsize; i++) {
  73. DBG_VERBOSE(UA_QualifiedName_printf("service_addnodes - name=", &(request->nodesToAdd[i].browseName)));
  74. response->results[i] = addSingleNode(application, &request->nodesToAdd[i]);
  75. }
  76. response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
  77. response->diagnosticInfosSize = -1;
  78. return UA_SUCCESS;
  79. }
  80. static UA_Int32 AddSingleReference(UA_Node *node, UA_ReferenceNode *reference) {
  81. // TODO: Check if reference already exists
  82. UA_Int32 count = node->referencesSize;
  83. if(count < 0) count = 0;
  84. UA_ReferenceNode *old_refs = node->references;
  85. UA_ReferenceNode *new_refs;
  86. UA_Int32 retval = UA_alloc((void **)&new_refs, sizeof(UA_ReferenceNode)*(count+1));
  87. if(retval != UA_SUCCESS)
  88. return UA_ERROR;
  89. UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
  90. retval |= UA_ReferenceNode_copy(reference, &new_refs[count]);
  91. if(retval != UA_SUCCESS) {
  92. UA_free(new_refs);
  93. return retval;
  94. }
  95. node->references = new_refs;
  96. node->referencesSize = count+1;
  97. UA_free(old_refs);
  98. return retval;
  99. }
  100. UA_Int32 AddReference(UA_Node *node, UA_ReferenceNode *reference, Namespace *targetns) {
  101. UA_Int32 retval = AddSingleReference(node, reference);
  102. if(retval != UA_SUCCESS || targetns == UA_NULL)
  103. return retval;
  104. UA_Node *targetnode;
  105. Namespace_Entry_Lock *lock;
  106. // TODO: Nodes in the namespace are immutable (for lockless multithreading).
  107. // Do a copy every time?
  108. if(Namespace_get(targetns, &reference->targetId.nodeId, (const UA_Node**)&targetnode, &lock) != UA_SUCCESS)
  109. return UA_ERROR;
  110. UA_ReferenceNode inversereference;
  111. inversereference.referenceTypeId = reference->referenceTypeId;
  112. inversereference.isInverse = !reference->isInverse;
  113. inversereference.targetId = (UA_ExpandedNodeId){node->nodeId, UA_STRING_NULL, 0};
  114. retval = AddSingleReference(targetnode, &inversereference);
  115. Namespace_Entry_Lock_release(lock);
  116. return retval;
  117. }
  118. UA_Int32 Service_AddReferences(UA_Session session, const UA_AddReferencesRequest *request, UA_AddReferencesResponse *response) {
  119. return UA_ERROR;
  120. }