ua_server_addressspace.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #include "ua_server.h"
  2. #include "ua_server_internal.h"
  3. UA_StatusCode
  4. UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_QualifiedName browseName,
  5. UA_NodeId nodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId)
  6. {
  7. UA_VariableNode *node = UA_VariableNode_new();
  8. node->variable.variant = *value; // copy content
  9. UA_NodeId_copy(&nodeId, &node->nodeId);
  10. UA_QualifiedName_copy(&browseName, &node->browseName);
  11. UA_String_copy(&browseName.name, &node->displayName.text);
  12. UA_ExpandedNodeId parentId; // we need an expandednodeid
  13. UA_ExpandedNodeId_init(&parentId);
  14. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  15. UA_AddNodesResult res =
  16. UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
  17. ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
  18. UA_EXPANDEDNODEID_STATIC(0, value->type->typeId.identifier.numeric));
  19. if(res.statusCode != UA_STATUSCODE_GOOD) {
  20. UA_Variant_init(&node->variable.variant);
  21. UA_VariableNode_delete(node);
  22. } else
  23. UA_free(value);
  24. return res.statusCode;
  25. }
  26. UA_StatusCode
  27. UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
  28. const UA_QualifiedName browseName, UA_NodeId nodeId,
  29. const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId)
  30. {
  31. UA_VariableNode *node = UA_VariableNode_new();
  32. node->variableType = UA_VARIABLENODETYPE_DATASOURCE;
  33. node->variable.dataSource = dataSource;
  34. UA_NodeId_copy(&nodeId, &node->nodeId);
  35. UA_QualifiedName_copy(&browseName, &node->browseName);
  36. UA_String_copy(&browseName.name, &node->displayName.text);
  37. UA_ExpandedNodeId parentId; // dummy exapndednodeid
  38. UA_ExpandedNodeId_init(&parentId);
  39. UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
  40. UA_AddNodesResult res =
  41. UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
  42. ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
  43. UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
  44. if(res.statusCode != UA_STATUSCODE_GOOD)
  45. UA_VariableNode_delete(node);
  46. return res.statusCode;
  47. }
  48. /* Adds a one-way reference to the local nodestore */
  49. static UA_StatusCode
  50. addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item)
  51. {
  52. const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
  53. if(!node)
  54. return UA_STATUSCODE_BADINTERNALERROR;
  55. UA_Node *newNode = UA_NULL;
  56. void (*deleteNode)(UA_Node*) = UA_NULL;
  57. switch(node->nodeClass) {
  58. case UA_NODECLASS_OBJECT:
  59. newNode = (UA_Node*)UA_ObjectNode_new();
  60. UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode*)newNode);
  61. deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete;
  62. break;
  63. case UA_NODECLASS_VARIABLE:
  64. newNode = (UA_Node*)UA_VariableNode_new();
  65. UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode*)newNode);
  66. deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete;
  67. break;
  68. case UA_NODECLASS_METHOD:
  69. newNode = (UA_Node*)UA_MethodNode_new();
  70. UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode*)newNode);
  71. deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete;
  72. break;
  73. case UA_NODECLASS_OBJECTTYPE:
  74. newNode = (UA_Node*)UA_ObjectTypeNode_new();
  75. UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode*)newNode);
  76. deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete;
  77. break;
  78. case UA_NODECLASS_VARIABLETYPE:
  79. newNode = (UA_Node*)UA_VariableTypeNode_new();
  80. UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode*)newNode);
  81. deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete;
  82. break;
  83. case UA_NODECLASS_REFERENCETYPE:
  84. newNode = (UA_Node*)UA_ReferenceTypeNode_new();
  85. UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode*)newNode);
  86. deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete;
  87. break;
  88. case UA_NODECLASS_DATATYPE:
  89. newNode = (UA_Node*)UA_DataTypeNode_new();
  90. UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode*)newNode);
  91. deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete;
  92. break;
  93. case UA_NODECLASS_VIEW:
  94. newNode = (UA_Node*)UA_ViewNode_new();
  95. UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode*)newNode);
  96. deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
  97. break;
  98. default:
  99. return UA_STATUSCODE_BADINTERNALERROR;
  100. }
  101. UA_Int32 count = node->referencesSize;
  102. if(count < 0)
  103. count = 0;
  104. UA_ReferenceNode *old_refs = newNode->references;
  105. UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1));
  106. if(!new_refs) {
  107. deleteNode(newNode);
  108. UA_NodeStore_release(node);
  109. return UA_STATUSCODE_BADOUTOFMEMORY;
  110. }
  111. // insert the new reference
  112. UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
  113. UA_ReferenceNode_init(&new_refs[count]);
  114. UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
  115. new_refs[count].isInverse = !item->isForward;
  116. retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
  117. if(retval != UA_STATUSCODE_GOOD) {
  118. UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count);
  119. newNode->references = UA_NULL;
  120. newNode->referencesSize = 0;
  121. deleteNode(newNode);
  122. UA_NodeStore_release(node);
  123. return UA_STATUSCODE_BADOUTOFMEMORY;
  124. }
  125. UA_free(old_refs);
  126. newNode->references = new_refs;
  127. newNode->referencesSize = ++count;
  128. retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
  129. UA_NodeStore_release(node);
  130. if(retval != UA_STATUSCODE_BADINTERNALERROR)
  131. return retval;
  132. // error presumably because the node was replaced and an old version was updated just try again
  133. deleteNode(newNode);
  134. return addOneWayReferenceWithSession(server, session, item);
  135. }
  136. /* userland version of addReferenceWithSession */
  137. UA_StatusCode
  138. UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item)
  139. {
  140. return UA_Server_addReferenceWithSession(server, &adminSession, item);
  141. }
  142. UA_StatusCode
  143. UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item)
  144. {
  145. if(item->targetServerUri.length > 0)
  146. return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
  147. // Is this for an external nodestore?
  148. UA_ExternalNodeStore *ensFirst = UA_NULL;
  149. UA_ExternalNodeStore *ensSecond = UA_NULL;
  150. for(UA_Int32 j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
  151. if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
  152. ensFirst = &server->externalNamespaces[j].externalNodeStore;
  153. if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)
  154. ensSecond = &server->externalNamespaces[j].externalNodeStore;
  155. }
  156. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  157. if(ensFirst) {
  158. // todo: use external nodestore
  159. } else
  160. retval = addOneWayReferenceWithSession(server, session, item);
  161. if(retval) return retval;
  162. UA_AddReferencesItem secondItem;
  163. secondItem = *item;
  164. secondItem.targetNodeId.nodeId = item->sourceNodeId;
  165. secondItem.sourceNodeId = item->targetNodeId.nodeId;
  166. secondItem.isForward = !item->isForward;
  167. if(ensSecond) {
  168. // todo: use external nodestore
  169. } else
  170. retval = addOneWayReferenceWithSession (server, session, &secondItem);
  171. // todo: remove reference if the second direction failed
  172. return retval;
  173. }
  174. /* userland version of addNodeWithSession */
  175. UA_AddNodesResult
  176. UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId *parentNodeId,
  177. const UA_NodeId *referenceTypeId)
  178. {
  179. return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
  180. }
  181. UA_AddNodesResult
  182. UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
  183. const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId)
  184. {
  185. UA_AddNodesResult result;
  186. UA_AddNodesResult_init(&result);
  187. const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId);
  188. if(!parent) {
  189. result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
  190. return result;
  191. }
  192. const UA_ReferenceTypeNode *referenceType =
  193. (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
  194. if(!referenceType) {
  195. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  196. goto ret;
  197. }
  198. if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
  199. result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
  200. goto ret2;
  201. }
  202. if(referenceType->isAbstract == UA_TRUE) {
  203. result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
  204. goto ret2;
  205. }
  206. // todo: test if the referencetype is hierarchical
  207. const UA_Node *managed = UA_NULL;
  208. if(UA_NodeId_isNull(&node->nodeId)) {
  209. if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
  210. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  211. goto ret2;
  212. }
  213. result.addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
  214. } else {
  215. if(UA_NodeId_copy(&node->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
  216. result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
  217. goto ret2;
  218. }
  219. if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
  220. result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS; // todo: differentiate out of memory
  221. UA_NodeId_deleteMembers(&result.addedNodeId);
  222. goto ret2;
  223. }
  224. }
  225. // reference back to the parent
  226. UA_AddReferencesItem item;
  227. UA_AddReferencesItem_init(&item);
  228. item.sourceNodeId = managed->nodeId;
  229. item.referenceTypeId = referenceType->nodeId;
  230. item.isForward = UA_FALSE;
  231. item.targetNodeId.nodeId = parent->nodeId;
  232. UA_Server_addReference(server, &item);
  233. // todo: error handling. remove new node from nodestore
  234. UA_NodeStore_release(managed);
  235. ret2:
  236. UA_NodeStore_release((const UA_Node*)referenceType);
  237. ret:
  238. UA_NodeStore_release(parent);
  239. return result;
  240. }