Procházet zdrojové kódy

method ctt tests pass relates to #602, @jpfr, i will tick off

Stasik0 před 8 roky
rodič
revize
93553be0fa

+ 91 - 0
examples/server.c

@@ -81,6 +81,22 @@ helloWorld(void *methodHandle, const UA_NodeId objectId,
     UA_String_deleteMembers(&greet);
     return UA_STATUSCODE_GOOD;
 }
+
+static UA_StatusCode
+noargMethod (void *methodHandle, const UA_NodeId objectId,
+           size_t inputSize, const UA_Variant *input,
+           size_t outputSize, UA_Variant *output) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+outargMethod (void *methodHandle, const UA_NodeId objectId,
+           size_t inputSize, const UA_Variant *input,
+           size_t outputSize, UA_Variant *output) {
+    UA_Int32 out = 42;
+    UA_Variant_setScalarCopy(output, &out, &UA_TYPES[UA_TYPES_INT32]);
+    return UA_STATUSCODE_GOOD;
+}
 #endif
 
 int main(int argc, char** argv) {
@@ -123,6 +139,7 @@ int main(int argc, char** argv) {
 
     /* Add HelloWorld method to the server */
 #ifdef UA_ENABLE_METHODCALLS
+    /* Method with IO Arguments */
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
@@ -275,6 +292,80 @@ int main(int argc, char** argv) {
     UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("en_US", "Objects");
     UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
 
+#define NOARGID     60000
+#define INARGID     60001
+#define OUTARGID    60002
+#define INOUTARGID  60003
+#ifdef UA_ENABLE_METHODCALLS
+    /* adding some more method nodes to pass CTT */
+    /* Method without arguments */
+    UA_MethodAttributes_init(&addmethodattributes);
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "noarg");
+    addmethodattributes.executable = true;
+    addmethodattributes.userExecutable = true;
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, NOARGID),
+        UA_NODEID_NUMERIC(1, DEMOID),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+        UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
+        &noargMethod, /* callback of the method node */
+        NULL, /* handle passed with the callback */
+        0, NULL, 0, NULL, NULL);
+
+    /* Method with in arguments */
+    UA_MethodAttributes_init(&addmethodattributes);
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "inarg");
+    addmethodattributes.executable = true;
+    addmethodattributes.userExecutable = true;
+
+    UA_Argument_init(&inputArguments);
+    inputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    inputArguments.description = UA_LOCALIZEDTEXT("en_US", "Input");
+    inputArguments.name = UA_STRING("Input");
+    inputArguments.valueRank = -1; //uaexpert will crash if set to 0 ;)
+
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, INARGID),
+        UA_NODEID_NUMERIC(1, DEMOID),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+        UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
+        &noargMethod, /* callback of the method node */
+        NULL, /* handle passed with the callback */
+        1, &inputArguments, 0, NULL, NULL);
+
+    /* Method with out arguments */
+    UA_MethodAttributes_init(&addmethodattributes);
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "outarg");
+    addmethodattributes.executable = true;
+    addmethodattributes.userExecutable = true;
+
+    UA_Argument_init(&outputArguments);
+    outputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    outputArguments.description = UA_LOCALIZEDTEXT("en_US", "Output");
+    outputArguments.name = UA_STRING("Output");
+    outputArguments.valueRank = -1;
+
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, OUTARGID),
+        UA_NODEID_NUMERIC(1, DEMOID),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+        UA_QUALIFIEDNAME(1, "outarg"), addmethodattributes,
+        &outargMethod, /* callback of the method node */
+        NULL, /* handle passed with the callback */
+        0, NULL, 1, &outputArguments, NULL);
+
+    /* Method with inout arguments */
+    UA_MethodAttributes_init(&addmethodattributes);
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "inoutarg");
+    addmethodattributes.executable = true;
+    addmethodattributes.userExecutable = true;
+
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, INOUTARGID),
+        UA_NODEID_NUMERIC(1, DEMOID),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+        UA_QUALIFIEDNAME(1, "inoutarg"), addmethodattributes,
+        &outargMethod, /* callback of the method node */
+        NULL, /* handle passed with the callback */
+        1, &inputArguments, 1, &outputArguments, NULL);
+#endif
+
     /* run server */
     UA_StatusCode retval = UA_Server_run(server, &running); /* run until ctrl-c is received */
     UA_Server_delete(server);

+ 20 - 16
src/server/ua_services_call.c

@@ -171,28 +171,32 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
         return;
 
     /* Verify Input Argument count, types and sizes */
-    const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
-    if(!inputArguments) {
-        result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
-        return;
+    //check inputAgruments only if there are any
+    if(request->inputArgumentsSize > 0){
+        const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
+
+        if(!inputArguments) {
+            result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
+            return;
+        }
+            result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize,
+                                                     request->inputArguments);
+        if(result->statusCode != UA_STATUSCODE_GOOD)
+            return;
     }
