ua_server_addressspace.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "ua_server.h"
  2. #include "ua_server_internal.h"
  3. #include "ua_namespace_0.h"
  4. static const UA_TypeVTable * UA_Node_getTypeVT(const UA_Node *node) {
  5. switch(node->nodeClass) {
  6. case UA_NODECLASS_OBJECT:
  7. return &UA_TYPES[UA_OBJECTNODE];
  8. case UA_NODECLASS_VARIABLE:
  9. return &UA_TYPES[UA_VARIABLENODE];
  10. case UA_NODECLASS_METHOD:
  11. return &UA_TYPES[UA_METHODNODE];
  12. case UA_NODECLASS_OBJECTTYPE:
  13. return &UA_TYPES[UA_OBJECTTYPENODE];
  14. case UA_NODECLASS_VARIABLETYPE:
  15. return &UA_TYPES[UA_VARIABLETYPENODE];
  16. case UA_NODECLASS_REFERENCETYPE:
  17. return &UA_TYPES[UA_REFERENCETYPENODE];
  18. case UA_NODECLASS_DATATYPE:
  19. return &UA_TYPES[UA_DATATYPENODE];
  20. case UA_NODECLASS_VIEW:
  21. return &UA_TYPES[UA_VIEWNODE];
  22. default: break;
  23. }
  24. return &UA_TYPES[UA_INVALIDTYPE];
  25. }
  26. void UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
  27. const UA_TypeVTable *vt, const UA_ExpandedNodeId *parentNodeId,
  28. const UA_NodeId *referenceTypeId) {
  29. UA_VariableNode *tmpNode = UA_VariableNode_new();
  30. UA_QualifiedName_copy(browseName, &tmpNode->browseName);
  31. UA_String_copy(&browseName->name, &tmpNode->displayName.text);
  32. /* UA_LocalizedText_copycstring("integer value", &tmpNode->description); */
  33. tmpNode->nodeClass = UA_NODECLASS_VARIABLE;
  34. tmpNode->valueRank = -1;
  35. tmpNode->value.vt = vt;
  36. tmpNode->value.storage.data.dataPtr = value;
  37. tmpNode->value.storageType = UA_VARIANT_DATA;
  38. tmpNode->value.storage.data.arrayLength = 1;
  39. UA_Server_addNode(server, (const UA_Node**)&tmpNode, parentNodeId, referenceTypeId);
  40. }
  41. /* Adds a one-way reference to the local nodestore */
  42. static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session *session,
  43. const UA_AddReferencesItem *item) {
  44. // use the servers nodestore
  45. const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
  46. // todo differentiate between error codes
  47. if(!node)
  48. return UA_STATUSCODE_BADINTERNALERROR;
  49. const UA_TypeVTable *nodeVT = UA_Node_getTypeVT(node);
  50. UA_Node *newNode = nodeVT->new();
  51. nodeVT->copy(node, newNode);
  52. UA_Int32 count = node->referencesSize;
  53. if(count < 0)
  54. count = 0;
  55. UA_ReferenceNode *old_refs = newNode->references;
  56. UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1));
  57. if(!new_refs) {
  58. nodeVT->delete(newNode);
  59. UA_NodeStore_release(node);
  60. return UA_STATUSCODE_BADOUTOFMEMORY;
  61. }
  62. // insert the new reference
  63. UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
  64. UA_ReferenceNode_init(&new_refs[count]);
  65. UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
  66. new_refs[count].isInverse = !item->isForward;
  67. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
  68. if(retval != UA_STATUSCODE_GOOD) {
  69. UA_Array_delete(new_refs, ++count, &UA_TYPES[UA_REFERENCENODE]);
  70. newNode->references = UA_NULL;
  71. newNode->referencesSize = 0;
  72. nodeVT->delete(newNode);
  73. UA_NodeStore_release(node);
  74. return UA_STATUSCODE_BADOUTOFMEMORY;
  75. }
  76. UA_free(old_refs);
  77. newNode->references = new_refs;
  78. newNode->referencesSize = ++count;
  79. const UA_Node *constNode = newNode;
  80. retval = UA_NodeStore_replace(server->nodestore, node, (const UA_Node **)&constNode, UA_FALSE);
  81. UA_NodeStore_release(node);
  82. if(retval != UA_STATUSCODE_BADINTERNALERROR)
  83. return retval;
  84. // error presumably because the node was replaced and an old version was updated
  85. // just try again
  86. nodeVT->delete(newNode);
  87. return addOneWayReferenceWithSession(server, session, item);
  88. }
  89. UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item) {
  90. return UA_Server_addReferenceWithSession(server, &adminSession, item);
  91. }
  92. UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
  93. const UA_AddReferencesItem *item) {
  94. // todo: we don't support references to other servers (expandednodeid) for now
  95. if(item->targetServerUri.length > 0)
  96. return UA_STATUSCODE_BADNOTIMPLEMENTED;
  97. // Is this for an external nodestore?
  98. UA_ExternalNodeStore *ensFirst = UA_NULL;
  99. UA_ExternalNodeStore *ensSecond = UA_NULL;
  100. for(UA_Int32 j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
  101. if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
  102. ensFirst = &server->externalNamespaces[j].externalNodeStore;
  103. if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)
  104. ensSecond = &server->externalNamespaces[j].externalNodeStore;
  105. }
  106. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  107. if(ensFirst) {
  108. // todo: use external nodestore
  109. } else
  110. retval = addOneWayReferenceWithSession(server, session, item);
  111. if(retval) return retval;
  112. UA_AddReferencesItem secondItem;
  113. secondItem = *item;
  114. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  115. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  116. secondItem.isForward = !item->isForward;
  117. if(ensSecond) {
  118. // todo: use external nodestore
  119. } else
  120. retval = addOneWayReferenceWithSession (server, session, &secondItem);
  121. // todo: remove reference if the second direction failed
  122. return retval;
  123. }
  124. UA_AddNodesResult UA_Server_addNode(UA_Server *server, const UA_Node **node,
  125. const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
  126. return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
  127. }
  128. UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, const UA_Node **node,
  129. const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
  130. UA_AddNodesResult result;
  131. UA_AddNodesResult_init(&result);
  132. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId);
  133. if(!parent) {
  134. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  135. return result;
  136. }
  137. const UA_ReferenceTypeNode *referenceType =
  138. (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
  139. if(!referenceType) {
  140. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  141. goto ret;
  142. }
  143. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  144. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  145. goto ret2;
  146. }
  147. if(referenceType->isAbstract == UA_TRUE) {
  148. result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
  149. goto ret2;
  150. }
  151. // todo: test if the referencetype is hierarchical
  152. if(UA_NodeId_isNull(&(*node)->nodeId)) {
  153. if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
  154. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  155. goto ret2;
  156. }
  157. result.addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
  158. } else {
  159. if(UA_NodeId_copy(&(*node)->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
  160. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  161. goto ret2;
  162. }
  163. if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
  164. result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
  165. UA_NodeId_deleteMembers(&result.addedNodeId);
  166. goto ret2;
  167. }
  168. }
  169. // reference back to the parent
  170. UA_AddReferencesItem item;
  171. UA_AddReferencesItem_init(&item);
  172. item.sourceNodeId = (*node)->nodeId;
  173. item.referenceTypeId = referenceType->nodeId;
  174. item.isForward = UA_FALSE;
  175. item.targetNodeId.nodeId = parent->nodeId;
  176. UA_Server_addReference(server, &item);
  177. // todo: error handling. remove new node from nodestore
  178. UA_NodeStore_release(*node);
  179. *node = UA_NULL;
  180. ret2:
  181. UA_NodeStore_release((const UA_Node*)referenceType);
  182. ret:
  183. UA_NodeStore_release(parent);
  184. return result;
  185. }