ua_services_view.c 8.9 KB

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