소스 검색

Merge pull request #613 from open62541/fixes_to_call_service

fixes for call service
Julius Pfrommer 8 년 전
부모
커밋
c58a05d207
2개의 변경된 파일64개의 추가작업 그리고 13개의 파일을 삭제
  1. 1 1
      examples/server_method.c
  2. 63 12
      src/server/ua_services_call.c

+ 1 - 1
examples/server_method.c

@@ -103,7 +103,7 @@ int main(int argc, char** argv) {
     helloAttr.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                             UA_QUALIFIEDNAME(1, "hello world"), 
                             helloAttr, &helloWorldMethod, NULL,
                             1, &inputArguments, 1, &outputArguments, NULL);

+ 63 - 12
src/server/ua_services_call.c

@@ -25,9 +25,51 @@ getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
 }
 
 static UA_StatusCode
-satisfySignature(const UA_Variant *var, const UA_Argument *arg) {
-    if(!UA_NodeId_equal(&var->type->typeId, &arg->dataType) )
-        return UA_STATUSCODE_BADINVALIDARGUMENT;
+isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode, const UA_NodeId *nodeToFind,
+             const UA_NodeId *referenceTypeId, size_t *maxDepth, UA_Boolean *found){
+    *maxDepth = *maxDepth-1;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    const UA_Node *node = UA_NodeStore_get(ns,rootNode);
+    if(!node)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    *found = false;
+    for(size_t i=0; i<node->referencesSize;i++) {
+        if(UA_NodeId_equal(&node->references[i].referenceTypeId, referenceTypeId) &&
+           node->references[i].isInverse == false) {
+           if(UA_NodeId_equal(&node->references[i].targetId.nodeId, nodeToFind)) {
+               *found = true;
+               return UA_STATUSCODE_GOOD;
+           }
+           if(*maxDepth > 0) {
+               retval = isNodeInTree(ns, &node->references[i].targetId.nodeId, nodeToFind,
+                                     referenceTypeId, maxDepth, found);
+               if(*found)
+                   break;
+           }
+        }
+    }
+    *maxDepth = *maxDepth+1;
+    return retval;
+}
+
+static UA_StatusCode
+satisfySignature(UA_Server *server, const UA_Variant *var, const UA_Argument *arg) {
+    if(!UA_NodeId_equal(&var->type->typeId, &arg->dataType)){
+        if(!UA_NodeId_equal(&var->type->typeId, &UA_TYPES[UA_TYPES_INT32].typeId))
+            return UA_STATUSCODE_BADINVALIDARGUMENT;
+
+        //enumerations are encoded as int32 -> if provided var is integer, check if arg is an enumeration type
+        UA_NodeId ENUMERATION_NODEID_NS0 = UA_NODEID_NUMERIC(0,29);
+        UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
+        UA_Boolean found = false;
+        size_t maxDepth = 1;
+        UA_StatusCode retval = isNodeInTree(server->nodestore, &ENUMERATION_NODEID_NS0, &arg->dataType, &hasSubTypeNodeId, &maxDepth, &found);
+        if(retval != UA_STATUSCODE_GOOD)
+            return UA_STATUSCODE_BADINTERNALERROR;
+        if(!found)
+            return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
 
     // Note: The namespace compiler will compile nodes with their actual array dimensions
     // Todo: Check if this is standard conform for scalars
@@ -83,7 +125,7 @@ satisfySignature(const UA_Variant *var, const UA_Argument *arg) {
 }
 
 static UA_StatusCode
-argConformsToDefinition(const UA_VariableNode *argRequirements, size_t argsSize, const UA_Variant *args) {
+argConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirements, size_t argsSize, const UA_Variant *args) {
     if(argRequirements->value.variant.value.type != &UA_TYPES[UA_TYPES_ARGUMENT])
         return UA_STATUSCODE_BADINTERNALERROR;
     UA_Argument *argReqs = (UA_Argument*)argRequirements->value.variant.value.data;
@@ -99,7 +141,7 @@ argConformsToDefinition(const UA_VariableNode *argRequirements, size_t argsSize,
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(size_t i = 0; i < argReqsSize; i++)
-        retval |= satisfySignature(&args[i], &argReqs[i]);
+        retval |= satisfySignature(server, &args[i], &argReqs[i]);
     return retval;
 }
 
@@ -134,15 +176,26 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
     // Object must have a hasComponent reference (or any inherited referenceType from sayd reference)
     // to be valid for a methodCall...
     result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
+    UA_Boolean found = false;
+    size_t maxDepth = 10;
+    UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
+    UA_NodeId hasComponentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASCOMPONENT);
     for(size_t i = 0; i < withObject->referencesSize; i++) {
-        if(withObject->references[i].referenceTypeId.identifier.numeric == UA_NS0ID_HASCOMPONENT) {
-            // FIXME: Not checking any subtypes of HasComponent at the moment
-            if(UA_NodeId_equal(&withObject->references[i].targetId.nodeId, &methodCalled->nodeId)) {
+        if(UA_NodeId_equal(&withObject->references[i].targetId.nodeId, &methodCalled->nodeId)) {
+            if(UA_NodeId_equal(&withObject->references[i].referenceTypeId, &hasComponentNodeId)){
+                result->statusCode = UA_STATUSCODE_GOOD;
+                break;
+            }
+            UA_StatusCode retval = isNodeInTree(server->nodestore, &hasComponentNodeId, &withObject->references[i].referenceTypeId,
+                                                &hasSubTypeNodeId, &maxDepth, &found);
+            if(retval == UA_STATUSCODE_GOOD && found){
                 result->statusCode = UA_STATUSCODE_GOOD;
                 break;
             }
+            return;
         }
     }
+
     if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
 
@@ -156,7 +209,7 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
     const UA_VariableNode *inputArguments;
     inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
     if(inputArguments) {
-        result->statusCode = argConformsToDefinition(inputArguments, request->inputArgumentsSize,
+        result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize,
                                                      request->inputArguments);
         if(result->statusCode != UA_STATUSCODE_GOOD)
             return;
@@ -186,7 +239,6 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
         result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
     /* TODO: Verify Output Argument count, types and sizes */
 }
-
 void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,
                   UA_CallResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing CallRequest");
@@ -195,8 +247,7 @@ void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *
         return;
     }
 
-    response->results = UA_Array_new(request->methodsToCallSize,
-                                     &UA_TYPES[UA_TYPES_CALLMETHODRESULT]);
+    response->results = UA_Array_new(request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT]);
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;