123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- #include "ua_server_internal.h"
- #include "ua_services.h"
- #include "ua_statuscodes.h"
- #include "ua_nodestore.h"
- #include "ua_util.h"
- /* Releases the current node, even if it was supplied as an argument. */
- static UA_StatusCode fillReferenceDescription(UA_NodeStore *ns, const UA_Node *currentNode, UA_ReferenceNode *reference,
- UA_UInt32 resultMask, UA_ReferenceDescription *referenceDescription) {
- UA_StatusCode retval = UA_STATUSCODE_GOOD;
- UA_ReferenceDescription_init(referenceDescription);
- retval |= UA_NodeId_copy(¤tNode->nodeId, &referenceDescription->nodeId.nodeId);
- //TODO: ExpandedNodeId is mocked up
- referenceDescription->nodeId.serverIndex = 0;
- referenceDescription->nodeId.namespaceUri.length = -1;
- if(resultMask & UA_BROWSERESULTMASK_REFERENCETYPEID)
- retval |= UA_NodeId_copy(&reference->referenceTypeId, &referenceDescription->referenceTypeId);
- if(resultMask & UA_BROWSERESULTMASK_ISFORWARD)
- referenceDescription->isForward = !reference->isInverse;
- if(resultMask & UA_BROWSERESULTMASK_NODECLASS)
- retval |= UA_NodeClass_copy(¤tNode->nodeClass, &referenceDescription->nodeClass);
- if(resultMask & UA_BROWSERESULTMASK_BROWSENAME)
- retval |= UA_QualifiedName_copy(¤tNode->browseName, &referenceDescription->browseName);
- if(resultMask & UA_BROWSERESULTMASK_DISPLAYNAME)
- retval |= UA_LocalizedText_copy(¤tNode->displayName, &referenceDescription->displayName);
- if(resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION ) {
- for(UA_Int32 i = 0;i < currentNode->referencesSize;i++) {
- UA_ReferenceNode *ref = ¤tNode->references[i];
- if(ref->referenceTypeId.identifier.numeric == 40 /* hastypedefinition */) {
- retval |= UA_ExpandedNodeId_copy(&ref->targetId, &referenceDescription->typeDefinition);
- break;
- }
- }
- }
- if(currentNode)
- UA_NodeStore_release(currentNode);
- if(retval)
- UA_ReferenceDescription_deleteMembers(referenceDescription);
- return retval;
- }
- /* Tests if the node is relevant to the browse request and shall be returned. If
- so, it is retrieved from the Nodestore. If not, null is returned. */
- static const UA_Node *
- getRelevantTargetNode(UA_NodeStore *ns, const UA_BrowseDescription *browseDescription, UA_Boolean returnAll,
- UA_ReferenceNode *reference, UA_NodeId *relevantRefTypes, UA_UInt32 relevantRefTypesCount) {
- if(reference->isInverse == UA_TRUE && browseDescription->browseDirection == UA_BROWSEDIRECTION_FORWARD)
- return UA_NULL;
- else if(reference->isInverse == UA_FALSE && browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE)
- return UA_NULL;
- UA_Boolean isRelevant = returnAll;
- if(!isRelevant) {
- for(UA_UInt32 i = 0;i < relevantRefTypesCount;i++) {
- if(UA_NodeId_equal(&reference->referenceTypeId, &relevantRefTypes[i]))
- isRelevant = UA_TRUE;
- }
- if(!isRelevant)
- return UA_NULL;
- }
- const UA_Node *node = UA_NodeStore_get(ns, &reference->targetId.nodeId);
- if(!node)
- return UA_NULL;
- if(browseDescription->nodeClassMask != 0 && (node->nodeClass & browseDescription->nodeClassMask) == 0) {
- UA_NodeStore_release(node);
- return UA_NULL;
- }
- return node;
- }
- /* We do not search across namespaces so far. The id of the root-referencetype
- is returned in the array also. */
- static UA_StatusCode findRelevantReferenceTypes(UA_NodeStore *ns, const UA_NodeId *rootReferenceType,
- UA_NodeId **referenceTypes, UA_UInt32 *referenceTypesSize) {
- /* The references form a tree. We walk the tree by adding new nodes to the end of the array. */
- UA_UInt32 currentIndex = 0;
- UA_UInt32 currentLastIndex = 0;
- UA_UInt32 currentArraySize = 20; // should be more than enough. if not, increase the array size.
- UA_NodeId *typeArray = UA_malloc(sizeof(UA_NodeId) * currentArraySize);
- if(!typeArray)
- return UA_STATUSCODE_BADOUTOFMEMORY;
- UA_StatusCode retval = UA_STATUSCODE_GOOD;
- retval |= UA_NodeId_copy(rootReferenceType, &typeArray[0]);
- if(retval) {
- UA_free(typeArray);
- return UA_STATUSCODE_BADOUTOFMEMORY;
- }
-
- do {
- const UA_ReferenceTypeNode *node =
- (const UA_ReferenceTypeNode *)UA_NodeStore_get(ns, &typeArray[currentIndex]);
- if(!node)
- break;
- // subtypes of referencestypes are always referencestypes?
- if(node->nodeClass != UA_NODECLASS_REFERENCETYPE)
- continue;
- // Find subtypes of the current referencetype
- for(UA_Int32 i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; i++) {
- if(node->references[i].referenceTypeId.identifier.numeric != 45 /* HasSubtype */ ||
- node->references[i].isInverse == UA_TRUE)
- continue;
- if(currentLastIndex + 1 >= currentArraySize) {
- // we need to resize the array
- UA_NodeId *newArray = UA_malloc(sizeof(UA_NodeId) * currentArraySize * 2);
- if(newArray) {
- UA_memcpy(newArray, typeArray, sizeof(UA_NodeId) * currentArraySize);
- currentArraySize *= 2;
- UA_free(typeArray);
- typeArray = newArray;
- } else {
- retval = UA_STATUSCODE_BADOUTOFMEMORY;
- break;
- }
- }
- // ok, we have space to add the new referencetype.
- retval |= UA_NodeId_copy(&node->references[i].targetId.nodeId, &typeArray[++currentLastIndex]);
- if(retval)
- currentLastIndex--; // undo if we need to delete the typeArray
- }
- UA_NodeStore_release((const UA_Node*)node);
- } while(++currentIndex <= currentLastIndex && retval == UA_STATUSCODE_GOOD);
- if(retval)
- UA_Array_delete(typeArray, &UA_TYPES[UA_TYPES_NODEID], currentLastIndex);
- else {
- *referenceTypes = typeArray;
- *referenceTypesSize = currentLastIndex + 1;
- }
-
- return retval;
- }
- /* Results for a single browsedescription. */
- static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browseDescription,
- UA_UInt32 maxReferences, UA_BrowseResult *browseResult) {
- UA_UInt32 relevantReferenceTypesSize = 0;
- UA_NodeId *relevantReferenceTypes = UA_NULL;
- // if the referencetype is null, all referencetypes are returned
- UA_Boolean returnAll = UA_NodeId_isNull(&browseDescription->referenceTypeId);
- if(!returnAll) {
- if(browseDescription->includeSubtypes) {
- browseResult->statusCode = findRelevantReferenceTypes(ns, &browseDescription->referenceTypeId,
- &relevantReferenceTypes,
- &relevantReferenceTypesSize);
- if(browseResult->statusCode != UA_STATUSCODE_GOOD)
- return;
- } else {
- relevantReferenceTypes = UA_NodeId_new();
- UA_NodeId_copy(&browseDescription->referenceTypeId, relevantReferenceTypes);
- relevantReferenceTypesSize = 1;
- }
- }
- const UA_Node *parentNode = UA_NodeStore_get(ns, &browseDescription->nodeId);
- if(!parentNode) {
- browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
- if(!returnAll)
- UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
- return;
- }
- maxReferences = parentNode->referencesSize;
- // 0 => unlimited references
- if(maxReferences <= 0 || maxReferences > UA_INT32_MAX ||
- (UA_Int32)maxReferences > parentNode->referencesSize) {
- if(parentNode->referencesSize < 0)
- maxReferences = 0;
- else
- maxReferences = parentNode->referencesSize;
- }
- /* We allocate an array that is probably too big. But since most systems
- have more than enough memory, this has zero impact on speed and
- performance. Call Array_delete with the actual content size! */
- browseResult->references = UA_malloc(sizeof(UA_ReferenceDescription) * maxReferences);
- if(!browseResult->references) {
- browseResult->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
- } else {
- UA_UInt32 currentRefs = 0;
- for(UA_Int32 i = 0;i < parentNode->referencesSize && currentRefs < maxReferences;i++) {
- // 1) Is the node relevant? If yes, the node is retrieved from the nodestore.
- const UA_Node *currentNode = getRelevantTargetNode(ns, browseDescription, returnAll,
- &parentNode->references[i],
- relevantReferenceTypes,
- relevantReferenceTypesSize);
- if(!currentNode)
- continue;
- // 2) Fill the reference description. This also releases the current node.
- if(fillReferenceDescription(ns, currentNode, &parentNode->references[i],
- browseDescription->resultMask,
- &browseResult->references[currentRefs]) != UA_STATUSCODE_GOOD) {
- UA_Array_delete(browseResult->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], currentRefs);
- currentRefs = 0;
- browseResult->references = UA_NULL;
- browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
- break;
- }
- currentRefs++;
- }
- if(currentRefs != 0)
- browseResult->referencesSize = currentRefs;
- else {
- UA_free(browseResult->references);
- browseResult->references = UA_NULL;
- }
- }
- UA_NodeStore_release(parentNode);
- if(!returnAll)
- UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
- }
- void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
- UA_BrowseResponse *response) {
- if(request->nodesToBrowseSize <= 0) {
- response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
- return;
- }
- response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], request->nodesToBrowseSize);
- if(!response->results) {
- response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
- return;
- }
- /* ### Begin External Namespaces */
- UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToBrowseSize);
- UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * request->nodesToBrowseSize);
- UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToBrowseSize);
- for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
- UA_UInt32 indexSize = 0;
- for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++) {
- if(request->nodesToBrowse[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
- continue;
- isExternal[i] = UA_TRUE;
- indices[indexSize] = i;
- indexSize++;
- }
- if(indexSize == 0)
- continue;
- UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
- ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse,
- indices, indexSize, request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
- }
- /* ### End External Namespaces */
- response->resultsSize = request->nodesToBrowseSize;
- for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++){
- if(!isExternal[i]) {
- getBrowseResult(server->nodestore, &request->nodesToBrowse[i],
- request->requestedMaxReferencesPerNode, &response->results[i]);
- }
- }
- }
- void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
- const UA_TranslateBrowsePathsToNodeIdsRequest *request,
- UA_TranslateBrowsePathsToNodeIdsResponse *response) {
- if(request->browsePathsSize <= 0) {
- response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
- return;
- }
- response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSEPATHRESULT], request->browsePathsSize);
- if(!response->results) {
- response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
- return;
- }
- response->resultsSize = request->browsePathsSize;
- for(UA_Int32 i = 0;i < response->resultsSize;i++)
- response->results[i].statusCode = UA_STATUSCODE_BADNOMATCH; //FIXME: implement
- }
|