Browse Source

further improvements

Julius Pfrommer 8 years ago
parent
commit
978e9caad3

+ 43 - 14
src/server/ua_server_internal.h

@@ -91,10 +91,6 @@ UA_StatusCode UA_Server_delayedCallback(UA_Server *server, UA_ServerCallback cal
 UA_StatusCode UA_Server_delayedFree(UA_Server *server, void *data);
 UA_StatusCode UA_Server_delayedFree(UA_Server *server, void *data);
 void UA_Server_deleteAllRepeatedJobs(UA_Server *server);
 void UA_Server_deleteAllRepeatedJobs(UA_Server *server);
 
 
-#ifdef UA_BUILD_UNIT_TESTS
-UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range);
-#endif
-
 /* Add an existing node. The node is assumed to be "finished", i.e. no
 /* Add an existing node. The node is assumed to be "finished", i.e. no
  * instantiation from inheritance is necessary. Instantiationcallback and
  * instantiation from inheritance is necessary. Instantiationcallback and
  * addedNodeId may be NULL. */
  * addedNodeId may be NULL. */
@@ -106,15 +102,53 @@ Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
                           UA_InstantiationCallback *instantiationCallback,
                           UA_InstantiationCallback *instantiationCallback,
                           UA_NodeId *addedNodeId);
                           UA_NodeId *addedNodeId);
 
 
-UA_StatusCode
-getTypeHierarchy(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size_t *reftypes_count);
+/*********************/
+/* Utility Functions */
+/*********************/
 
 
 UA_StatusCode
 UA_StatusCode
-isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode, const UA_NodeId *nodeToFind,
-             const UA_NodeId *referenceTypeIds, size_t referenceTypeIdsSize, UA_Boolean *found);
+parse_numericrange(const UA_String *str, UA_NumericRange *range);
+
+UA_Boolean
+UA_Node_hasSubTypeOrInstances(const UA_Node *node);
 
 
 const UA_VariableTypeNode *
 const UA_VariableTypeNode *
-getVariableType(UA_Server *server, const UA_VariableNode *node);
+getVariableNodeType(UA_Server *server, const UA_VariableNode *node);
+
+const UA_ObjectTypeNode *
+getObjectNodeType(UA_Server *server, const UA_ObjectNode *node);
+
+UA_StatusCode
+getTypeHierarchy(UA_NodeStore *ns, const UA_NodeId *root,
+                 UA_NodeId **reftypes, size_t *reftypes_count);
+
+UA_StatusCode
+isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode,
+             const UA_NodeId *nodeToFind, const UA_NodeId *referenceTypeIds,
+             size_t referenceTypeIdsSize, UA_Boolean *found);
+
+/***************************************/
+/* Check Information Model Consistency */
+/***************************************/
+
+UA_StatusCode
+UA_VariableNode_setArrayDimensions(UA_Server *server, UA_VariableNode *node,
+                                   const UA_VariableTypeNode *vt,
+                                   size_t arrayDimensionsSize, UA_UInt32 *arrayDimensions);
+
+UA_StatusCode
+UA_VariableNode_setValueRank(UA_Server *server, UA_VariableNode *node,
+                             const UA_VariableTypeNode *vt,
+                             const UA_Int32 valueRank);
+
+UA_StatusCode
+UA_VariableNode_setDataType(UA_Server *server, UA_VariableNode *node,
+                            const UA_VariableTypeNode *vt,
+                            const UA_NodeId *dataType);
+
+UA_StatusCode
+UA_VariableNode_setValue(UA_Server *server, UA_VariableNode *node,
+                         const UA_DataValue *value, const UA_String *indexRange);
 
 
 UA_StatusCode
 UA_StatusCode
 UA_Variant_matchVariableDefinition(UA_Server *server, const UA_NodeId *variableDataTypeId,
 UA_Variant_matchVariableDefinition(UA_Server *server, const UA_NodeId *variableDataTypeId,
@@ -122,9 +156,4 @@ UA_Variant_matchVariableDefinition(UA_Server *server, const UA_NodeId *variableD
                                    const UA_UInt32 *variableArrayDimensions, const UA_Variant *value,
                                    const UA_UInt32 *variableArrayDimensions, const UA_Variant *value,
                                    const UA_NumericRange *range, UA_Variant *equivalent);
                                    const UA_NumericRange *range, UA_Variant *equivalent);
 
 
-/* Set the value attribute inside a node */
-UA_StatusCode
-writeValueAttribute(UA_Server *server, UA_VariableNode *node,
-                    const UA_DataValue *value, const UA_String *indexRange);
-
 #endif /* UA_SERVER_INTERNAL_H_ */
 #endif /* UA_SERVER_INTERNAL_H_ */

+ 45 - 11
src/server/ua_server_utils.c

@@ -26,10 +26,8 @@ readDimension(UA_Byte *buf, size_t buflen, UA_NumericRangeDimension *dim) {
     return progress + progress2;
     return progress + progress2;
 }
 }
 
 