-    result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize,
-                                                 request->inputArguments);
-    if(result->statusCode != UA_STATUSCODE_GOOD)
-        return;
 
     /* Allocate the output arguments */
     const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
     if(!outputArguments) {
-        result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
-        return;
-    }
-    result->outputArguments = UA_Array_new(outputArguments->value.variant.value.arrayLength, &UA_TYPES[UA_TYPES_VARIANT]);
-    if(!result->outputArguments) {
-        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-        return;
+        result->outputArgumentsSize=0;
+    }else{
+        result->outputArguments = UA_Array_new(outputArguments->value.variant.value.arrayLength, &UA_TYPES[UA_TYPES_VARIANT]);
+        if(!result->outputArguments) {
+            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+            return;
+        }
+        result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
     }
-    result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
 
 #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
     methodCallSession = session;

+ 49 - 44
src/server/ua_services_nodemanagement.c

@@ -873,52 +873,57 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     parent.nodeId = result.addedNodeId;
 
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-    UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
-    inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0, "InputArguments");
-    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->valueRank = 1;
-    //TODO: 0.3 work item: the addMethodNode API does not have the possibility to set nodeIDs
-    //actually we need to change the signature to pass UA_NS0ID_SERVER_GETMONITOREDITEMS_INPUTARGUMENTS
-    //and UA_NS0ID_SERVER_GETMONITOREDITEMS_OUTPUTARGUMENTS into the function :/
-    if(result.addedNodeId.namespaceIndex == 0 &&
-       result.addedNodeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
-       result.addedNodeId.identifier.numeric == UA_NS0ID_SERVER_GETMONITOREDITEMS){
-        inputArgumentsVariableNode->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS_INPUTARGUMENTS);
+
+    if(inputArgumentsSize > 0){
+        UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
+        inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+        inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0, "InputArguments");
+        inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+        inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+        inputArgumentsVariableNode->valueRank = 1;
+        //TODO: 0.3 work item: the addMethodNode API does not have the possibility to set nodeIDs
+        //actually we need to change the signature to pass UA_NS0ID_SERVER_GETMONITOREDITEMS_INPUTARGUMENTS
+        //and UA_NS0ID_SERVER_GETMONITOREDITEMS_OUTPUTARGUMENTS into the function :/
+        if(result.addedNodeId.namespaceIndex == 0 &&
+           result.addedNodeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
+           result.addedNodeId.identifier.numeric == UA_NS0ID_SERVER_GETMONITOREDITEMS){
+            inputArgumentsVariableNode->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS_INPUTARGUMENTS);
+        }
+        UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
+                                inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+        UA_AddNodesResult inputAddRes;
+        UA_RCU_LOCK();
+        Service_AddNodes_existing(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
+                                  &parent.nodeId, &hasproperty, &UA_NODEID_NULL, NULL, &inputAddRes);
+        UA_RCU_UNLOCK();
+        // todo: check if adding succeeded
+        UA_AddNodesResult_deleteMembers(&inputAddRes);
     }
-    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
-                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    UA_AddNodesResult inputAddRes;
-    UA_RCU_LOCK();
-    Service_AddNodes_existing(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
-                              &parent.nodeId, &hasproperty, &UA_NODEID_NULL, NULL, &inputAddRes);
-    UA_RCU_UNLOCK();
-    // todo: check if adding succeeded
-    UA_AddNodesResult_deleteMembers(&inputAddRes);
-
-    /* create OutputArguments */
-    UA_VariableNode *outputArgumentsVariableNode  = UA_NodeStore_newVariableNode();
-    outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0, "OutputArguments");
-    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->valueRank = 1;
-    //FIXME: comment in line 882
-    if(result.addedNodeId.namespaceIndex == 0 &&
-       result.addedNodeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
-       result.addedNodeId.identifier.numeric == UA_NS0ID_SERVER_GETMONITOREDITEMS){
-        outputArgumentsVariableNode->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS_OUTPUTARGUMENTS);
+
+    if(outputArgumentsSize > 0){
+        /* create OutputArguments */
+        UA_VariableNode *outputArgumentsVariableNode  = UA_NodeStore_newVariableNode();
+        outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+        outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0, "OutputArguments");
+        outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+        outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+        outputArgumentsVariableNode->valueRank = 1;
+        //FIXME: comment in line 882
+        if(result.addedNodeId.namespaceIndex == 0 &&
+           result.addedNodeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
+           result.addedNodeId.identifier.numeric == UA_NS0ID_SERVER_GETMONITOREDITEMS){
+            outputArgumentsVariableNode->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS_OUTPUTARGUMENTS);
+        }
+        UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
+                                outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+        UA_AddNodesResult outputAddRes;
+        UA_RCU_LOCK();
+        Service_AddNodes_existing(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
+                                  &parent.nodeId, &hasproperty, &UA_NODEID_NULL, NULL, &outputAddRes);
+        UA_RCU_UNLOCK();
+        // todo: check if adding succeeded
+        UA_AddNodesResult_deleteMembers(&outputAddRes);
     }
-    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
-                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    UA_AddNodesResult outputAddRes;
-    UA_RCU_LOCK();
-    Service_AddNodes_existing(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
-                              &parent.nodeId, &hasproperty, &UA_NODEID_NULL, NULL, &outputAddRes);
-    UA_RCU_UNLOCK();
-    // todo: check if adding succeeded
-    UA_AddNodesResult_deleteMembers(&outputAddRes);
 
     if(outNewNodeId)
         *outNewNodeId = result.addedNodeId; // don't deleteMember the result