ua_services_call.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #include "ua_services.h"
  2. #include "ua_server_internal.h"
  3. #include "ua_statuscodes.h"
  4. #include "ua_util.h"
  5. #include "ua_nodestore.h"
  6. #include "ua_nodes.h"
  7. static const UA_VariableNode *getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
  8. UA_String withBrowseName) {
  9. const UA_Node *refTarget;
  10. UA_NodeId hasProperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
  11. for(UA_Int32 i = 0; i < ofMethod->referencesSize; i++) {
  12. if(ofMethod->references[i].isInverse == UA_FALSE &&
  13. UA_NodeId_equal(&hasProperty, &ofMethod->references[i].referenceTypeId)) {
  14. refTarget = UA_NodeStore_get(server->nodestore, &ofMethod->references[i].targetId.nodeId);
  15. if(!refTarget)
  16. continue;
  17. if(refTarget->nodeClass == UA_NODECLASS_VARIABLE &&
  18. refTarget->browseName.namespaceIndex == 0 &&
  19. UA_String_equal(&withBrowseName, &refTarget->browseName.name)) {
  20. return (const UA_VariableNode*) refTarget;
  21. }
  22. UA_NodeStore_release(refTarget);
  23. }
  24. }
  25. return UA_NULL;
  26. }
  27. static UA_StatusCode statisfySignature(UA_Variant *var, UA_Argument arg) {
  28. if(!UA_NodeId_equal(&var->type->typeId, &arg.dataType) )
  29. return UA_STATUSCODE_BADINVALIDARGUMENT;
  30. // Note: The namespace compiler will compile nodes with their actual array dimensions, never -1
  31. if(arg.arrayDimensionsSize > 0 && var->arrayDimensionsSize > 0)
  32. if(var->arrayDimensionsSize != arg.arrayDimensionsSize)
  33. return UA_STATUSCODE_BADINVALIDARGUMENT;
  34. // Continue with jpfr's statisfySignature from here on
  35. /* ValueRank Semantics
  36. * n >= 1: the value is an array with the specified number of dimens*ions.
  37. * n = 0: the value is an array with one or more dimensions.
  38. * n = -1: the value is a scalar.
  39. * n = -2: the value can be a scalar or an array with any number of dimensions.
  40. * n = -3: the value can be a scalar or a one dimensional array. */
  41. UA_Boolean scalar = UA_Variant_isScalar(var);
  42. if(arg.valueRank == 0 && scalar)
  43. return UA_STATUSCODE_BADINVALIDARGUMENT;
  44. if(arg.valueRank == -1 && !scalar)
  45. return UA_STATUSCODE_BADINVALIDARGUMENT;
  46. if(arg.valueRank == -3 && var->arrayDimensionsSize > 1)
  47. return UA_STATUSCODE_BADINVALIDARGUMENT;
  48. if(arg.valueRank >= 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
  49. return UA_STATUSCODE_BADINVALIDARGUMENT;
  50. if(arg.arrayDimensionsSize >= 1) {
  51. if(arg.arrayDimensionsSize != var->arrayDimensionsSize)
  52. return UA_STATUSCODE_BADINVALIDARGUMENT;
  53. for(UA_Int32 i = 0; i < arg.arrayDimensionsSize; i++) {
  54. if(arg.arrayDimensions[i] != (UA_UInt32) var->arrayDimensions[i])
  55. return UA_STATUSCODE_BADINVALIDARGUMENT;
  56. }
  57. }
  58. return UA_STATUSCODE_GOOD;
  59. }
  60. static UA_StatusCode argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefinition) {
  61. if(argDefinition->value.variant.type != &UA_TYPES[UA_TYPES_ARGUMENT] &&
  62. argDefinition->value.variant.type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
  63. return UA_STATUSCODE_BADINTERNALERROR;
  64. if(rs->inputArgumentsSize < argDefinition->value.variant.arrayLength)
  65. return UA_STATUSCODE_BADARGUMENTSMISSING;
  66. if(rs->inputArgumentsSize > argDefinition->value.variant.arrayLength)
  67. return UA_STATUSCODE_BADINVALIDARGUMENT;
  68. const UA_ExtensionObject *thisArgDefExtObj;
  69. UA_Variant *var;
  70. UA_Argument arg;
  71. size_t decodingOffset = 0;
  72. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  73. UA_NodeId ArgumentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ARGUMENT + UA_ENCODINGOFFSET_BINARY);
  74. for(int i = 0; i<rs->inputArgumentsSize; i++) {
  75. var = &rs->inputArguments[i];
  76. if(argDefinition->value.variant.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) {
  77. thisArgDefExtObj = &((const UA_ExtensionObject *) (argDefinition->value.variant.data))[i];
  78. decodingOffset = 0;
  79. if(!UA_NodeId_equal(&ArgumentNodeId, &thisArgDefExtObj->typeId))
  80. return UA_STATUSCODE_BADINTERNALERROR;
  81. UA_decodeBinary(&thisArgDefExtObj->body, &decodingOffset, &arg, &UA_TYPES[UA_TYPES_ARGUMENT]);
  82. } else if(argDefinition->value.variant.type == &UA_TYPES[UA_TYPES_ARGUMENT])
  83. arg = ((UA_Argument *) argDefinition->value.variant.data)[i];
  84. retval |= statisfySignature(var, arg);
  85. }
  86. return retval;
  87. }
  88. void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,
  89. UA_CallResponse *response) {
  90. if(request->methodsToCallSize <= 0) {
  91. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  92. return;
  93. }
  94. response->results = UA_Array_new(&UA_TYPES[UA_TYPES_CALLMETHODRESULT], request->methodsToCallSize);
  95. if(!response->results) {
  96. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  97. return;
  98. }
  99. response->resultsSize = request->methodsToCallSize;
  100. for(UA_Int32 i = 0; i < request->methodsToCallSize;i++) {
  101. UA_CallMethodRequest *rq = &request->methodsToCall[i];
  102. UA_CallMethodResult *rs = &response->results[i];
  103. /* Get/Check Nodes */
  104. const UA_MethodNode *methodCalled =
  105. (const UA_MethodNode*) UA_NodeStore_get(server->nodestore, &rq->methodId);
  106. if(methodCalled == UA_NULL) {
  107. rs->statusCode = UA_STATUSCODE_BADMETHODINVALID;
  108. continue;
  109. }
  110. const UA_ObjectNode *withObject =
  111. (const UA_ObjectNode *) UA_NodeStore_get(server->nodestore, &rq->objectId);
  112. if(withObject == UA_NULL) {
  113. rs->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
  114. printf("Obj not found\n");
  115. continue;
  116. }
  117. if(methodCalled->nodeClass != UA_NODECLASS_METHOD) {
  118. rs->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
  119. continue;
  120. }
  121. if(withObject->nodeClass != UA_NODECLASS_OBJECT && withObject->nodeClass != UA_NODECLASS_OBJECTTYPE) {
  122. rs->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
  123. printf("Obj not found 1\n");
  124. continue;
  125. }
  126. /* Verify method/object relations */
  127. // Object must have a hasComponent reference (or any inherited referenceType from sayd reference)
  128. // to be valid for a methodCall...
  129. for(UA_Int32 i = 0; i < withObject->referencesSize; i++) {
  130. if(withObject->references[i].referenceTypeId.identifier.numeric == UA_NS0ID_HASCOMPONENT) {
  131. // FIXME: Not checking any subtypes of HasComponent at the moment
  132. if(UA_NodeId_equal(&withObject->references[i].targetId.nodeId, &methodCalled->nodeId)) {
  133. rs->statusCode = UA_STATUSCODE_GOOD;
  134. break;
  135. }
  136. }
  137. }
  138. if(rs->statusCode != UA_STATUSCODE_GOOD)
  139. continue;
  140. /* Verify method executable */
  141. if(((const UA_MethodNode *) methodCalled)->executable == UA_FALSE ||
  142. ((const UA_MethodNode *) methodCalled)->userExecutable == UA_FALSE ) {
  143. rs->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
  144. continue;
  145. }
  146. /* Verify Input Argument count, types and sizes */
  147. const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled,
  148. UA_STRING("InputArguments"));
  149. if(inputArguments) {
  150. // Expects arguments
  151. rs->statusCode = argConformsToDefinition(rq, inputArguments);
  152. UA_NodeStore_release((const UA_Node*)inputArguments);
  153. if(rs->statusCode != UA_STATUSCODE_GOOD)
  154. continue;
  155. } else if(rq->inputArgumentsSize > 0) {
  156. // Expects no arguments, but got some
  157. rs->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
  158. UA_NodeStore_release((const UA_Node*)inputArguments);
  159. continue;
  160. }
  161. const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled,
  162. UA_STRING("OutputArguments"));
  163. if(!outputArguments) {
  164. // A MethodNode must have an OutputArguments variable (which may be empty)
  165. rs->statusCode = UA_STATUSCODE_BADINTERNALERROR;
  166. continue;
  167. }
  168. // Call method if available
  169. if(methodCalled->attachedMethod) {
  170. rs->outputArguments = UA_Array_new(&UA_TYPES[UA_TYPES_VARIANT],
  171. outputArguments->value.variant.arrayLength);
  172. rs->outputArgumentsSize = outputArguments->value.variant.arrayLength;
  173. rs->statusCode = methodCalled->attachedMethod(withObject->nodeId, rq->inputArguments,
  174. rs->outputArguments);
  175. }
  176. else
  177. rs->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
  178. /* FIXME: Verify Output Argument count, types and sizes */
  179. if(outputArguments) {
  180. UA_NodeStore_release((const UA_Node*)outputArguments);
  181. }
  182. UA_NodeStore_release((const UA_Node *)withObject);
  183. UA_NodeStore_release((const UA_Node *)methodCalled);
  184. }
  185. }