-#ifndef UA_BUILD_UNIT_TESTS
-static
-#endif
-UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
+UA_StatusCode
+parse_numericrange(const UA_String *str, UA_NumericRange *range) {
     size_t idx = 0;
     size_t idx = 0;
     size_t dimensionsMax = 0;
     size_t dimensionsMax = 0;
     UA_NumericRangeDimension *dimensions = NULL;
     UA_NumericRangeDimension *dimensions = NULL;
@@ -184,17 +182,23 @@ isNodeInTree(UA_NodeStore *ns, const UA_NodeId *leafNode, const UA_NodeId *nodeT
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-const UA_VariableTypeNode *
-getVariableType(UA_Server *server, const UA_VariableNode *node) {
+static const UA_Node *
+getNodeType(UA_Server *server, const UA_Node *node) {
     /* The reference to the parent is different for variable and variabletype */ 
     /* The reference to the parent is different for variable and variabletype */ 
     UA_NodeId parentRef;
     UA_NodeId parentRef;
     UA_Boolean inverse;
     UA_Boolean inverse;
-    if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+    if(node->nodeClass == UA_NODECLASS_VARIABLE ||
+       node->nodeClass == UA_NODECLASS_OBJECT) {
         parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         inverse = false;
         inverse = false;
-    } else { /* UA_NODECLASS_VARIABLETYPE */
+    } else if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
+              /* node->nodeClass == UA_NODECLASS_OBJECTTYPE || // objecttype may have multiple parents */
+              node->nodeClass == UA_NODECLASS_REFERENCETYPE ||
+              node->nodeClass == UA_NODECLASS_DATATYPE) {
         parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
         parentRef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
         inverse = true;
         inverse = true;
+    } else {
+        return NULL;
     }
     }
 
 
     /* stop at the first matching candidate */
     /* stop at the first matching candidate */
@@ -207,10 +211,40 @@ getVariableType(UA_Server *server, const UA_VariableNode *node) {
         }
         }
     }
     }
 
 
