ua_services_nodemanagement.c 5.0 KB

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