Bläddra i källkod

Merge remote-tracking branch 'upstream/master' into feature/architectures

# Conflicts:
#	CMakeLists.txt
#	arch/ua_network_tcp.c
Stefan Profanter 6 år sedan
förälder
incheckning
050a234c01

+ 5 - 3
CMakeLists.txt

@@ -329,8 +329,10 @@ if(NOT UA_COMPILE_AS_CXX AND (CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID
     if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
         add_definitions(-ffunction-sections -fdata-sections -fno-stack-protector -fno-unwind-tables
                         -fno-asynchronous-unwind-tables -fno-math-errno -fmerge-all-constants -fno-ident)
-        set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -s")
-        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s")
+        if(NOT OS9)
+            set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -s")
+            set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s")
+        endif()
         if(APPLE)
             set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-dead_strip")
             set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
@@ -398,7 +400,7 @@ endif()
 
 set(exported_headers ${exported_headers}
                      ${ua_architecture_headers_beginning}
-                     ${PROJECT_BINARY_DIR}/src_generated/ua_config.h 
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/deps/ms_stdint.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_statuscodes.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h

+ 95 - 0
CONTRIBUTING.md

@@ -0,0 +1,95 @@
+# Contributing to open62541
+
+Contributions to open62541 include code, documentation, answering user
+questions, running the project's infrastructure, and advocating for all types of
+open62541 users.
+
+The open62541 project welcomes all contributions from anyone willing to work in
+good faith with other contributors and the community. No contribution is too
+small and all contributions are valued.
+
+This guide explains the process for contributing to the open62541 project's core
+repository and describes what to expect at each step. Thank you for considering
+these point.
+
+Your friendly open62541 community!
+
+## Code of Conduct
+
+The open62541 project has a [Code of Conduct](./CODE_OF_CONDUCT.md) that *all*
+contributors are expected to follow. This code describes the *minimum* behavior
+expectations for all contributors.
+
+## Issues
+
+- Help us help you
+- Use the [Issue Template](./.github/ISSUE_TEMPLATE)
+
+## Pull Requests
+
+Everybody can propose a pull request (PR). But only the core-maintainers of the
+project can merge PR.
+
+### Minimal requirements for a PR
+
+The following are the minimal requirements that every PR needs to meet.
+
+- **Pass Continuous Integration (CI)**: Every PR has to pass our CI. This
+  includes compilation with a range of compilers and for a range of target
+  architectures, passing the unit tests and no detected issues with static code
+  analysis tools.
+
+- **Code-Style**: Please consider the
+  [Code-Style](https://github.com/open62541/open62541/wiki/Code-Style)
+  recommendations when formatting your code.
+
+- **Signed CLA**: Every contributor must sign the Contributor License Agreement
+  (CLA) before we can merge his first PR. The signing can be done online. The
+  link automatically appears on the page of the first PR. In addition, the CLA
+  text can be accessed [here](https://cla-assistant.io/open62541/open62541).
+
+### Commit and PR Hygiene
+
+- **Separation of Concerns**: Small changes are much easier to review.
+  Typically, small PR are merged much faster. For larger contributions, it might
+  make sense to break them up into a series of PR. For example, a PR with a new
+  feature should not contain other commits with only stylistic improvements to
+  another portion of the code.
+
+- **Feature Commits**: The same holds true for the individual PR as well. Every
+  commit inside the PR should do one thing only. If many changes have been
+  applied at the same time, `git add --patch` can be used to partially stage and
+  commit changes that belong together.
+
+- **Commit Messages**: Good commit messages help in understanding changes.
+  Consider the following article with best practices for commit messages:
+  https://chris.beams.io/posts/git-commit
+
+- **Linear Commit History**: Our goal is to maintain a linear commit history
+  where possible. Use the `git rebase` functionality before pushing a PR. Use
+  `git rebase --interactive` to squash bugfix commits.
+
+### Review Process
+
+The following labels can be used for the PR title to indicate its status.
+
+- [WIP]: The PR is work in progress and at this point simply informative.
+- [Review]: The PR is ready from the developers perspective. He requests a review from a core-maintainer.
+
+The core-maintainers are busy people. If they take especially long to react,
+feel free to trigger them by additional comments in the PR thread. Again, small
+PR are much faster to review.
+
+It is the job of the developer that posts the PR to rebase the PR on the target
+branch when the two diverge.
+
+### Changes to the public API
+
+The *public* API is the collection of header files in the /include folder.
+
+Changes to the public API are under especially high scrutiny. Public API changes
+are best discussed with the core-maintainers early on. Simply to avoid duplicate
+work when changes to the proposed API become necessary.
+
+You can create a special issue or PR just for the sake of discussing a proposed
+API change. The actual implementation can follow later on.

+ 49 - 2
arch/ua_network_tcp.c

@@ -635,7 +635,31 @@ UA_StatusCode UA_ClientConnectionTCP_poll(UA_Client *client, void *data) {
         UA_UInt32 timeSinceStart =
                         (UA_UInt32) ((UA_Double) (UA_DateTime_nowMonotonic() - connStart)
                                         * UA_DATETIME_MSEC);
+#ifdef _OS9000
+        /* OS-9 can't use select for checking write sockets.
+         * Therefore, we need to use connect until success or failed
+         */
+        UA_UInt32 timeout_usec = (tcpConnection->timeout - timeSinceStart)
+                        * 1000;
+        int resultsize = 0;
+        do {
+            u_int32 time = 0x80000001;
+            signal_code sig;
+
+            timeout_usec -= 1000000/256;    // Sleep 1/256 second
+            if (timeout_usec < 0)
+                break;
 
+            _os_sleep(&time,&sig);
+            error = connect(clientsockfd, tcpConnection->server->ai_addr,
+                        WIN32_INT tcpConnection->server->ai_addrlen);
+            if ((error == -1 && errno__ == EISCONN) || (error == 0))
+                resultsize = 1;
+            if (error == -1 && errno__ != EALREADY && errno__ != EINPROGRESS)
+                break;
+        }
+        while(resultsize == 0);
+#else
         fd_set fdset;
         FD_ZERO(&fdset);
         UA_fd_set(clientsockfd, &fdset);
@@ -646,7 +670,7 @@ UA_StatusCode UA_ClientConnectionTCP_poll(UA_Client *client, void *data) {
 
         int resultsize = UA_select((UA_Int32) (clientsockfd + 1), NULL, &fdset,
         NULL, &tmptv);
-
+#endif
         if (resultsize == 1) {
             /* Windows does not have any getsockopt equivalent and it is not needed there */
 #ifdef _WIN32
@@ -873,6 +897,29 @@ UA_ClientConnectionTCP(UA_ConnectionConfig conf,
             if(timeSinceStart > dtTimeout)
                 break;
 
+#ifdef _OS9000
+            /* OS-9 can't use select for checking write sockets.
+             * Therefore, we need to use connect until success or failed
+             */
+            UA_DateTime timeout_usec = (dtTimeout - timeSinceStart) / UA_DATETIME_USEC;
+            int resultsize = 0;
+            do {
+                u_int32 time = 0x80000001;
+                signal_code sig;
+
+                timeout_usec -= 1000000/256;    // Sleep 1/256 second
+                if (timeout_usec < 0)
+                    break;
+
+                _os_sleep(&time,&sig);
+                error = connect(clientsockfd, server->ai_addr, WIN32_INT server->ai_addrlen);
+                if ((error == -1 && errno__ == EISCONN) || (error == 0))
+                    resultsize = 1;
+                if (error == -1 && errno__ != EALREADY && errno__ != EINPROGRESS)
+                    break;
+            }
+            while(resultsize == 0);
+#else
             fd_set fdset;
             FD_ZERO(&fdset);
             UA_fd_set(clientsockfd, &fdset);
@@ -880,7 +927,7 @@ UA_ClientConnectionTCP(UA_ConnectionConfig conf,
             struct timeval tmptv = {(long int) (timeout_usec / 1000000),
                                     (long int) (timeout_usec % 1000000)};
 
-            int resultsize = UA_select(clientsockfd + 1, NULL, &fdset, NULL, &tmptv);
+            int resultsize = UA_select((UA_Int32)(clientsockfd + 1), NULL, &fdset, NULL, &tmptv);
 
             if(resultsize == 1) {
 #ifdef _WIN32

+ 6 - 0
examples/server_ctt.c

@@ -241,6 +241,7 @@ setInformationModel(UA_Server *server) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
     /* Fill demo nodes for each type*/
+    UA_UInt32 matrixDims[2] = {3, 3};
     UA_UInt32 id = 51000; // running id in namespace 0
     for(UA_UInt32 type = 0; type < UA_TYPES_DIAGNOSTICINFO; type++) {
         if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
@@ -271,7 +272,10 @@ setInformationModel(UA_Server *server) {
         UA_Variant_deleteMembers(&attr.value);
 
         /* add an array node for every built-in type */
+        UA_UInt32 arrayDims = 0;
         attr.valueRank = 1;
+        attr.arrayDimensions = &arrayDims;
+        attr.arrayDimensionsSize = 1;
         UA_Variant_setArray(&attr.value, UA_Array_new(10, &UA_TYPES[type]), 10, &UA_TYPES[type]);
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), UA_NODEID_NUMERIC(1, ARRAYID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), qualifiedName,
@@ -280,6 +284,8 @@ setInformationModel(UA_Server *server) {
 
         /* add an matrix node for every built-in type */
         attr.valueRank = 2;
+        attr.arrayDimensions = matrixDims;
+        attr.arrayDimensionsSize = 2;
         void *myMultiArray = UA_Array_new(9, &UA_TYPES[type]);
         attr.value.arrayDimensions = (UA_UInt32 *)UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
         attr.value.arrayDimensions[0] = 3;

+ 4 - 0
include/ua_config.h.in

@@ -237,6 +237,10 @@ extern "C" {
 # if defined(__LITTLEENDIAN__)
 #  define UA_LITTLE_ENDIAN 1
 # endif
+#elif defined(_OS9000) /* OS-9 */
+# if defined(_LIL_END)
+#  define UA_LITTLE_ENDIAN 1
+# endif
 #endif
 #ifndef UA_LITTLE_ENDIAN
 # define UA_LITTLE_ENDIAN 0

+ 1 - 1
src/server/ua_server_binary.c

@@ -521,7 +521,7 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
                                "bound to this SecureChannel");
         UA_deleteMembers(request, requestType);
         return sendServiceFault(channel, msg, requestPos, responseType,
-                                requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
+                                requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID);
     }
 
     /* Update the session lifetime */

+ 3 - 2
src/server/ua_server_internal.h

@@ -300,7 +300,7 @@ readValueAttribute(UA_Server *server, UA_Session *session,
  * byte array to bytestring or uint32 to some enum. If editableValue is non-NULL,
  * we try to create a matching variant that points to the original data. */
 UA_Boolean
-compatibleValue(UA_Server *server, const UA_NodeId *targetDataTypeId,
+compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId,
                 UA_Int32 targetValueRank, size_t targetArrayDimensionsSize,
                 const UA_UInt32 *targetArrayDimensions, const UA_Variant *value,
                 const UA_NumericRange *range);
@@ -316,7 +316,8 @@ compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimens
                                const UA_UInt32 *targetArrayDimensions);
 
 UA_Boolean
-compatibleValueRankArrayDimensions(UA_Int32 valueRank, size_t arrayDimensionsSize);
+compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session,
+                                   UA_Int32 valueRank, size_t arrayDimensionsSize);
 
 UA_Boolean
 compatibleDataType(UA_Server *server, const UA_NodeId *dataType,

+ 2 - 2
src/server/ua_server_ns0.c

@@ -436,8 +436,8 @@ readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId, void *sessionC
         serverHandles[i] = monitoredItem->monitoredItemId;
         ++i;
     }
-    UA_Variant_setArray(&output[0], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
-    UA_Variant_setArray(&output[1], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_Variant_setArray(&output[0], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_Variant_setArray(&output[1], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
     return UA_STATUSCODE_GOOD;
 }
 #endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */

+ 67 - 45
src/server/ua_services_attribute.c

@@ -617,32 +617,38 @@ compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
     return false;
 }
 
-/* Test whether a valurank and the given arraydimensions are compatible. zero
- * array dimensions indicate a scalar */
+/* Test whether a ValueRank and the given arraydimensions are compatible.
+ *
+ * 5.6.2 Variable NodeClass: If the maximum is unknown the value shall be 0. The
+ * number of elements shall be equal to the value of the ValueRank Attribute.
+ * This Attribute shall be null if ValueRank <= 0. */
 UA_Boolean
-compatibleValueRankArrayDimensions(UA_Int32 valueRank, size_t arrayDimensionsSize) {
-    switch(valueRank) {
-    case -3: /* the value can be a scalar or a one dimensional array */
-        if(arrayDimensionsSize > 1)
-            return false;
-        break;
-    case -2: /* the value can be a scalar or an array with any number of dimensions */
-        break;
-    case -1: /* the value is a scalar */
-        if(arrayDimensionsSize > 0)
-            return false;
-        break;
-    case 0: /* the value is an array with one or more dimensions */
-        if(arrayDimensionsSize < 1)
-            return false;
-        break;
-    default: /* >= 1: the value is an array with the specified number of dimensions */
-        if(valueRank < (UA_Int32) 0)
-            return false;
-        /* Must hold if the array has a defined length. Null arrays (length -1)
-         * need to be caught before. */
-        if(arrayDimensionsSize != (size_t)valueRank)
+compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session,
+                                   UA_Int32 valueRank, size_t arrayDimensionsSize) {
+    /* ValueRank invalid */
+    if(valueRank < -3) {
+        UA_LOG_INFO_SESSION(server->config.logger, session, "The ValueRank is invalid (< -3)");
+        return false;
+    }
+
+    /* case -3: the value can be a scalar or a one dimensional array */
+    /* case -2: the value can be a scalar or an array with any number of dimensions */
+    /* case -1: the value is a scalar */
+    /* case 0:  the value is an array with one or more dimensions */
+    if(valueRank <= 0) {
+        if(arrayDimensionsSize > 0) {
+            UA_LOG_INFO_SESSION(server->config.logger, session,
+                                "No ArrayDimensions can be defined for a ValueRank <= 0");
             return false;
+        }
+        return true;
+    }
+    
+    /* case >= 1: the value is an array with the specified number of dimensions */
+    if(arrayDimensionsSize != (size_t)valueRank) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "The number of ArrayDimensions is not equal to the (positive) ValueRank");
+        return false;
     }
     return true;
 }
@@ -673,9 +679,15 @@ compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank) {
     return true;
 }
 
-/* Check if the valuerank allows for the value dimension */
+/* Check if the ValueRank allows for the value dimension. This is more
+ * permissive than checking for the ArrayDimensions attribute. Because the value
+ * can have dimensions if the ValueRank < 0 */
 static UA_Boolean
 compatibleValueRankValue(UA_Int32 valueRank, const UA_Variant *value) {
+    /* Invalid ValueRank */
+    if(valueRank < -3)
+        return false;
+
     /* Empty arrays (-1) always match */
     if(!value->data)
         return true;
@@ -683,7 +695,24 @@ compatibleValueRankValue(UA_Int32 valueRank, const UA_Variant *value) {
     size_t arrayDims = value->arrayDimensionsSize;
     if(arrayDims == 0 && !UA_Variant_isScalar(value))
         arrayDims = 1; /* array but no arraydimensions -> implicit array dimension 1 */
-    return compatibleValueRankArrayDimensions(valueRank, arrayDims);
+
+    /* We cannot simply use compatibleValueRankArrayDimensions since we can have
+     * defined ArrayDimensions for the value if the ValueRank is -2 */
+    switch(valueRank) {
+    case -3: /* The value can be a scalar or a one dimensional array */
+        return (arrayDims <= 1);
+    case -2: /* The value can be a scalar or an array with any number of dimensions */
+        return true;
+    case -1: /* The value is a scalar */
+        return (arrayDims == 0);
+    default:
+        break;
+    }
+
+    UA_assert(valueRank >= 0);
+
+    /* case 0:  the value is an array with one or more dimensions */
+    return (arrayDims == (UA_UInt32)valueRank);
 }
 
 UA_Boolean
@@ -724,7 +753,7 @@ compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimens
 }
 
 UA_Boolean
-compatibleValue(UA_Server *server, const UA_NodeId *targetDataTypeId,
+compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId,
                 UA_Int32 targetValueRank, size_t targetArrayDimensionsSize,
                 const UA_UInt32 *targetArrayDimensions, const UA_Variant *value,
                 const UA_NumericRange *range) {
@@ -802,7 +831,6 @@ adjustValue(UA_Server *server, UA_Variant *value,
     /* No more possible equivalencies */
 }
 
-/* Stack layout: ... | node | type */
 static UA_StatusCode
 writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session,
                               UA_VariableNode *node, const UA_VariableTypeNode *type,
@@ -820,9 +848,9 @@ writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session,
     }
 
     /* Check that the array dimensions match with the valuerank */
-    if(!compatibleValueRankArrayDimensions(node->valueRank, arrayDimensionsSize)) {
+    if(!compatibleValueRankArrayDimensions(server, session, node->valueRank, arrayDimensionsSize)) {
         UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SERVER,
-                     "The current value rank does not match the new array dimensions");
+                     "Cannot write the ArrayDimensions. The ValueRank does not match.");
         return UA_STATUSCODE_BADTYPEMISMATCH;
     }
 
@@ -906,7 +934,7 @@ writeValueRankAttribute(UA_Server *server, UA_Session *session,
             arrayDims = 1;
         UA_DataValue_deleteMembers(&value);
     }
-    if(!compatibleValueRankArrayDimensions(valueRank, arrayDims))
+    if(!compatibleValueRankArrayDimensions(server, session, valueRank, arrayDims))
         return UA_STATUSCODE_BADTYPEMISMATCH;
 
     /* All good, apply the change */
@@ -938,7 +966,7 @@ writeDataTypeAttribute(UA_Server *server, UA_Session *session,
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     if(value.hasValue) {
-        if(!compatibleValue(server, dataType, node->valueRank,
+        if(!compatibleValue(server, session, dataType, node->valueRank,
                             node->arrayDimensionsSize, node->arrayDimensions,
                             &value.value, NULL))
             retval = UA_STATUSCODE_BADTYPEMISMATCH;
@@ -1041,21 +1069,15 @@ writeValueAttribute(UA_Server *server, UA_Session *session,
          * uses extension objects to write variable values. If value is an
          * extension object we check if the current node value is also an
          * extension object. */
-        UA_Boolean compatible;
+        const UA_NodeId nodeDataType = UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE);
+        const UA_NodeId *nodeDataTypePtr = &node->dataType;
         if(value->value.type->typeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
-           value->value.type->typeId.identifier.numeric == UA_NS0ID_STRUCTURE) {
-            const UA_NodeId nodeDataType = UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE);
-            compatible = compatibleValue(server, &nodeDataType, node->valueRank,
-                                    node->arrayDimensionsSize, node->arrayDimensions,
-                                    &adjustedValue.value, rangeptr);
-        } else {
-            compatible = compatibleValue(server, &node->dataType, node->valueRank,
-                                     node->arrayDimensionsSize, node->arrayDimensions,
-                                     &adjustedValue.value, rangeptr);
-        }
+           value->value.type->typeId.identifier.numeric == UA_NS0ID_STRUCTURE)
+            nodeDataTypePtr = &nodeDataType;
 
-
-        if(!compatible) {
+        if(!compatibleValue(server, session, nodeDataTypePtr, node->valueRank,
+                            node->arrayDimensionsSize, node->arrayDimensions,
+                            &adjustedValue.value, rangeptr)) {
             if(rangeptr)
                 UA_free(range.dimensions);
             return UA_STATUSCODE_BADTYPEMISMATCH;

+ 7 - 7
src/server/ua_services_call.c

@@ -50,9 +50,9 @@ getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
 
 /* inputArgumentResults has the length request->inputArgumentsSize */
 static UA_StatusCode
-typeCheckArguments(UA_Server *server, const UA_VariableNode *argRequirements,
-                   size_t argsSize, UA_Variant *args,
-                   UA_StatusCode *inputArgumentResults) {
+typeCheckArguments(UA_Server *server, UA_Session *session,
+                   const UA_VariableNode *argRequirements, size_t argsSize,
+                   UA_Variant *args, UA_StatusCode *inputArgumentResults) {
     /* Verify that we have a Variant containing UA_Argument (scalar or array) in
      * the "InputArguments" node */
     if(argRequirements->valueSource != UA_VALUESOURCE_DATA)
@@ -76,7 +76,7 @@ typeCheckArguments(UA_Server *server, const UA_VariableNode *argRequirements,
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Argument *argReqs = (UA_Argument*)argRequirements->value.data.value.value.data;
     for(size_t i = 0; i < argReqsSize; ++i) {
-        if(!compatibleValue(server, &argReqs[i].dataType, argReqs[i].valueRank,
+        if(!compatibleValue(server, session, &argReqs[i].dataType, argReqs[i].valueRank,
                             argReqs[i].arrayDimensionsSize, argReqs[i].arrayDimensions,
                             &args[i], NULL)) {
             inputArgumentResults[i] = UA_STATUSCODE_BADTYPEMISMATCH;
@@ -88,7 +88,7 @@ typeCheckArguments(UA_Server *server, const UA_VariableNode *argRequirements,
 
 /* inputArgumentResults has the length request->inputArgumentsSize */
 static UA_StatusCode
-validMethodArguments(UA_Server *server, const UA_MethodNode *method,
+validMethodArguments(UA_Server *server, UA_Session *session, const UA_MethodNode *method,
                      const UA_CallMethodRequest *request,
                      UA_StatusCode *inputArgumentResults) {
     /* Get the input arguments node */
@@ -101,7 +101,7 @@ validMethodArguments(UA_Server *server, const UA_MethodNode *method,
     }
 
     /* Verify the request */
-    UA_StatusCode retval = typeCheckArguments(server, inputArguments,
+    UA_StatusCode retval = typeCheckArguments(server, session, inputArguments,
                                               request->inputArgumentsSize,
                                               request->inputArguments,
                                               inputArgumentResults);
@@ -185,7 +185,7 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session,
     result->inputArgumentResultsSize = request->inputArgumentsSize;
 
     /* Verify Input Arguments */
-    result->statusCode = validMethodArguments(server, method, request, result->inputArgumentResults);
+    result->statusCode = validMethodArguments(server, session, method, request, result->inputArgumentResults);
 
     /* Return inputArgumentResults only for BADINVALIDARGUMENT */
     if(result->statusCode != UA_STATUSCODE_BADINVALIDARGUMENT) {

+ 8 - 15
src/server/ua_services_nodemanagement.c

@@ -161,22 +161,9 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
         return UA_STATUSCODE_BADTYPEMISMATCH;
     }
 
-    /* Get the array dimensions */
-    size_t arrayDims = node->arrayDimensionsSize;
-    if(arrayDims == 0 && value.hasValue && value.value.type &&
-       !UA_Variant_isScalar(&value.value)) {
-        arrayDims = 1; /* No array dimensions on an array implies one dimension */
-    }
-
     /* Check valueRank against array dimensions */
-    if(arrayDims != 0 &&
-       !(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
-         ((const UA_VariableTypeNode*)node)->isAbstract && node->valueRank == 0) &&
-       !compatibleValueRankArrayDimensions(node->valueRank, arrayDims)) {
-        UA_LOG_INFO_SESSION(server->config.logger, session,
-                            "AddNodes: The value rank and array dimensions are not compatible");
+    if(!compatibleValueRankArrayDimensions(server, session, node->valueRank, node->arrayDimensionsSize))
         return UA_STATUSCODE_BADTYPEMISMATCH;
-    }
 
     /* Check valueRank against the vt */
     if(!compatibleValueRanks(node->valueRank, vt->valueRank)) {
@@ -197,7 +184,7 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
     if(value.hasValue) {
         /* If the type-check failed write the same value again. The
          * write-service tries to convert to the correct type... */
-        if(!compatibleValue(server, &node->dataType, node->valueRank,
+        if(!compatibleValue(server, session, &node->dataType, node->valueRank,
                             node->arrayDimensionsSize, node->arrayDimensions,
                             &value.value, NULL))
             retval = UA_Server_writeValue(server, node->nodeId, value.value);
@@ -1639,6 +1626,9 @@ UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
         attr.displayName = UA_LOCALIZEDTEXT("", name);
         attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
         attr.valueRank = 1;
+        UA_UInt32 inputArgsSize32 = (UA_UInt32)inputArgumentsSize;
+        attr.arrayDimensions = &inputArgsSize32;
+        attr.arrayDimensionsSize = 1;
         UA_Variant_setArray(&attr.value, (void*)(uintptr_t) inputArguments,
                             inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
         retval |= UA_Server_addVariableNode(server, inputArgumentsRequestedNewNodeId, nodeId,
@@ -1653,6 +1643,9 @@ UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
         attr.displayName = UA_LOCALIZEDTEXT("", name);
         attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
         attr.valueRank = 1;
+        UA_UInt32 outputArgsSize32 = (UA_UInt32)outputArgumentsSize;
+        attr.arrayDimensions = &outputArgsSize32;
+        attr.arrayDimensionsSize = 1;
         UA_Variant_setArray(&attr.value, (void*)(uintptr_t) outputArguments,
                             outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
         retval |= UA_Server_addVariableNode(server, outputArgumentsRequestedNewNodeId, nodeId,