-    const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentId);
-    if(!parent || parent->nodeClass != UA_NODECLASS_VARIABLETYPE)
+    if(!parentId)
+        return NULL;
+    return UA_NodeStore_get(server->nodestore, parentId);
+}
+
+const UA_VariableTypeNode *
+getVariableNodeType(UA_Server *server, const UA_VariableNode *node) {
+    const UA_Node *type = getNodeType(server, (const UA_Node*)node);
+    if(!type || type->nodeClass != UA_NODECLASS_VARIABLETYPE)
         return NULL;
         return NULL;
-    return (const UA_VariableTypeNode*)parent;
+    return (const UA_VariableTypeNode*)type;
+}
+
+const UA_ObjectTypeNode *
+getObjectNodeType(UA_Server *server, const UA_ObjectNode *node) {
+    const UA_Node *type = getNodeType(server, (const UA_Node*)node);
+    if(type->nodeClass != UA_NODECLASS_OBJECTTYPE)
+        return NULL;
+    return (const UA_ObjectTypeNode*)type;
+}
+
+UA_Boolean
+UA_Node_hasSubTypeOrInstances(const UA_Node *node) {
+    const UA_NodeId hasSubType = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
+    const UA_NodeId hasTypeDefinition = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
+    for(size_t i = 0; i < node->referencesSize; i++) {
+        if(node->references[i].isInverse == false &&
+           UA_NodeId_equal(&node->references[i].referenceTypeId, &hasSubType))
+            return true;
+        if(node->references[i].isInverse == true &&
+           UA_NodeId_equal(&node->references[i].referenceTypeId, &hasTypeDefinition))
+            return true;
+    }
+    return false;
 }
 }
 
 
 /* For mulithreading: make a copy of the node, edit and replace.
 /* For mulithreading: make a copy of the node, edit and replace.

+ 160 - 29
src/server/ua_services_attribute.c

@@ -16,10 +16,9 @@ forceVariantSetScalar(UA_Variant *v, const void *p, const UA_DataType *t) {
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
-getVariableNodeValue(UA_Server *server, UA_Session *session,
-                     const UA_VariableNode *vn,
-                     const UA_TimestampsToReturn timestamps,
-                     const UA_ReadValueId *id, UA_DataValue *v) {
+getVariableNodeValue(UA_Server *server, UA_Session *session, const UA_VariableNode *vn,
+                     const UA_TimestampsToReturn timestamps, const UA_ReadValueId *id,
+                     UA_DataValue *v) {
     UA_NumericRange range;
     UA_NumericRange range;
     UA_NumericRange *rangeptr = NULL;
     UA_NumericRange *rangeptr = NULL;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
@@ -120,7 +119,7 @@ void Service_Read_single(UA_Server *server, UA_Session *session,
         return;
         return;
     }
     }
 
 
-    UA_Node const *node = UA_NodeStore_get(server->nodestore, &id->nodeId);
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &id->nodeId);
     if(!node) {
     if(!node) {
         v->hasStatus = true;
         v->hasStatus = true;
         v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
         v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
@@ -532,21 +531,26 @@ UA_Variant_matchVariableDefinition(UA_Server *server, const UA_NodeId *variableD
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static UA_StatusCode
-writeDataTypeAttribute(UA_Server *server, UA_VariableNode *node,
-                       const UA_NodeId *dataType) {
-    /* Get the variabletype */
-    const UA_VariableNode *vt = (const UA_VariableNode*)getVariableType(server, node);
-    if(!vt)
-        return UA_STATUSCODE_BADINTERNALERROR; /* should never happen */
+UA_StatusCode
+UA_VariableNode_setDataType(UA_Server *server, UA_VariableNode *node,
+                            const UA_VariableTypeNode *vt,
+                            const UA_NodeId *dataType) {
+    /* If this is a variabletype, there must be no instances or subtypes of it
+       when we do the change */
+    if(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
+       UA_Node_hasSubTypeOrInstances((const UA_Node*)node))
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Is the type abstract? */
+    if(vt->isAbstract)
+        return UA_STATUSCODE_BADTYPEMISMATCH;
 
 
     /* Does the new type match the constraints of the variabletype? */
     /* Does the new type match the constraints of the variabletype? */
     const UA_NodeId *vtDataType = &vt->dataType;
     const UA_NodeId *vtDataType = &vt->dataType;
     UA_NodeId subtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
     UA_NodeId subtypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
     UA_Boolean found = false;
     UA_Boolean found = false;
     UA_StatusCode retval = isNodeInTree(server->nodestore, dataType,
     UA_StatusCode retval = isNodeInTree(server->nodestore, dataType,
-                                        vtDataType, &subtypeId,
-                                        1, &found);
+                                        vtDataType, &subtypeId, 1, &found);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
     if(!found)
     if(!found)
@@ -572,8 +576,117 @@ writeDataTypeAttribute(UA_Server *server, UA_VariableNode *node,
 }
 }
 
 
 UA_StatusCode
 UA_StatusCode
