Bladeren bron

Reintroduce changes removed during rebase onto master.

These changes are required for more complex nodesets, i.e., DI
Stefan Profanter 7 jaren geleden
bovenliggende
commit
9e00b809a0
2 gewijzigde bestanden met toevoegingen van 104 en 29 verwijderingen
  1. 20 3
      src/server/ua_services_attribute.c
  2. 84 26
      src/server/ua_services_nodemanagement.c

+ 20 - 3
src/server/ua_services_attribute.c

@@ -878,9 +878,26 @@ writeValueAttribute(UA_Server *server, UA_Session *session,
     /* Type checking. May change the type of editableValue */
     if(value->hasValue && value->value.type) {
         adjustValue(server, &adjustedValue.value, &node->dataType);
-        if(!compatibleValue(server, &node->dataType, node->valueRank,
-                            node->arrayDimensionsSize, node->arrayDimensions,
-                            &adjustedValue.value, rangeptr)) {
+
+        /* The value may be an extension object, especially the nodeset compiler 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;
+        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);
+        }
+
+
+        if(!compatible) {
             if(rangeptr)
                 UA_free(range.dimensions);
             return UA_STATUSCODE_BADTYPEMISMATCH;

+ 84 - 26
src/server/ua_services_nodemanagement.c

@@ -131,7 +131,8 @@ checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeCl
 
 static UA_StatusCode
 typeCheckVariableNode(UA_Server *server, UA_Session *session,
-                      const UA_VariableNode *node, const UA_VariableTypeNode *vt) {
+                      const UA_VariableNode *node, const UA_VariableTypeNode *vt,
+                      const UA_NodeId *parentNodeId) {
     /* The value might come from a datasource, so we perform a
      * regular read. */
     UA_DataValue value;
@@ -152,12 +153,24 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
     }
 
     /* Check valueRank against array dimensions */
-    if(!compatibleValueRankArrayDimensions(node->valueRank, arrayDims))
+    if (!(node->nodeClass == UA_NODECLASS_VARIABLETYPE && ((const UA_VariableTypeNode*)node)->isAbstract && node->valueRank == 0) &&
+        !compatibleValueRankArrayDimensions(node->valueRank, arrayDims))
         return UA_STATUSCODE_BADTYPEMISMATCH;
 
-    /* Check valueRank against the vt */
-    if(!compatibleValueRanks(node->valueRank, vt->valueRank))
-        return UA_STATUSCODE_BADTYPEMISMATCH;
+    /* If variable node is created below BaseObjectType and has its default valueRank of -2,
+     * skip the test */
+    const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
+    const UA_NodeId refs[] = {
+            UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)
+    };
+    if(node->valueRank != vt->valueRank &&
+       node->valueRank != UA_VariableAttributes_default.valueRank &&
+       !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes, refs , 2)) {
+        /* Check valueRank against the vt */
+        if(!compatibleValueRanks(node->valueRank, vt->valueRank))
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+    }
 
     /* Check array dimensions against the vt */
     if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions,
@@ -625,18 +638,24 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
     if(!node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
-    if(server->bootstrapNS0)
-        goto get_type;
-
     /* Use the typeDefinition as parent for type-nodes */
     if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
        node->nodeClass == UA_NODECLASS_OBJECTTYPE ||
        node->nodeClass == UA_NODECLASS_REFERENCETYPE ||
        node->nodeClass == UA_NODECLASS_DATATYPE) {
-        referenceTypeId = &hasSubtype;
-        typeDefinitionId = parentNodeId;
+        if (UA_NodeId_equal(referenceTypeId, &UA_NODEID_NULL))
+            referenceTypeId = &hasSubtype;
+        const UA_Node *parentNode = UA_Nodestore_get(server, parentNodeId);
+        if (parentNode) {
+			if (parentNode->nodeClass == node->nodeClass)
+				typeDefinitionId = parentNodeId;
+			UA_Nodestore_release(server, parentNode);
+        }
     }
 
+    if(server->bootstrapNS0)
+        goto get_type;
+
     /* Check parent reference. Objects may have no parent. */
     retval = checkParentReference(server, session, node->nodeClass,
                                   parentNodeId, referenceTypeId);
