ua_server_addressspace.c 11 KB

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