-writeValueAttribute(UA_Server *server, UA_VariableNode *node,
-                    const UA_DataValue *value, const UA_String *indexRange) {
+UA_VariableNode_setValueRank(UA_Server *server, UA_VariableNode *node,
+                             const UA_VariableTypeNode *vt,
+                             const UA_Int32 valueRank) {
+    /* If this is a variabletype, there must be no instances or subtypes of it
+       when we do the change */
+    if(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
+       UA_Node_hasSubTypeOrInstances((const UA_Node*)node))
+        return UA_STATUSCODE_BADINTERNALERROR;
+    
+    /* Check if the valuerank of the type allows the change */
+    switch(vt->valueRank) {
+    case -3: /* the value can be a scalar or a one dimensional array */
+        if(valueRank != -1 && valueRank != 1)
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+        break;
+    case -2: /* the value can be a scalar or an array with any number of dimensions */
+        return UA_STATUSCODE_GOOD;
+    case -1: /* the value is a scalar */
+        return UA_STATUSCODE_BADTYPEMISMATCH;
+    case 0: /* the value is an array with one or more dimensions */
+        if(valueRank < 0)
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+        break;
+    default: /* >= 1: the value is an array with the specified number of dimensions */
+        return UA_STATUSCODE_BADTYPEMISMATCH;
+    }
+
+    /* Check if the current value is compatible with the valueRank */
+    if(node->value.data.value.hasValue) {
+        UA_StatusCode retval =
+            UA_Variant_matchVariableDefinition(server, &node->dataType, valueRank,
+                                               node->arrayDimensionsSize, node->arrayDimensions,
+                                               &node->value.data.value.value, NULL, NULL);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
+    /* Ok, apply */
+    node->valueRank = valueRank;
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+UA_VariableNode_setArrayDimensions(UA_Server *server, UA_VariableNode *node,
+                                   const UA_VariableTypeNode *vt,
+                                   size_t arrayDimensionsSize, UA_UInt32 *arrayDimensions) {
+    /* If this is a variabletype, there must be no instances or subtypes of it
+     * when we do the change */
+    if(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
+       UA_Node_hasSubTypeOrInstances((const UA_Node*)node))
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    /* Check if the array dimensions match with the valuerank */
+    switch(node->valueRank) {
+    case -3: /* the value can be a scalar or a one dimensional array */
+        if(arrayDimensionsSize > 1)
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+        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 UA_STATUSCODE_BADTYPEMISMATCH;
+        break;
+    case 0: /* the value is an array with one or more dimensions */
+        if(arrayDimensionsSize == 0)
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+        break;
+    default: /* >= 1: the value is an array with the specified number of dimensions */
+        if(node->valueRank < 0)
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+        if(arrayDimensionsSize != (size_t)node->valueRank)
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+    }
+
+    /* Check if the array dimensions match with the wildcards in the
+     * variabletype (dimension length 0) */
+    if(vt->arrayDimensions) {
+        if(vt->arrayDimensionsSize != arrayDimensionsSize)
+            return UA_STATUSCODE_BADTYPEMISMATCH;
+        for(size_t i = 0; i < arrayDimensionsSize; i++) {
+            if(vt->arrayDimensions[i] != 0 &&
+               vt->arrayDimensions[i] != arrayDimensions[i])
+                return UA_STATUSCODE_BADTYPEMISMATCH;
+        }
+    }
+
+    /* Check if the current value is compatible with the array dimensions */
+    UA_StatusCode retval;
+    if(node->value.data.value.hasValue) {
+        retval = UA_Variant_matchVariableDefinition(server, &node->dataType, node->valueRank,
+                                                    arrayDimensionsSize, arrayDimensions,
+                                                    &node->value.data.value.value, NULL, NULL);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
+    /* Ok, apply */
+    UA_UInt32 *oldArrayDimensions = node->arrayDimensions;
+    retval = UA_Array_copy(arrayDimensions, arrayDimensionsSize,
+                           (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    UA_free(oldArrayDimensions);
+    node->arrayDimensionsSize = arrayDimensionsSize;
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+UA_VariableNode_setValue(UA_Server *server, UA_VariableNode *node,
+                         const UA_DataValue *value, const UA_String *indexRange) {
     /* Parse the range */
     /* Parse the range */
     UA_NumericRange range;
     UA_NumericRange range;
     UA_NumericRange *rangeptr = NULL;
     UA_NumericRange *rangeptr = NULL;
@@ -742,24 +855,43 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
         break;
         break;
     case UA_ATTRIBUTEID_VALUE:
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = writeValueAttribute(server, (UA_VariableNode*)node, &wvalue->value, &wvalue->indexRange);
+        retval = UA_VariableNode_setValue(server, (UA_VariableNode*)node,
+                                          &wvalue->value, &wvalue->indexRange);
         break;
         break;
-    case UA_ATTRIBUTEID_DATATYPE:
+    case UA_ATTRIBUTEID_DATATYPE: {
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_DATATYPE(NODEID);
         CHECK_DATATYPE(NODEID);
-
-        retval = writeDataTypeAttribute(server, (UA_VariableNode*)node, (const UA_NodeId*)value);
-        break;
-    case UA_ATTRIBUTEID_VALUERANK:
+        const UA_VariableTypeNode *vt = getVariableNodeType(server, (UA_VariableNode*)node);
+        if(vt)
+            retval = UA_VariableNode_setDataType(server, (UA_VariableNode*)node,
+                                                 vt, (const UA_NodeId*)value);
+        else
+            retval = UA_STATUSCODE_BADINTERNALERROR;
+        break; }
+    case UA_ATTRIBUTEID_VALUERANK: {
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_DATATYPE(INT32);
         CHECK_DATATYPE(INT32);
-        /* TODO */
-        retval = UA_STATUSCODE_BADNOTWRITABLE;
-        break;
+        const UA_VariableTypeNode *vt = getVariableNodeType(server, (UA_VariableNode*)node);
+        if(vt)
+            retval = UA_VariableNode_setValueRank(server, (UA_VariableNode*)node,
+                                                  vt, *(const UA_Int32*)value);
+        else
+            retval = UA_STATUSCODE_BADINTERNALERROR;
+        break; }
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        /* TODO */
-        retval = UA_STATUSCODE_BADNOTWRITABLE;
+        CHECK_DATATYPE(UINT32);
+        if(!UA_Variant_isScalar(&wvalue->value.value)) {
+            const UA_VariableTypeNode *vt = getVariableNodeType(server, (UA_VariableNode*)node);
+            if(vt)
+                retval = UA_VariableNode_setArrayDimensions(server, (UA_VariableNode*)node,
+                                                            vt, wvalue->value.value.arrayLength,
+                                                            wvalue->value.value.data);
+            else
+                retval = UA_STATUSCODE_BADINTERNALERROR;
+        } else {
+            retval = UA_STATUSCODE_BADTYPEMISMATCH;
+        }
         break;
         break;
     case UA_ATTRIBUTEID_ACCESSLEVEL:
     case UA_ATTRIBUTEID_ACCESSLEVEL:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
@@ -877,8 +1009,7 @@ __UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
     wvalue.attributeId = attributeId;
     wvalue.attributeId = attributeId;
     if(attributeId != UA_ATTRIBUTEID_VALUE) {
     if(attributeId != UA_ATTRIBUTEID_VALUE) {
         /* hacked cast. the target WriteValue is used as const anyway */
         /* hacked cast. the target WriteValue is used as const anyway */
-        UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value,
-                             attr_type);
+        UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value, attr_type);
     } else {
     } else {
         if(attr_type != &UA_TYPES[UA_TYPES_VARIANT])
         if(attr_type != &UA_TYPES[UA_TYPES_VARIANT])
             return UA_STATUSCODE_BADTYPEMISMATCH;
             return UA_STATUSCODE_BADTYPEMISMATCH;

+ 64 - 32
src/server/ua_services_nodemanagement.c

@@ -428,8 +428,8 @@ instantiateVariableNode(UA_Server *server, UA_Session *session,
 static UA_StatusCode
 static UA_StatusCode
 copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item,
 copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item,
                        const UA_NodeAttributes *attr) {
                        const UA_NodeAttributes *attr) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
+    UA_StatusCode retval;
+    retval  = UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
     retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
     retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
     retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
     retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
     retval |= UA_LocalizedText_copy(&attr->description, &node->description);
     retval |= UA_LocalizedText_copy(&attr->description, &node->description);
@@ -441,21 +441,23 @@ copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item,
 static UA_StatusCode
 static UA_StatusCode
 copyCommonVariableAttributes(UA_Server *server, UA_VariableNode *node,
 copyCommonVariableAttributes(UA_Server *server, UA_VariableNode *node,
                              const UA_VariableAttributes *attr) {
                              const UA_VariableAttributes *attr) {
-    /* Set the constraints */
-    UA_StatusCode retval = UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
-                                         (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    node->arrayDimensionsSize = attr->arrayDimensionsSize;
-    retval = UA_NodeId_copy(&attr->dataType, &node->dataType);
-    node->valueRank = attr->valueRank;
+    const UA_VariableTypeNode *vt = getVariableNodeType(server, node);
+    if(!vt)
+        return UA_STATUSCODE_BADINTERNALERROR;
 
 
-    /* Set the value with the write service. This also checks the constraints. */
+    /* Set the constraints */
+    UA_StatusCode retval;
+    retval  = UA_VariableNode_setDataType(server, node, vt, &attr->dataType);
+    retval |= UA_VariableNode_setValueRank(server, node, vt, attr->valueRank);
+    retval |= UA_VariableNode_setArrayDimensions(server, node, vt,
+                                                 attr->arrayDimensionsSize,
+                                                 attr->arrayDimensions);
+    /* Set the value */
     UA_DataValue value;
     UA_DataValue value;
     UA_DataValue_init(&value);
     UA_DataValue_init(&value);
     value.value = attr->value;
     value.value = attr->value;
     value.hasValue = true;
     value.hasValue = true;
-    retval = writeValueAttribute(server, node, &value, NULL);
+    retval |= UA_VariableNode_setValue(server, node, &value, NULL);
     return retval;
     return retval;
 }
 }
 
 
@@ -692,6 +694,18 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
                                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                                     const UA_VariableAttributes attr, const UA_DataSource dataSource,
                                     const UA_VariableAttributes attr, const UA_DataSource dataSource,
                                     UA_NodeId *outNewNodeId) {
                                     UA_NodeId *outNewNodeId) {
+    /* replace null type with basedatavariabletype */
+    UA_NodeId basevartype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
+    const UA_NodeId *type = &typeDefinition;
+    if(UA_NodeId_isNull(&typeDefinition))
+        type = &basevartype;
+
+    /* get the datatype node */
+    const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)UA_NodeStore_get(server->nodestore, type);
+    if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE)
+        return UA_STATUSCODE_BADTYPEMISMATCH;
+
+    /* create the new node */
     UA_VariableNode *node = UA_NodeStore_newVariableNode();
     UA_VariableNode *node = UA_NodeStore_newVariableNode();
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -701,21 +715,31 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     UA_AddNodesItem_init(&item);
     UA_AddNodesItem_init(&item);
     item.requestedNewNodeId.nodeId = requestedNewNodeId;
     item.requestedNewNodeId.nodeId = requestedNewNodeId;
     item.browseName = browseName;
     item.browseName = browseName;
-    copyStandardAttributes((UA_Node*)node, &item, (const UA_NodeAttributes*)&attr);
-    node->valueSource = UA_VALUESOURCE_DATASOURCE;
-    node->value.dataSource = dataSource;
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)node, &item, (const UA_NodeAttributes*)&attr);
+
     node->accessLevel = attr.accessLevel;
     node->accessLevel = attr.accessLevel;
     node->userAccessLevel = attr.userAccessLevel;
     node->userAccessLevel = attr.userAccessLevel;
     node->historizing = attr.historizing;
     node->historizing = attr.historizing;
     node->minimumSamplingInterval = attr.minimumSamplingInterval;
     node->minimumSamplingInterval = attr.minimumSamplingInterval;
-    node->valueRank = attr.valueRank;
+    retval  = UA_VariableNode_setDataType(server, node, vt, &attr.dataType);
+    retval |= UA_VariableNode_setValueRank(server, node, vt, attr.valueRank);
+    retval |= UA_VariableNode_setArrayDimensions(server, node, vt,
+                                                 attr.arrayDimensionsSize,
+                                                 attr.arrayDimensions);
+    node->valueSource = UA_VALUESOURCE_DATASOURCE;
+    node->value.dataSource = dataSource;
+
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteMembersAnyNodeClass((UA_Node*)node);
+        return retval;
+    }
 
 
     /* Add the node */
     /* Add the node */
     UA_AddNodesResult result;
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
     UA_AddNodesResult_init(&result);
     UA_RCU_LOCK();
     UA_RCU_LOCK();
-    UA_StatusCode retval = Service_AddNodes_existing(server, &adminSession, (UA_Node*)node, &parentNodeId,
-                                                     &referenceTypeId, &typeDefinition, NULL, outNewNodeId);
+    retval = Service_AddNodes_existing(server, &adminSession, (UA_Node*)node, &parentNodeId,
+                                       &referenceTypeId, &typeDefinition, NULL, outNewNodeId);
     UA_RCU_UNLOCK();
     UA_RCU_UNLOCK();
     return retval;
     return retval;
 }
 }
@@ -756,7 +780,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 
 
     UA_NodeId *parent = &result.addedNodeId;
     UA_NodeId *parent = &result.addedNodeId;
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-    const UA_NodeId propertytype= UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE);
+    const UA_NodeId propertytype = UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE);
 
 
     if(inputArgumentsSize > 0) {
     if(inputArgumentsSize > 0) {
         UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
         UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
@@ -972,25 +996,16 @@ UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
 /* Delete Nodes */
 /* Delete Nodes */
 /****************/
 /****************/
 
 
-// TODO: Check consistency constraints, remove the references.
+static UA_StatusCode
+deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
+                      const UA_DeleteReferencesItem *item);
 
 
 UA_StatusCode
 UA_StatusCode
 Service_DeleteNodes_single(UA_Server *server, UA_Session *session,
 Service_DeleteNodes_single(UA_Server *server, UA_Session *session,
                            const UA_NodeId *nodeId, UA_Boolean deleteReferences) {
                            const UA_NodeId *nodeId, UA_Boolean deleteReferences) {
     const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
     const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
     if(!node)
     if(!node)
-        return UA_STATUSCODE_BADNODEIDINVALID;
-    if(deleteReferences == true) {
-        UA_DeleteReferencesItem delItem;
-        UA_DeleteReferencesItem_init(&delItem);
-        delItem.deleteBidirectional = false;
-        delItem.targetNodeId.nodeId = *nodeId;
-        for(size_t i = 0; i < node->referencesSize; i++) {
-            delItem.sourceNodeId = node->references[i].targetId.nodeId;
-            delItem.isForward = node->references[i].isInverse;
-            Service_DeleteReferences_single(server, session, &delItem);
-        }
-    }
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
 
     /* destroy an object before removing it */
     /* destroy an object before removing it */
     if(node->nodeClass == UA_NODECLASS_OBJECT) {
     if(node->nodeClass == UA_NODECLASS_OBJECT) {
@@ -1023,6 +1038,20 @@ Service_DeleteNodes_single(UA_Server *server, UA_Session *session,
         UA_BrowseResult_deleteMembers(&result);
         UA_BrowseResult_deleteMembers(&result);
     }
     }
 
 
+    /* remove references */
+    /* TODO: check if consistency is violated */
+    if(deleteReferences == true) { 
+        for(size_t i = 0; i < node->referencesSize; i++) {
+            UA_DeleteReferencesItem item;
+            UA_DeleteReferencesItem_init(&item);
+            item.isForward = node->references[i].isInverse;
+            item.sourceNodeId = node->references[i].targetId.nodeId;
+            item.targetNodeId.nodeId = node->nodeId;
+            UA_Server_editNode(server, session, &node->references[i].targetId.nodeId,
+                               (UA_EditNodeCallback)deleteOneWayReference, &item);
+        }
+    }
+
     return UA_NodeStore_remove(server->nodestore, nodeId);
     return UA_NodeStore_remove(server->nodestore, nodeId);
 }
 }
 
 
@@ -1063,6 +1092,7 @@ UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
 /* Delete References */
 /* Delete References */
 /*********************/
 /*********************/
 
 
+// TODO: Check consistency constraints, remove the references.
 static UA_StatusCode
 static UA_StatusCode
 deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
 deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
                       const UA_DeleteReferencesItem *item) {
                       const UA_DeleteReferencesItem *item) {
@@ -1096,6 +1126,8 @@ Service_DeleteReferences_single(UA_Server *server, UA_Session *session,
                                 const UA_DeleteReferencesItem *item) {
                                 const UA_DeleteReferencesItem *item) {
     UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
     UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
                                               (UA_EditNodeCallback)deleteOneWayReference, item);
                                               (UA_EditNodeCallback)deleteOneWayReference, item);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
     if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
     if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
         return retval;
         return retval;
     UA_DeleteReferencesItem secondItem;
     UA_DeleteReferencesItem secondItem;