@@ -668,24 +687,54 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
         /* Get the type node */
         type = UA_Nodestore_get(server, typeDefinitionId);
         if(!type) {
+            UA_LOG_INFO_SESSION(server->config.logger, session,
+                                "AddNodes: Node type not found in nodestore");
             retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
             goto cleanup;
         }
 
         /* See if the type has the correct node class. For type-nodes, we know
          * that type has the same nodeClass from checkParentReference. */
-        if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+        if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_VARIABLE) {
             if(type->nodeClass != UA_NODECLASS_VARIABLETYPE ||
-               ((const UA_VariableTypeNode*)type)->isAbstract) {
-                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
-                goto cleanup;
+                    ((const UA_VariableTypeNode*)type)->isAbstract) {
+                /* Abstract variable is allowed if parent is a children of a base data variable */
+                const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+                /* A variable may be of an object type which again is below BaseObjectType */
+                const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
+                const UA_NodeId refs[] = {
+                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)
+                };
+                if(!isNodeInTree(&server->config.nodestore, parentNodeId,
+                                 &variableTypes, refs , 2) &&
+                   !isNodeInTree(&server->config.nodestore, parentNodeId,
+                                     &objectTypes, refs , 2)) {
+                    UA_LOG_INFO_SESSION(server->config.logger, session,
+                                        "AddNodes: Type of variable node must "
+                                                "be VariableType and not cannot be abstract");
+                    retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+                    goto cleanup;
+                }
             }
         }
-        if(node->nodeClass == UA_NODECLASS_OBJECT) {
+        if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_OBJECT) {
             if(type->nodeClass != UA_NODECLASS_OBJECTTYPE ||
-               ((const UA_ObjectTypeNode*)type)->isAbstract) {
-                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
-                goto cleanup;
+                    ((const UA_ObjectTypeNode*)type)->isAbstract) {
+                /* Object node created of an abstract ObjectType. Only allowed if within BaseObjectType folder */
+                const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
+                const UA_NodeId refs[] = {
+                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT)
+                };
+                if(!isNodeInTree(&server->config.nodestore, parentNodeId,
+                                 &objectTypes, refs , 2)) {
+                    UA_LOG_INFO_SESSION(server->config.logger, session,
+                                        "AddNodes: Type of object node must "
+                                                "be ObjectType and not be abstract");
+                    retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+                    goto cleanup;
+                }
             }
         }
     }
@@ -697,7 +746,7 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
                 node->nodeClass == UA_NODECLASS_VARIABLETYPE)) {
         retval = typeCheckVariableNode(server, session,
                                        (const UA_VariableNode*)node,
-                                       (const UA_VariableTypeNode*)type);
+                                       (const UA_VariableTypeNode*)type, parentNodeId);
         if(retval != UA_STATUSCODE_GOOD) {
             UA_LOG_INFO_SESSION(server->config.logger, session,
                                 "AddNodes: Type-checking the variable node "
@@ -711,13 +760,15 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
        node->nodeClass == UA_NODECLASS_OBJECT) {
         UA_assert(type != NULL); /* see above */
         /* Add (mandatory) child nodes from the type definition */
-        retval = addChildren(server, session, node, type);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Adding child nodes failed with error code %s",
-                                UA_StatusCode_name(retval));
-            goto cleanup;
-        }
+		if (!server->bootstrapNS0) {
+			retval = addChildren(server, session, node, type);
+			if(retval != UA_STATUSCODE_GOOD) {
+				UA_LOG_INFO_SESSION(server->config.logger, session,
+									"AddNodes: Adding child nodes failed with error code %s",
+									UA_StatusCode_name(retval));
+				goto cleanup;
+			}
+		}
 
         /* Add a hasTypeDefinition reference */
         retval = addTypeDefRef(server, session, node, type);
@@ -732,6 +783,13 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
 
     /* Add reference to the parent */
     if(!UA_NodeId_isNull(parentNodeId)) {
+        if (UA_NodeId_isNull(referenceTypeId)) {
+            UA_LOG_INFO_SESSION(server->config.logger, session,
+                                "AddNodes: Reference to parent cannot be null");
+            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+            goto cleanup;
+        }
+
         retval = addParentRef(server, session, nodeId, referenceTypeId, parentNodeId);
         if(retval != UA_STATUSCODE_GOOD) {
             UA_LOG_INFO_SESSION(server->config.logger, session,