|
@@ -25,83 +25,8 @@ getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
|
|
|
}
|
|
|
|
|
|
static UA_StatusCode
|
|
|
-satisfySignature(UA_Server *server, const UA_Variant *var, const UA_Argument *arg) {
|
|
|
- if(var == NULL || var->type == NULL)
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
-
|
|
|
- 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;
|
|
|
-
|
|
|
-
|
|
|
- UA_NodeId enumerationNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ENUMERATION);
|
|
|
- UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
|
|
|
- UA_Boolean found = false;
|
|
|
- UA_StatusCode retval = isNodeInTree(server->nodestore, &arg->dataType, &enumerationNodeId, &hasSubTypeNodeId, 1, 1, &found);
|
|
|
- if(retval != UA_STATUSCODE_GOOD)
|
|
|
- return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
- if(!found)
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if(arg->arrayDimensionsSize > 0 && var->arrayDimensionsSize > 0)
|
|
|
- if(var->arrayDimensionsSize != arg->arrayDimensionsSize)
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
-
|
|
|
- UA_Int32 *varDims = var->arrayDimensions;
|
|
|
- size_t varDimsSize = var->arrayDimensionsSize;
|
|
|
- UA_Boolean scalar = UA_Variant_isScalar(var);
|
|
|
-
|
|
|
-
|
|
|
- UA_Int32 fakeDims;
|
|
|
- if(!scalar && !varDims) {
|
|
|
- fakeDims = (UA_Int32)var->arrayLength;
|
|
|
- varDims = &fakeDims;
|
|
|
- varDimsSize = 1;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- * n >= 1: the value is an array with the specified number of dimens*ions.
|
|
|
- * n = 0: the value is an array with one or more dimensions.
|
|
|
- * n = -1: the value is a scalar.
|
|
|
- * n = -2: the value can be a scalar or an array with any number of dimensions.
|
|
|
- * n = -3: the value can be a scalar or a one dimensional array. */
|
|
|
- switch(arg->valueRank) {
|
|
|
- case -3:
|
|
|
- if(varDimsSize > 1)
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
- break;
|
|
|
- case -2:
|
|
|
- break;
|
|
|
- case -1:
|
|
|
- if(!scalar)
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
- break;
|
|
|
- case 0:
|
|
|
- if(scalar || !varDims)
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
- break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- if(arg->arrayDimensionsSize > 0) {
|
|
|
- if(arg->arrayDimensionsSize != varDimsSize)
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
- for(size_t i = 0; i < varDimsSize; i++) {
|
|
|
-
|
|
|
- if((UA_Int32)arg->arrayDimensions[i]!=0 && (UA_Int32)arg->arrayDimensions[i] != varDims[i])
|
|
|
- return UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
- }
|
|
|
- }
|
|
|
- return UA_STATUSCODE_GOOD;
|
|
|
-}
|
|
|
-
|
|
|
-static UA_StatusCode
|
|
|
-argConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirements, size_t argsSize, const UA_Variant *args) {
|
|
|
+argumentsConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirements,
|
|
|
+ size_t argsSize, const UA_Variant *args) {
|
|
|
if(argRequirements->value.data.value.value.type != &UA_TYPES[UA_TYPES_ARGUMENT])
|
|
|
return UA_STATUSCODE_BADINTERNALERROR;
|
|
|
UA_Argument *argReqs = (UA_Argument*)argRequirements->value.data.value.value.data;
|
|
@@ -117,14 +42,18 @@ argConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirement
|
|
|
|
|
|
UA_StatusCode retval = UA_STATUSCODE_GOOD;
|
|
|
for(size_t i = 0; i < argReqsSize; i++)
|
|
|
- retval |= satisfySignature(server, &args[i], &argReqs[i]);
|
|
|
+ retval |= UA_Variant_matchVariableDefinition(server, &argReqs[i].dataType,
|
|
|
+ argReqs[i].valueRank,
|
|
|
+ argReqs[i].arrayDimensionsSize,
|
|
|
+ argReqs[i].arrayDimensions,
|
|
|
+ &args[i], NULL, NULL);
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
void
|
|
|
-Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *request,
|
|
|
+Service_Call_single(UA_Server *server, UA_Session *session,
|
|
|
+ const UA_CallMethodRequest *request,
|
|
|
UA_CallMethodResult *result) {
|
|
|
-
|
|
|
|
|
|
const UA_MethodNode *methodCalled =
|
|
|
(const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
|
|
@@ -153,47 +82,52 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+ * subtype of hasComponent reference to the method node. Therefore, check
|
|
|
+ * every reference between the parent object and the method node if there is
|
|
|
+ * a hasComponent (or subtype) reference */
|
|
|
UA_Boolean found = false;
|
|
|
UA_NodeId hasComponentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASCOMPONENT);
|
|
|
UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
|
|
|
- for(size_t i=0;i<methodCalled->referencesSize;i++){
|
|
|
- if (methodCalled->references[i].isInverse && UA_NodeId_equal(&methodCalled->references[i].targetId.nodeId,&withObject->nodeId)){
|
|
|
+ for(size_t i = 0; i < methodCalled->referencesSize; i++) {
|
|
|
+ if(methodCalled->references[i].isInverse &&
|
|
|
+ UA_NodeId_equal(&methodCalled->references[i].targetId.nodeId,&withObject->nodeId)) {
|
|
|
|
|
|
- isNodeInTree(server->nodestore, &methodCalled->references[i].referenceTypeId, &hasComponentNodeId,
|
|
|
- &hasSubTypeNodeId, 1, 1, &found);
|
|
|
- if(found){
|
|
|
+ isNodeInTree(server->nodestore, &methodCalled->references[i].referenceTypeId,
|
|
|
+ &hasComponentNodeId, &hasSubTypeNodeId, 1, 1, &found);
|
|
|
+ if(found)
|
|
|
break;
|
|
|
- }
|
|
|
}
|
|
|
}
|
|
|
- if(!found)
|
|
|
+ if(!found) {
|
|
|
result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
|
|
|
- if(result->statusCode != UA_STATUSCODE_GOOD)
|
|
|
return;
|
|
|
+ }
|
|
|
|
|
|
|
|
|
-
|
|
|
- if(request->inputArgumentsSize > 0){
|
|
|
- const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
|
|
|
+ const UA_VariableNode *inputArguments =
|
|
|
+ getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
|
|
|
|
|
|
- if(!inputArguments) {
|
|
|
+ if(!inputArguments) {
|
|
|
+ if(request->inputArgumentsSize > 0) {
|
|
|
result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
|
|
|
return;
|
|
|
}
|
|
|
- result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize,
|
|
|
- request->inputArguments);
|
|
|
+ } else {
|
|
|
+ result->statusCode = argumentsConformsToDefinition(server, inputArguments,
|
|
|
+ request->inputArgumentsSize,
|
|
|
+ request->inputArguments);
|
|
|
if(result->statusCode != UA_STATUSCODE_GOOD)
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
- const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
|
|
|
- if(!outputArguments) {
|
|
|
- result->outputArgumentsSize=0;
|
|
|
- }else{
|
|
|
- result->outputArguments = UA_Array_new(outputArguments->value.data.value.value.arrayLength, &UA_TYPES[UA_TYPES_VARIANT]);
|
|
|
+ result->outputArgumentsSize = 0;
|
|
|
+ const UA_VariableNode *outputArguments =
|
|
|
+ getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
|
|
|
+ if(outputArguments) {
|
|
|
+ result->outputArguments = UA_Array_new(outputArguments->value.data.value.value.arrayLength,
|
|
|
+ &UA_TYPES[UA_TYPES_VARIANT]);
|
|
|
if(!result->outputArguments) {
|
|
|
result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
|
|
|
return;
|
|
@@ -201,23 +135,23 @@ Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodR
|
|
|
result->outputArgumentsSize = outputArguments->value.data.value.value.arrayLength;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
|
|
|
methodCallSession = session;
|
|
|
#endif
|
|
|
-
|
|
|
-
|
|
|
result->statusCode = methodCalled->attachedMethod(methodCalled->methodHandle, withObject->nodeId,
|
|
|
request->inputArgumentsSize, request->inputArguments,
|
|
|
result->outputArgumentsSize, result->outputArguments);
|
|
|
-
|
|
|
#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
|
|
|
methodCallSession = NULL;
|
|
|
#endif
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
-void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,
|
|
|
- UA_CallResponse *response) {
|
|
|
|
|
|
+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");
|
|
|
if(request->methodsToCallSize <= 0) {
|
|
|
response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
|