|
@@ -1,36 +1,30 @@
|
|
#include "ua_services.h"
|
|
#include "ua_services.h"
|
|
#include "ua_statuscodes.h"
|
|
#include "ua_statuscodes.h"
|
|
|
|
|
|
-UA_Int32 Service_Browse_getReferenceDescription(Namespace *ns,UA_ReferenceNode* reference, UA_UInt32 nodeClassMask,
|
|
|
|
|
|
+UA_Int32 Service_Browse_getReferenceDescription(Namespace *ns, UA_ReferenceNode* reference, UA_UInt32 nodeClassMask,
|
|
UA_UInt32 resultMask, UA_ReferenceDescription* referenceDescription) {
|
|
UA_UInt32 resultMask, UA_ReferenceDescription* referenceDescription) {
|
|
const UA_Node* foundNode;
|
|
const UA_Node* foundNode;
|
|
Namespace_Entry_Lock *lock;
|
|
Namespace_Entry_Lock *lock;
|
|
- if(Namespace_get(ns,&reference->targetId.nodeId,&foundNode, &lock) != UA_SUCCESS )
|
|
|
|
|
|
+ if(Namespace_get(ns,&reference->targetId.nodeId,&foundNode, &lock) != UA_SUCCESS)
|
|
return UA_ERROR;
|
|
return UA_ERROR;
|
|
|
|
|
|
UA_UInt32 mask = 0;
|
|
UA_UInt32 mask = 0;
|
|
- referenceDescription->resultMask = 0;
|
|
|
|
for (mask = 0x01; mask <= 0x40; mask *= 2) {
|
|
for (mask = 0x01; mask <= 0x40; mask *= 2) {
|
|
switch (mask & (resultMask)) {
|
|
switch (mask & (resultMask)) {
|
|
case UA_BROWSERESULTMASK_REFERENCETYPEID:
|
|
case UA_BROWSERESULTMASK_REFERENCETYPEID:
|
|
UA_NodeId_copy(&reference->referenceTypeId, &referenceDescription->referenceTypeId);
|
|
UA_NodeId_copy(&reference->referenceTypeId, &referenceDescription->referenceTypeId);
|
|
- referenceDescription->resultMask |= UA_BROWSERESULTMASK_REFERENCETYPEID;
|
|
|
|
break;
|
|
break;
|
|
case UA_BROWSERESULTMASK_ISFORWARD:
|
|
case UA_BROWSERESULTMASK_ISFORWARD:
|
|
referenceDescription->isForward = !reference->isInverse;
|
|
referenceDescription->isForward = !reference->isInverse;
|
|
- referenceDescription->resultMask |= UA_BROWSERESULTMASK_ISFORWARD;
|
|
|
|
break;
|
|
break;
|
|
case UA_BROWSERESULTMASK_NODECLASS:
|
|
case UA_BROWSERESULTMASK_NODECLASS:
|
|
UA_NodeClass_copy(&foundNode->nodeClass, &referenceDescription->nodeClass);
|
|
UA_NodeClass_copy(&foundNode->nodeClass, &referenceDescription->nodeClass);
|
|
- referenceDescription->resultMask |= UA_BROWSERESULTMASK_NODECLASS;
|
|
|
|
break;
|
|
break;
|
|
case UA_BROWSERESULTMASK_BROWSENAME:
|
|
case UA_BROWSERESULTMASK_BROWSENAME:
|
|
UA_QualifiedName_copy(&foundNode->browseName, &referenceDescription->browseName);
|
|
UA_QualifiedName_copy(&foundNode->browseName, &referenceDescription->browseName);
|
|
- referenceDescription->resultMask |= UA_BROWSERESULTMASK_BROWSENAME;
|
|
|
|
break;
|
|
break;
|
|
case UA_BROWSERESULTMASK_DISPLAYNAME:
|
|
case UA_BROWSERESULTMASK_DISPLAYNAME:
|
|
UA_LocalizedText_copy(&foundNode->displayName, &referenceDescription->displayName);
|
|
UA_LocalizedText_copy(&foundNode->displayName, &referenceDescription->displayName);
|
|
- referenceDescription->resultMask |= UA_BROWSERESULTMASK_DISPLAYNAME;
|
|
|
|
break;
|
|
break;
|
|
case UA_BROWSERESULTMASK_TYPEDEFINITION:
|
|
case UA_BROWSERESULTMASK_TYPEDEFINITION:
|
|
if (referenceDescription->nodeClass == UA_NODECLASS_OBJECT ||
|
|
if (referenceDescription->nodeClass == UA_NODECLASS_OBJECT ||
|
|
@@ -39,15 +33,16 @@ UA_Int32 Service_Browse_getReferenceDescription(Namespace *ns,UA_ReferenceNode*
|
|
//TODO mockup
|
|
//TODO mockup
|
|
referenceDescription->typeDefinition.serverIndex = 0;
|
|
referenceDescription->typeDefinition.serverIndex = 0;
|
|
referenceDescription->typeDefinition.namespaceUri.length = 0;
|
|
referenceDescription->typeDefinition.namespaceUri.length = 0;
|
|
-
|
|
|
|
- referenceDescription->resultMask |= UA_BROWSERESULTMASK_TYPEDEFINITION;
|
|
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ Namespace_Entry_Lock_release(lock);
|
|
return UA_SUCCESS;
|
|
return UA_SUCCESS;
|
|
}
|
|
}
|
|
-UA_Boolean Service_Browse_returnReference(UA_BrowseDescription *browseDescription, UA_ReferenceNode* reference) {
|
|
|
|
|
|
+
|
|
|
|
+static inline UA_Boolean Service_Browse_returnReference(UA_BrowseDescription *browseDescription, UA_ReferenceNode* reference) {
|
|
UA_Boolean c = UA_FALSE;
|
|
UA_Boolean c = UA_FALSE;
|
|
|
|
|
|
c = c || ((reference->isInverse == UA_TRUE) && (browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE));
|
|
c = c || ((reference->isInverse == UA_TRUE) && (browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE));
|
|
@@ -58,92 +53,98 @@ UA_Boolean Service_Browse_returnReference(UA_BrowseDescription *browseDescriptio
|
|
//TODO subtypes
|
|
//TODO subtypes
|
|
return c;
|
|
return c;
|
|
}
|
|
}
|
|
-UA_Int32 Service_Browse_getBrowseResult(Namespace *ns,UA_BrowseDescription *browseDescription,UA_UInt32 requestedMaxReferencesPerNode, UA_BrowseResult *browseResult) {
|
|
|
|
- UA_Int32 retval = UA_SUCCESS;
|
|
|
|
- const UA_Node* foundNode = UA_NULL;
|
|
|
|
|
|
+
|
|
|
|
+static void Service_Browse_getBrowseResult(Namespace *ns,UA_BrowseDescription *browseDescription,
|
|
|
|
+ UA_UInt32 maxReferences, UA_BrowseResult *browseResult) {
|
|
|
|
+ const UA_Node* node;
|
|
Namespace_Entry_Lock *lock;
|
|
Namespace_Entry_Lock *lock;
|
|
- if(Namespace_get(ns, &browseDescription->nodeId, &foundNode, &lock) == UA_SUCCESS && foundNode)
|
|
|
|
- {
|
|
|
|
- UA_Int32 i = 0;
|
|
|
|
- UA_list_List referenceDescriptionList;
|
|
|
|
- UA_list_init(&referenceDescriptionList);
|
|
|
|
- for(i = 0; i < (foundNode->referencesSize) && ((UA_UInt32)referenceDescriptionList.size < requestedMaxReferencesPerNode); i++)
|
|
|
|
- {
|
|
|
|
- if(Service_Browse_returnReference(browseDescription, &foundNode->references[i]) == UA_TRUE)
|
|
|
|
- {
|
|
|
|
- UA_ReferenceDescription *referenceDescription = UA_NULL;
|
|
|
|
- UA_ReferenceDescription_new(&referenceDescription);
|
|
|
|
-
|
|
|
|
- retval |= Service_Browse_getReferenceDescription(ns, &foundNode->references[i],
|
|
|
|
- browseDescription->nodeClassMask,browseDescription->resultMask,referenceDescription);
|
|
|
|
- if(retval == UA_SUCCESS){
|
|
|
|
- retval |= UA_list_addPayloadToBack(&referenceDescriptionList,referenceDescription);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- //create result array and copy all data from list into it
|
|
|
|
- UA_Array_new((void**) &browseResult->references, referenceDescriptionList.size,
|
|
|
|
- &UA_.types[UA_REFERENCEDESCRIPTION]);
|
|
|
|
-
|
|
|
|
- browseResult->referencesSize = referenceDescriptionList.size;
|
|
|
|
- UA_list_Element *element = referenceDescriptionList.first;
|
|
|
|
- UA_Int32 l = 0;
|
|
|
|
-
|
|
|
|
- for (l = 0; l < referenceDescriptionList.size; l++) {
|
|
|
|
- UA_ReferenceDescription_copy(
|
|
|
|
- (UA_ReferenceDescription*) element->payload,
|
|
|
|
- &browseResult->references[l]);
|
|
|
|
- element = element->next;
|
|
|
|
- }
|
|
|
|
- UA_list_destroy(&referenceDescriptionList,
|
|
|
|
- (UA_list_PayloadVisitor) UA_ReferenceDescription_delete);
|
|
|
|
- return retval;
|
|
|
|
|
|
+
|
|
|
|
+ if(Namespace_get(ns, &browseDescription->nodeId, &node, &lock) != UA_SUCCESS) {
|
|
|
|
+ browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 0 => unlimited references
|
|
|
|
+ if(maxReferences == 0)
|
|
|
|
+ maxReferences = node->referencesSize;
|
|
|
|
+
|
|
|
|
+ /* We do not use a linked list but traverse the nodes references list twice
|
|
|
|
+ * (once for counting, once for generating the referencedescriptions). That
|
|
|
|
+ * is much faster than using a linked list, since the references are
|
|
|
|
+ * allocated in a continuous blob and RAM access is predictible/does not
|
|
|
|
+ * miss cache lines so often. */
|
|
|
|
+ UA_UInt32 refs = 0;
|
|
|
|
+ for(UA_Int32 i=0;i < node->referencesSize && refs <= maxReferences;i++) {
|
|
|
|
+ if(Service_Browse_returnReference(browseDescription, &node->references[i]))
|
|
|
|
+ refs++;
|
|
}
|
|
}
|
|
- return UA_ERROR;
|
|
|
|
|
|
+
|
|
|
|
+ // can we return all relevant references in one go?
|
|
|
|
+ UA_Boolean finished = UA_TRUE;
|
|
|
|
+ if(refs > maxReferences) {
|
|
|
|
+ refs--;
|
|
|
|
+ finished = UA_FALSE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ browseResult->referencesSize = refs;
|
|
|
|
+ UA_Array_new((void**) &browseResult->references, refs, &UA_.types[UA_REFERENCEDESCRIPTION]);
|
|
|
|
+
|
|
|
|
+ for(UA_UInt32 i = 0, j=0; j < refs; i++) {
|
|
|
|
+ if(!Service_Browse_returnReference(browseDescription, &node->references[i]))
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if(Service_Browse_getReferenceDescription(ns, &node->references[i], browseDescription->nodeClassMask,
|
|
|
|
+ browseDescription->resultMask, &browseResult->references[j]) != UA_SUCCESS)
|
|
|
|
+ browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
|
|
|
|
+ j++;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(!finished) {
|
|
|
|
+ // Todo. Set the Statuscode and the continuation point.
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Namespace_Entry_Lock_release(lock);
|
|
}
|
|
}
|
|
|
|
+
|
|
UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response) {
|
|
UA_Int32 Service_Browse(SL_Channel *channel, const UA_BrowseRequest *request, UA_BrowseResponse *response) {
|
|
UA_Int32 retval = UA_SUCCESS;
|
|
UA_Int32 retval = UA_SUCCESS;
|
|
DBG_VERBOSE(UA_NodeId_printf("BrowseService - view=", &request->view.viewId));
|
|
DBG_VERBOSE(UA_NodeId_printf("BrowseService - view=", &request->view.viewId));
|
|
- UA_Int32 i = 0;
|
|
|
|
- Namespace *ns = UA_indexedList_findValue(
|
|
|
|
- channel->session->application->namespaces,
|
|
|
|
- request->nodesToBrowse[i].nodeId.namespace);
|
|
|
|
|
|
+
|
|
//TODO request->view not used atm
|
|
//TODO request->view not used atm
|
|
- if(ns) {
|
|
|
|
- UA_Array_new((void**) &(response->results), request->nodesToBrowseSize,
|
|
|
|
- &UA_.types[UA_BROWSERESULT]);
|
|
|
|
- response->resultsSize = request->nodesToBrowseSize;
|
|
|
|
-
|
|
|
|
- for(i=0; i < request->nodesToBrowseSize; i++) {
|
|
|
|
- retval |= Service_Browse_getBrowseResult(ns,
|
|
|
|
- request->nodesToBrowse,
|
|
|
|
- request->requestedMaxReferencesPerNode,
|
|
|
|
- &response->results[i]);
|
|
|
|
- }
|
|
|
|
|
|
+ UA_Array_new((void**) &(response->results), request->nodesToBrowseSize, &UA_.types[UA_BROWSERESULT]);
|
|
|
|
+ response->resultsSize = request->nodesToBrowseSize;
|
|
|
|
|
|
- response->diagnosticInfosSize = 0;
|
|
|
|
- response->diagnosticInfos = UA_NULL;
|
|
|
|
- //TODO fill Diagnostic info array
|
|
|
|
- return retval;
|
|
|
|
|
|
+ for(UA_Int32 i=0; i < request->nodesToBrowseSize; i++) {
|
|
|
|
+ Namespace *ns = UA_indexedList_findValue(channel->session->application->namespaces,
|
|
|
|
+ request->nodesToBrowse[i].nodeId.namespace);
|
|
|
|
+ if(ns == UA_NULL) {
|
|
|
|
+ response->results[i].statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Service_Browse_getBrowseResult has no return value. All errors are resolved internally.
|
|
|
|
+ Service_Browse_getBrowseResult(ns, &request->nodesToBrowse[i],
|
|
|
|
+ request->requestedMaxReferencesPerNode, &response->results[i]);
|
|
}
|
|
}
|
|
- return UA_ERROR;
|
|
|
|
|
|
+
|
|
|
|
+ //TODO fill Diagnostic info array
|
|
|
|
+ response->diagnosticInfosSize = 0;
|
|
|
|
+ response->diagnosticInfos = UA_NULL;
|
|
|
|
+ return retval;
|
|
}
|
|
}
|
|
|
|
|
|
-UA_Int32 Service_TranslateBrowsePathsToNodeIds(SL_Channel *channel,
|
|
|
|
- const UA_TranslateBrowsePathsToNodeIdsRequest *request,
|
|
|
|
- UA_TranslateBrowsePathsToNodeIdsResponse *response) {
|
|
|
|
|
|
+UA_Int32 Service_TranslateBrowsePathsToNodeIds(SL_Channel *channel, const UA_TranslateBrowsePathsToNodeIdsRequest *request,
|
|
|
|
+ UA_TranslateBrowsePathsToNodeIdsResponse *response) {
|
|
UA_Int32 retval = UA_SUCCESS;
|
|
UA_Int32 retval = UA_SUCCESS;
|
|
-
|
|
|
|
DBG_VERBOSE(printf("TranslateBrowsePathsToNodeIdsService - %i path(s)", request->browsePathsSize));
|
|
DBG_VERBOSE(printf("TranslateBrowsePathsToNodeIdsService - %i path(s)", request->browsePathsSize));
|
|
-//Allocate space for a correct answer
|
|
|
|
- UA_Array_new((void**) &response->results, request->browsePathsSize,
|
|
|
|
- &UA_.types[UA_BROWSEPATHRESULT]);
|
|
|
|
|
|
|
|
|
|
+ // Allocate space for a correct answer
|
|
response->resultsSize = request->browsePathsSize;
|
|
response->resultsSize = request->browsePathsSize;
|
|
|
|
+ // _init of the elements is done in Array_new
|
|
|
|
+ UA_Array_new((void**) &response->results, request->browsePathsSize, &UA_.types[UA_BROWSEPATHRESULT]);
|
|
|
|
|
|
for (UA_Int32 i = 0; i < request->browsePathsSize; i++) {
|
|
for (UA_Int32 i = 0; i < request->browsePathsSize; i++) {
|
|
- UA_BrowsePathResult_init(&response->results[i]);
|
|
|
|
-//FIXME: implement
|
|
|
|
|
|
+ //FIXME: implement
|
|
response->results[i].statusCode = UA_STATUSCODE_BADNOMATCH;
|
|
response->results[i].statusCode = UA_STATUSCODE_BADNOMATCH;
|
|
}
|
|
}
|
|
|
|
|