ua_services_view.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include "ua_services.h"
  2. #include "ua_statuscodes.h"
  3. UA_Int32 Service_Browse_getReferenceDescription(UA_Namespace *ns, UA_ReferenceNode *reference,
  4. UA_UInt32 nodeClassMask, UA_UInt32 resultMask,
  5. UA_ReferenceDescription *referenceDescription) {
  6. const UA_Node *foundNode;
  7. if(UA_Namespace_get(ns, &reference->targetId.nodeId, &foundNode) != UA_SUCCESS)
  8. return UA_ERROR;
  9. UA_NodeId_copy(&foundNode->nodeId, &referenceDescription->nodeId.nodeId);
  10. //TODO ExpandedNodeId is a mockup
  11. referenceDescription->nodeId.serverIndex = 0;
  12. referenceDescription->nodeId.namespaceUri.length = -1;
  13. UA_UInt32 mask = 0;
  14. for(mask = 0x01;mask <= 0x40;mask *= 2) {
  15. switch(mask & (resultMask)) {
  16. case UA_BROWSERESULTMASK_REFERENCETYPEID:
  17. UA_NodeId_copy(&reference->referenceTypeId, &referenceDescription->referenceTypeId);
  18. break;
  19. case UA_BROWSERESULTMASK_ISFORWARD:
  20. referenceDescription->isForward = !reference->isInverse;
  21. break;
  22. case UA_BROWSERESULTMASK_NODECLASS:
  23. UA_NodeClass_copy(&foundNode->nodeClass, &referenceDescription->nodeClass);
  24. break;
  25. case UA_BROWSERESULTMASK_BROWSENAME:
  26. UA_QualifiedName_copy(&foundNode->browseName, &referenceDescription->browseName);
  27. break;
  28. case UA_BROWSERESULTMASK_DISPLAYNAME:
  29. UA_LocalizedText_copy(&foundNode->displayName, &referenceDescription->displayName);
  30. break;
  31. case UA_BROWSERESULTMASK_TYPEDEFINITION:
  32. if(foundNode->nodeClass != UA_NODECLASS_OBJECT &&
  33. foundNode->nodeClass != UA_NODECLASS_VARIABLE)
  34. break;
  35. for(UA_Int32 i = 0;i < foundNode->referencesSize;i++) {
  36. UA_ReferenceNode *ref = &foundNode->references[i];
  37. if(ref->referenceTypeId.identifier.numeric == 40 /* hastypedefinition */) {
  38. UA_ExpandedNodeId_copy(&ref->targetId, &referenceDescription->typeDefinition);
  39. break;
  40. }
  41. }
  42. break;
  43. }
  44. }
  45. UA_Namespace_releaseManagedNode(foundNode);
  46. return UA_SUCCESS;
  47. }
  48. /* singly-linked list */
  49. struct SubRefTypeId {
  50. UA_NodeId id;
  51. SLIST_ENTRY(SubRefTypeId) next;
  52. };
  53. SLIST_HEAD(SubRefTypeIdList, SubRefTypeId);
  54. UA_UInt32 walkReferenceTree(UA_Namespace *ns, const UA_ReferenceTypeNode *current,
  55. struct SubRefTypeIdList *list) {
  56. // insert the current referencetype
  57. struct SubRefTypeId *element;
  58. UA_alloc((void **)&element, sizeof(struct SubRefTypeId));
  59. element->id = current->nodeId;
  60. SLIST_INSERT_HEAD(list, element, next);
  61. UA_UInt32 count = 1; // the current element
  62. // walk the tree
  63. for(UA_Int32 i = 0;i < current->referencesSize;i++) {
  64. if(current->references[i].referenceTypeId.identifier.numeric == 45 /* HasSubtype */ &&
  65. current->references[i].isInverse == UA_FALSE) {
  66. const UA_Node *node;
  67. if(UA_Namespace_get(ns, &current->references[i].targetId.nodeId, &node) == UA_SUCCESS
  68. && node->nodeClass == UA_NODECLASS_REFERENCETYPE) {
  69. count += walkReferenceTree(ns, (UA_ReferenceTypeNode *)node, list);
  70. UA_Namespace_releaseManagedNode(node);
  71. }
  72. }
  73. }
  74. return count;
  75. }
  76. /* We do not search across namespaces so far. The id of the father-referencetype is returned in the array also. */
  77. static UA_Int32 findSubReferenceTypes(UA_Namespace *ns, UA_NodeId *rootReferenceType,
  78. UA_NodeId **ids, UA_UInt32 *idcount) {
  79. struct SubRefTypeIdList list;
  80. UA_UInt32 count;
  81. SLIST_INIT(&list);
  82. // walk the tree
  83. const UA_ReferenceTypeNode *root;
  84. if(UA_Namespace_get(ns, rootReferenceType, (const UA_Node **)&root) != UA_SUCCESS ||
  85. root->nodeClass != UA_NODECLASS_REFERENCETYPE)
  86. return UA_ERROR;
  87. count = walkReferenceTree(ns, root, &list);
  88. UA_Namespace_releaseManagedNode((const UA_Node *)root);
  89. // copy results into an array
  90. UA_alloc((void **)ids, sizeof(UA_NodeId)*count);
  91. for(UA_UInt32 i = 0;i < count;i++) {
  92. struct SubRefTypeId *element = SLIST_FIRST(&list);
  93. UA_NodeId_copy(&element->id, &(*ids)[i]);
  94. SLIST_REMOVE_HEAD(&list, next);
  95. UA_free(element);
  96. }
  97. *idcount = count;
  98. return UA_SUCCESS;
  99. }
  100. /* is this a relevant reference? */
  101. static INLINE UA_Boolean Service_Browse_returnReference(UA_BrowseDescription *browseDescription,
  102. UA_ReferenceNode *reference,
  103. UA_NodeId *relevantRefTypes,
  104. UA_UInt32 relevantRefTypesCount) {
  105. if(reference->isInverse == UA_TRUE &&
  106. browseDescription->browseDirection == UA_BROWSEDIRECTION_FORWARD)
  107. return UA_FALSE;
  108. else if(reference->isInverse == UA_FALSE &&
  109. browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE)
  110. return UA_FALSE;
  111. for(UA_UInt32 i = 0;i < relevantRefTypesCount;i++) {
  112. if(UA_NodeId_equal(&browseDescription->referenceTypeId, &relevantRefTypes[i]) == UA_EQUAL)
  113. return UA_TRUE;
  114. }
  115. return UA_FALSE;
  116. }
  117. /* Return results to a single browsedescription. */
  118. static void Service_Browse_getBrowseResult(UA_Namespace *ns,
  119. UA_BrowseDescription *browseDescription,
  120. UA_UInt32 maxReferences,
  121. UA_BrowseResult *browseResult) {
  122. const UA_Node *node;
  123. UA_NodeId *relevantReferenceTypes;
  124. UA_UInt32 relevantReferenceTypesCount = 0;
  125. if(UA_Namespace_get(ns, &browseDescription->nodeId, &node) != UA_SUCCESS) {
  126. browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
  127. return;
  128. }
  129. // 0 => unlimited references
  130. if(maxReferences == 0)
  131. maxReferences = node->referencesSize;
  132. // discover the relevant subtypes
  133. if(!browseDescription->includeSubtypes ||
  134. findSubReferenceTypes(ns, &browseDescription->referenceTypeId, &relevantReferenceTypes,
  135. &relevantReferenceTypesCount) != UA_SUCCESS) {
  136. UA_alloc((void **)&relevantReferenceTypes, sizeof(UA_NodeId));
  137. UA_NodeId_copy(&browseDescription->referenceTypeId, relevantReferenceTypes);
  138. relevantReferenceTypesCount = 1;
  139. }
  140. /* We do not use a linked list but traverse the nodes references list twice
  141. * (once for counting, once for generating the referencedescriptions). That
  142. * is much faster than using a linked list, since the references are
  143. * allocated in a continuous blob and RAM access is predictible/does not
  144. * miss cache lines so often. TODO: measure with some huge objects! */
  145. UA_UInt32 refs = 0;
  146. for(UA_Int32 i = 0;i < node->referencesSize && refs <= maxReferences;i++) {
  147. if(Service_Browse_returnReference(browseDescription, &node->references[i], relevantReferenceTypes,
  148. relevantReferenceTypesCount))
  149. refs++;
  150. }
  151. // can we return all relevant references at once?
  152. UA_Boolean finished = UA_TRUE;
  153. if(refs > maxReferences) {
  154. refs--;
  155. finished = UA_FALSE;
  156. }
  157. browseResult->referencesSize = refs;
  158. UA_Array_new((void **)&browseResult->references, refs, &UA_.types[UA_REFERENCEDESCRIPTION]);
  159. for(UA_UInt32 i = 0, j = 0;j < refs;i++) {
  160. if(!Service_Browse_returnReference(browseDescription, &node->references[i], relevantReferenceTypes,
  161. relevantReferenceTypesCount))
  162. continue;
  163. if(Service_Browse_getReferenceDescription(ns, &node->references[i], browseDescription->nodeClassMask,
  164. browseDescription->resultMask,
  165. &browseResult->references[j]) != UA_SUCCESS)
  166. browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
  167. j++;
  168. }
  169. if(!finished) {
  170. // Todo. Set the Statuscode and the continuation point.
  171. }
  172. UA_Namespace_releaseManagedNode(node);
  173. UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesCount, &UA_.types[UA_NODEID]);
  174. }
  175. UA_Int32 Service_Browse(UA_Server *server, UA_Session *session,
  176. const UA_BrowseRequest *request, UA_BrowseResponse *response) {
  177. UA_Int32 retval = UA_SUCCESS;
  178. if(server == UA_NULL || session == UA_NULL)
  179. return UA_ERROR;
  180. //TODO request->view not used atm
  181. UA_Array_new((void **)&(response->results), request->nodesToBrowseSize, &UA_.types[UA_BROWSERESULT]);
  182. response->resultsSize = request->nodesToBrowseSize;
  183. for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++) {
  184. UA_Namespace *ns = UA_NULL;
  185. for(UA_UInt32 i = 0;i < server->namespacesSize;i++) {
  186. if(server->namespaces[i].namespaceIndex ==
  187. request->nodesToBrowse[i].nodeId.namespaceIndex) {
  188. ns = server->namespaces[i].namespace;
  189. break;
  190. }
  191. }
  192. if(ns == UA_NULL) {
  193. response->results[i].statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
  194. continue;
  195. }
  196. // Service_Browse_getBrowseResult has no return value. All errors are resolved internally.
  197. Service_Browse_getBrowseResult(ns, &request->nodesToBrowse[i],
  198. request->requestedMaxReferencesPerNode,
  199. &response->results[i]);
  200. }
  201. //TODO fill Diagnostic info array
  202. response->diagnosticInfosSize = 0;
  203. response->diagnosticInfos = UA_NULL;
  204. return retval;
  205. }
  206. UA_Int32 Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
  207. const UA_TranslateBrowsePathsToNodeIdsRequest *request,
  208. UA_TranslateBrowsePathsToNodeIdsResponse *response) {
  209. UA_Int32 retval = UA_SUCCESS;
  210. DBG_VERBOSE(printf("TranslateBrowsePathsToNodeIdsService - %i path(s)", request->browsePathsSize));
  211. // Allocate space for a correct answer
  212. response->resultsSize = request->browsePathsSize;
  213. // _init of the elements is done in Array_new
  214. UA_Array_new((void **)&response->results, request->browsePathsSize, &UA_.types[UA_BROWSEPATHRESULT]);
  215. for(UA_Int32 i = 0;i < request->browsePathsSize;i++) {
  216. //FIXME: implement
  217. response->results[i].statusCode = UA_STATUSCODE_BADNOMATCH;
  218. }
  219. return retval;
  220. }