ua_services_view.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. Namespace_Entry_Lock *lock;
  7. if(Namespace_get(ns,&reference->targetId.nodeId,&foundNode, &lock) != 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. Namespace_Entry_Lock_release(lock);
  46. return UA_SUCCESS;
  47. }
  48. /* singly-linked list */
  49. struct SubRefTypeId {
  50. UA_NodeId id;
  51. UA_SLIST_ENTRY(SubRefTypeId) next;
  52. };
  53. UA_SLIST_HEAD(SubRefTypeIdList, SubRefTypeId);
  54. UA_UInt32 walkReferenceTree(Namespace *ns, UA_ReferenceTypeNode *current, struct SubRefTypeIdList *list) {
  55. // insert the current referencetype
  56. struct SubRefTypeId *element;
  57. UA_alloc((void**)&element, sizeof(struct SubRefTypeId));
  58. element->id = current->nodeId;
  59. UA_SLIST_INSERT_HEAD(list, element, next);
  60. UA_UInt32 count = 1; // the current element
  61. // walk the tree
  62. for(UA_Int32 i = 0;i < current->referencesSize;i++) {
  63. if(current->references[i].referenceTypeId.identifier.numeric == 45 /* HasSubtype */ &&
  64. current->references[i].isInverse == UA_FALSE) {
  65. const UA_Node *node;
  66. Namespace_Entry_Lock *lock;
  67. if(Namespace_get(ns, &current->references[i].targetId.nodeId, &node, &lock) == UA_SUCCESS &&
  68. node->nodeClass == UA_NODECLASS_REFERENCETYPE) {
  69. count += walkReferenceTree(ns,(UA_ReferenceTypeNode*)node, list);
  70. Namespace_Entry_Lock_release(lock);
  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(Namespace *ns, UA_NodeId *rootReferenceType, UA_NodeId **ids, UA_UInt32 *idcount) {
  78. struct SubRefTypeIdList list;
  79. UA_SLIST_INIT(&list);
  80. // walk the tree
  81. UA_ReferenceTypeNode *root;
  82. Namespace_Entry_Lock *lock;
  83. if(Namespace_get(ns, rootReferenceType, (const UA_Node**)&root, &lock) != UA_SUCCESS ||
  84. root->nodeClass != UA_NODECLASS_REFERENCETYPE)
  85. return UA_ERROR;
  86. UA_UInt32 count = walkReferenceTree(ns, root, &list);
  87. Namespace_Entry_Lock_release(lock);
  88. // copy results into an array
  89. UA_alloc((void**) ids, sizeof(UA_NodeId)*count);
  90. for(UA_UInt32 i = 0; i < count;i++) {
  91. struct SubRefTypeId *element = UA_SLIST_FIRST(&list);
  92. UA_NodeId_copy(&element->id, &(*ids)[i]);
  93. UA_SLIST_REMOVE_HEAD(&list, next);
  94. UA_free(element);
  95. }
  96. *idcount = count;
  97. return UA_SUCCESS;
  98. }
  99. /* is this a relevant reference? */
  100. static inline UA_Boolean Service_Browse_returnReference(UA_BrowseDescription *browseDescription, UA_ReferenceNode* reference,
  101. UA_NodeId *relevantRefTypes, UA_UInt32 relevantRefTypesCount) {
  102. if (reference->isInverse == UA_TRUE && browseDescription->browseDirection == UA_BROWSEDIRECTION_FORWARD)
  103. return UA_FALSE;
  104. else if (reference->isInverse == UA_FALSE && browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE)
  105. return UA_FALSE;
  106. for(UA_UInt32 i = 0; i<relevantRefTypesCount;i++) {
  107. if(UA_NodeId_equal(&browseDescription->referenceTypeId, &relevantRefTypes[i]) == UA_EQUAL)
  108. return UA_TRUE;
  109. }
  110. return UA_FALSE;
  111. }
  112. /* Return results to a single browsedescription. */
  113. static void Service_Browse_getBrowseResult(Namespace *ns, UA_BrowseDescription *browseDescription,
  114. UA_UInt32 maxReferences, UA_BrowseResult *browseResult) {
  115. const UA_Node* node;
  116. Namespace_Entry_Lock *lock;
  117. if(Namespace_get(ns, &browseDescription->nodeId, &node, &lock) != UA_SUCCESS) {
  118. browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
  119. return;
  120. }
  121. // 0 => unlimited references
  122. if(maxReferences == 0)
  123. maxReferences = node->referencesSize;
  124. // discover the relevant subtypes
  125. UA_NodeId *relevantReferenceTypes;
  126. UA_UInt32 relevantReferenceTypesCount;
  127. if(!browseDescription->includeSubtypes ||
  128. findSubReferenceTypes(ns, &browseDescription->referenceTypeId, &relevantReferenceTypes, &relevantReferenceTypesCount) != UA_SUCCESS) {
  129. UA_alloc((void**)&relevantReferenceTypes, sizeof(UA_NodeId));
  130. UA_NodeId_copy(&browseDescription->referenceTypeId, relevantReferenceTypes);
  131. relevantReferenceTypesCount = 1;
  132. }
  133. /* We do not use a linked list but traverse the nodes references list twice
  134. * (once for counting, once for generating the referencedescriptions). That
  135. * is much faster than using a linked list, since the references are
  136. * allocated in a continuous blob and RAM access is predictible/does not
  137. * miss cache lines so often. TODO: measure with some huge objects! */
  138. UA_UInt32 refs = 0;
  139. for(UA_Int32 i=0;i < node->referencesSize && refs <= maxReferences;i++) {
  140. if(Service_Browse_returnReference(browseDescription, &node->references[i], relevantReferenceTypes, relevantReferenceTypesCount))
  141. refs++;
  142. }
  143. // can we return all relevant references at once?
  144. UA_Boolean finished = UA_TRUE;
  145. if(refs > maxReferences) {
  146. refs--;
  147. finished = UA_FALSE;
  148. }
  149. browseResult->referencesSize = refs;
  150. UA_Array_new((void**) &browseResult->references, refs, &UA_.types[UA_REFERENCEDESCRIPTION]);
  151. for(UA_UInt32 i = 0, j=0; j < refs; i++) {
  152. if(!Service_Browse_returnReference(browseDescription, &node->references[i], relevantReferenceTypes, relevantReferenceTypesCount))
  153. continue;
  154. if(Service_Browse_getReferenceDescription(ns, &node->references[i], browseDescription->nodeClassMask,
  155. browseDescription->resultMask, &browseResult->references[j]) != UA_SUCCESS)
  156. browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
  157. j++;
  158. }
  159. if(!finished) {
  160. // Todo. Set the Statuscode and the continuation point.
  161. }
  162. Namespace_Entry_Lock_release(lock);
  163. UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesCount, &UA_.types[UA_NODEID]);
  164. }
  165. UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response) {
  166. UA_Int32 retval = UA_SUCCESS;
  167. DBG_VERBOSE(UA_NodeId_printf("BrowseService - view=", &request->view.viewId));
  168. //TODO request->view not used atm
  169. UA_Array_new((void**) &(response->results), request->nodesToBrowseSize, &UA_.types[UA_BROWSERESULT]);
  170. response->resultsSize = request->nodesToBrowseSize;
  171. for(UA_Int32 i=0; i < request->nodesToBrowseSize; i++) {
  172. Namespace *ns = UA_indexedList_findValue(channel->session->application->namespaces,
  173. request->nodesToBrowse[i].nodeId.namespace);
  174. if(ns == UA_NULL) {
  175. response->results[i].statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
  176. continue;
  177. }
  178. // Service_Browse_getBrowseResult has no return value. All errors are resolved internally.
  179. Service_Browse_getBrowseResult(ns, &request->nodesToBrowse[i],
  180. request->requestedMaxReferencesPerNode, &response->results[i]);
  181. }
  182. //TODO fill Diagnostic info array
  183. response->diagnosticInfosSize = 0;
  184. response->diagnosticInfos = UA_NULL;
  185. return retval;
  186. }
  187. UA_Int32 Service_TranslateBrowsePathsToNodeIds(SL_Channel *channel, const UA_TranslateBrowsePathsToNodeIdsRequest *request,
  188. UA_TranslateBrowsePathsToNodeIdsResponse *response) {
  189. UA_Int32 retval = UA_SUCCESS;
  190. DBG_VERBOSE(printf("TranslateBrowsePathsToNodeIdsService - %i path(s)", request->browsePathsSize));
  191. // Allocate space for a correct answer
  192. response->resultsSize = request->browsePathsSize;
  193. // _init of the elements is done in Array_new
  194. UA_Array_new((void**) &response->results, request->browsePathsSize, &UA_.types[UA_BROWSEPATHRESULT]);
  195. for (UA_Int32 i = 0; i < request->browsePathsSize; i++) {
  196. //FIXME: implement
  197. response->results[i].statusCode = UA_STATUSCODE_BADNOMATCH;
  198. }
  199. return retval;
  200. }