Преглед на файлове

finish refactoring the write service

Julius Pfrommer преди 9 години
родител
ревизия
de60618406
променени са 6 файла, в които са добавени 183 реда и са изтрити 210 реда
  1. 3 3
      examples/server.c
  2. 33 34
      include/ua_server.h
  3. 17 16
      src/server/ua_nodes.c
  4. 35 9
      src/server/ua_server_addressspace.c
  5. 89 148
      src/server/ua_services_attribute.c
  6. 6 0
      tests/check_services_attributes.c

+ 3 - 3
examples/server.c

@@ -233,11 +233,11 @@ int main(int argc, char** argv) {
 
   // Get and reattach the datasource
   UA_DataSource dataSourceCopy;
-  UA_Server_getNodeAttribute_valueDataSource(server, nodeId_currentTime, &dataSourceCopy);
+  UA_Server_getNodeAttribute_value_dataSource(server, nodeId_currentTime, &dataSourceCopy);
   if (dataSourceCopy.read != dateDataSource.read)
     UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "The returned dataSource is not the same as we set?");
   else
-    UA_Server_setNodeAttribute_valueDataSource(server, nodeId_currentTime, dataSourceCopy);
+    UA_Server_setNodeAttribute_value_dataSource(server, nodeId_currentTime, dataSourceCopy);
 #ifndef _WIN32
   //cpu temperature monitoring for linux machines
   if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))) {
@@ -388,7 +388,7 @@ int main(int argc, char** argv) {
   
   // Some easy localization
   UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("de_DE", "Objekte");
-  UA_Server_setNodeAttribute_displayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
+  UA_Server_setNodeAttribute_displayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), &objectsName);
   
   //start server
   UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false

+ 33 - 34
include/ua_server.h

@@ -279,23 +279,25 @@ UA_StatusCode UA_EXPORT UA_Server_forEachChildNodeCall(UA_Server *server, UA_Nod
 /* Set Node Attributes */
 /***********************/
 
-/* The variant is being deleteMembered internally. May save some cycles since we don't copy the attribute. */
-UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttributeDestructive(UA_Server *server, const UA_NodeId nodeId,
-                                      const UA_AttributeId attributeId, UA_Variant *value);
-
 /* Don't use. There are typed versions of this function with no additional overhead.  */
 UA_StatusCode UA_EXPORT
 UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId,
-                           UA_DataType *type, const void *value);
+                           const UA_DataType *type, const void *value);
+
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeAttribute_value_dataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource dataSource);
+
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeAttribute_value(UA_Server *server, const UA_NodeId nodeId,
+                                 const UA_DataType *type, const UA_Variant *value);
+
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeAttribute_value_destructive(UA_Server *server, const UA_NodeId nodeId,
+                                             const UA_DataType *type, UA_Variant *value);
 
 #define UA_SERVER_SETNODEATTRIBUTE_DECL(ATTRIBUTE, ATTRIBUTEID, TYPE, TYPEINDEX)	\
-  static UA_INLINE UA_StatusCode UA_Server_setNodeAttribute_##ATTRIBUTE(UA_Server *server, const UA_NodeId nodeId, const TYPE value) { \
-	/* hack to cast to void*. but is treated as const internally. */	\
-	const UA_Variant var = {.type = &UA_TYPES[TYPEINDEX], .storageType = UA_VARIANT_DATA, \
-							.arrayLength = -1, .data = (void *)(uintptr_t)&value,	\
-							.arrayDimensionsSize = -1, .arrayDimensions = NULL};       \
-	return UA_Server_setNodeAttribute(server, nodeId, ATTRIBUTEID, var);                  \
+    static UA_INLINE UA_StatusCode UA_Server_setNodeAttribute_##ATTRIBUTE(UA_Server *server, const UA_NodeId nodeId, const TYPE *value) { \
+      return UA_Server_setNodeAttribute(server, nodeId, ATTRIBUTEID, &UA_TYPES[TYPEINDEX], value); \
   }
 
 UA_SERVER_SETNODEATTRIBUTE_DECL(nodeId, UA_ATTRIBUTEID_NODEID, UA_NodeId, UA_TYPES_NODEID)
@@ -310,7 +312,7 @@ UA_SERVER_SETNODEATTRIBUTE_DECL(symmetric, UA_ATTRIBUTEID_SYMMETRIC, UA_Boolean,
 UA_SERVER_SETNODEATTRIBUTE_DECL(inverseName, UA_ATTRIBUTEID_INVERSENAME, UA_LocalizedText, UA_TYPES_LOCALIZEDTEXT)
 UA_SERVER_SETNODEATTRIBUTE_DECL(containsNoLoops, UA_ATTRIBUTEID_CONTAINSNOLOOPS, UA_Boolean, UA_TYPES_BOOLEAN)
 UA_SERVER_SETNODEATTRIBUTE_DECL(eventNotifier, UA_ATTRIBUTEID_EVENTNOTIFIER, UA_Byte, UA_TYPES_BYTE)
-#define UA_Server_setNodeAttribute_value(server, nodeId, value) UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, value)
+// UA_SERVER_SETNODEATTRIBUTE_DECL(value, UA_ATTRIBUTEID_VALUE, UA_Variant, UA_TYPES_VARIANT) // use custom functions
 // UA_SERVER_SETNODEATTRIBUTE_DECL(dataType, UA_ATTRIBUTEID_DATATYPE, UA_NodeId, UA_TYPES_NODEID) // not supported. set via the value variant.
 // UA_SERVER_SETNODEATTRIBUTE_DECL(valueRank, UA_ATTRIBUTEID_VALUERANK, UA_Int32, UA_TYPES_INT32) // not supported. set via the value variant.
 // UA_SERVER_SETNODEATTRIBUTE_DECL(arrayDimensions, UA_ATTRIBUTEID_ARRAYDIMENSIONS, UA_Int32, UA_TYPES_INT32) // not supported. set via the value variant.
@@ -327,9 +329,6 @@ UA_Server_setNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId,
                                   UA_MethodCallback method, void *handle);
 #endif
 
-UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource dataSource);
-
 /***********************/
 /* Get Node Attributes */
 /***********************/
@@ -338,61 +337,61 @@ UA_StatusCode UA_EXPORT
 UA_Server_getNodeAttribute(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, UA_Variant *v);
 
 UA_StatusCode UA_EXPORT
-UA_Server_getNodeAttributeUnpacked(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void *v);
+UA_Server_getNodeAttribute_unboxed(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void *v);
   
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_nodeId(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outNodeId) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_nodeClass(UA_Server *server, UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_browseName(UA_Server *server, UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_displayName(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_description(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDescription) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
 
 // #define UA_Server_getNodeAttribute_writeMask(SERVER, NODEID, VALUE) UA_Server_getNodeAttribute(SERVER, NODEID, UA_ATTRIBUTEID_WRITEMASK, (UA_UInt32 **) VALUE);
 // #define UA_Server_getNodeAttribute_userWriteMask(SERVER, NODEID, VALUE) UA_Server_getNodeAttribute(SERVER, NODEID, UA_ATTRIBUTEID_USERWRITEMASK, (UA_UInt32 **) VALUE);
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_isAbstract(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_symmetric(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outSymmetric) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_inverseName(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_containsNoLoops(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_eventNotifier(UA_Server *server, UA_NodeId nodeId, UA_Byte *outEventNotifier) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_value(UA_Server *server, UA_NodeId nodeId, UA_Variant *outValue) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_dataType(UA_Server *server, UA_NodeId nodeId, UA_Variant *outDataType) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_valueRank(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outValueRank) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_arrayDimensions(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outArrayDimensions) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
 
 // #define UA_Server_getNodeAttribute_accessLevel(SERVER, NODEID, VALUE) UA_Server_getNodeAttribute(SERVER, NODEID, UA_ATTRIBUTEID_ACCESSLEVEL, (UA_UInt32 **) VALUE);
 // #define UA_Server_getNodeAttribute_userAccessLevel(SERVER, NODEID, VALUE) UA_Server_getNodeAttribute(SERVER, NODEID, UA_ATTRIBUTEID_USERACCESSLEVEL, (UA_UInt32 **) VALUE);
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_minimumSamplingInterval(UA_Server *server, UA_NodeId nodeId, UA_Double *outMinimumSamplingInterval) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, outMinimumSamplingInterval); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, outMinimumSamplingInterval); }
 
 static UA_INLINE UA_StatusCode UA_Server_getNodeAttribute_historizing(UA_Server *server, UA_NodeId nodeId, UA_Double *outHistorizing) {
-    return UA_Server_getNodeAttributeUnpacked(server, nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
+    return UA_Server_getNodeAttribute_unboxed(server, nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
 
 // #define UA_Server_getNodeAttribute_executable(SERVER, NODEID, VALUE) UA_Server_getNodeAttribute(SERVER, NODEID, UA_ATTRIBUTEID_EXECUTABLE, (UA_Boolean **) VALUE);
 // #define UA_Server_getNodeAttribute_userExecutable(SERVER, NODEID, VALUE) UA_Server_getNodeAttribute(SERVER, NODEID, UA_ATTRIBUTEID_USEREXECUTABLE, (UA_Boolean **) VALUE);
@@ -403,7 +402,7 @@ UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_
 #endif
 
 UA_StatusCode UA_EXPORT
-UA_Server_getNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource *dataSource);
+UA_Server_getNodeAttribute_value_dataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource *dataSource);
 
 /** Jobs describe work that is executed once or repeatedly. */
 typedef struct {

+ 17 - 16
src/server/ua_nodes.c

@@ -42,28 +42,28 @@ static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 
 void UA_Node_deleteAnyNodeClass(UA_Node *node) {
     switch(node->nodeClass) {
-    UA_NODECLASS_OBJECT:
+    case UA_NODECLASS_OBJECT:
         UA_ObjectNode_delete((UA_ObjectNode*)node);
         break;
-    UA_NODECLASS_VARIABLE:
+    case UA_NODECLASS_VARIABLE:
         UA_VariableNode_delete((UA_VariableNode*)node);
         break;
-    UA_NODECLASS_METHOD:
+    case UA_NODECLASS_METHOD:
         UA_MethodNode_delete((UA_MethodNode*)node);
         break;
-    UA_NODECLASS_OBJECTTYPE:
+    case UA_NODECLASS_OBJECTTYPE:
         UA_ObjectTypeNode_delete((UA_ObjectTypeNode*)node);
         break;
-    UA_NODECLASS_VARIABLETYPE:
+    case UA_NODECLASS_VARIABLETYPE:
         UA_VariableTypeNode_delete((UA_VariableTypeNode*)node);
         break;
-    UA_NODECLASS_REFERENCETYPE:
+    case UA_NODECLASS_REFERENCETYPE:
         UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode*)node);
         break;
-    UA_NODECLASS_DATATYPE:
+    case UA_NODECLASS_DATATYPE:
         UA_DataTypeNode_delete((UA_DataTypeNode*)node);
         break;
-    UA_NODECLASS_VIEW:
+    case UA_NODECLASS_VIEW:
         UA_ViewNode_delete((UA_ViewNode*)node);
         break;
     default:
@@ -81,48 +81,49 @@ UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node) {
     UA_DeleteNodeFunction deleteNode;
 
     switch(node->nodeClass) {
-    UA_NODECLASS_OBJECT:
+    case UA_NODECLASS_OBJECT:
         newNode = (UA_NewNodeFunction)UA_ObjectNode_new;
         copyNode = (UA_CopyNodeFunction)UA_ObjectNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_ObjectNode_delete;
         break;
-    UA_NODECLASS_VARIABLE:
+    case UA_NODECLASS_VARIABLE:
         newNode = (UA_NewNodeFunction)UA_VariableNode_new;
         copyNode = (UA_CopyNodeFunction)UA_VariableNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_VariableNode_delete;
         break;
-    UA_NODECLASS_METHOD:
+    case UA_NODECLASS_METHOD:
         newNode = (UA_NewNodeFunction)UA_MethodNode_new;
         copyNode = (UA_CopyNodeFunction)UA_MethodNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_MethodNode_delete;
         break;
-    UA_NODECLASS_OBJECTTYPE:
+    case UA_NODECLASS_OBJECTTYPE:
         newNode = (UA_NewNodeFunction)UA_ObjectTypeNode_new;
         copyNode = (UA_CopyNodeFunction)UA_ObjectTypeNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_ObjectTypeNode_delete;
         break;
-    UA_NODECLASS_VARIABLETYPE:
+    case UA_NODECLASS_VARIABLETYPE:
         newNode = (UA_NewNodeFunction)UA_VariableTypeNode_new;
         copyNode = (UA_CopyNodeFunction)UA_VariableTypeNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_VariableTypeNode_delete;
         break;
-    UA_NODECLASS_REFERENCETYPE:
+    case UA_NODECLASS_REFERENCETYPE:
         newNode = (UA_NewNodeFunction)UA_ReferenceTypeNode_new;
         copyNode = (UA_CopyNodeFunction)UA_ReferenceTypeNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_ReferenceTypeNode_delete;
         break;
-    UA_NODECLASS_DATATYPE:
+    case UA_NODECLASS_DATATYPE:
         newNode = (UA_NewNodeFunction)UA_DataTypeNode_new;
         copyNode = (UA_CopyNodeFunction)UA_DataTypeNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_DataTypeNode_delete;
         break;
-    UA_NODECLASS_VIEW:
+    case UA_NODECLASS_VIEW:
         newNode = (UA_NewNodeFunction)UA_ViewNode_new;
         copyNode = (UA_CopyNodeFunction)UA_ViewNode_copy;
         deleteNode = (UA_DeleteNodeFunction)UA_ViewNode_delete;
         break;
     default:
         return UA_NULL;
+        break;
     }
 
     UA_Node *copy = newNode();

+ 35 - 9
src/server/ua_server_addressspace.c

@@ -761,9 +761,12 @@ UA_StatusCode UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId node
     UA_WriteValue_init(&wvalue);
     wvalue.nodeId = nodeId;
     wvalue.attributeId = attributeId;
-    UA_Variant_setScalar(&wvalue.value.value, type, value);
+    UA_Variant_setScalarCopy(&wvalue.value.value, type, value);
     wvalue.value.hasValue = UA_TRUE;
-    return Service_Write_single(server, &adminSession, &wvalue);
+    UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
+    UA_NodeId_init(&wvalue.nodeId);
+    UA_WriteValue_deleteMembers(&wvalue);
+    return retval;
 }
 
 UA_StatusCode UA_Server_setNodeAttribute_value(UA_Server *server, const UA_NodeId nodeId,
@@ -771,10 +774,31 @@ UA_StatusCode UA_Server_setNodeAttribute_value(UA_Server *server, const UA_NodeI
     UA_WriteValue wvalue;
     UA_WriteValue_init(&wvalue);
     wvalue.nodeId = nodeId;
-    wvalue.attributeId = attributeId;
+    wvalue.attributeId = UA_ATTRIBUTEID_VALUE;
+    UA_StatusCode retval = UA_Variant_copy(value, &wvalue.value.value);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    wvalue.value.hasValue = UA_TRUE;
+    retval = Service_Write_single(server, &adminSession, &wvalue);
+    UA_NodeId_init(&wvalue.nodeId);
+    UA_WriteValue_deleteMembers(&wvalue);
+    return retval;
+}
+
+UA_StatusCode
+UA_Server_setNodeAttribute_value_destructive(UA_Server *server, const UA_NodeId nodeId,
+                                             const UA_DataType *type, UA_Variant *value) {
+    UA_WriteValue wvalue;
+    UA_WriteValue_init(&wvalue);
+    wvalue.nodeId = nodeId;
+    wvalue.attributeId = UA_ATTRIBUTEID_VALUE;
     wvalue.value.value = *value;
+    UA_Variant_init(value);
     wvalue.value.hasValue = UA_TRUE;
-    return Service_Write_single(server, &adminSession, &wvalue);
+    UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
+    UA_NodeId_init(&wvalue.nodeId);
+    UA_WriteValue_deleteMembers(&wvalue);
+    return retval;
 }
 
 #ifdef ENABLE_METHODCALLS
@@ -814,7 +838,7 @@ UA_Server_setNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_
 #endif
 
 UA_StatusCode
-UA_Server_setNodeAttribute_valueDataSource(UA_Server *server, const UA_NodeId nodeId, UA_DataSource dataSource) {
+UA_Server_setNodeAttribute_value_dataSource(UA_Server *server, const UA_NodeId nodeId, UA_DataSource dataSource) {
     const UA_Node *orig;
  retrySetDataSource:
     orig = UA_NodeStore_get(server->nodestore, &nodeId);
@@ -869,7 +893,9 @@ UA_Server_getNodeAttribute(UA_Server *server, const UA_NodeId nodeId,
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_Server_getNodeAttributeUnpacked(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId, void *v) {
+UA_StatusCode
+UA_Server_getNodeAttribute_unboxed(UA_Server *server, const UA_NodeId nodeId,
+                                   const UA_AttributeId attributeId, void *v) {
     UA_Variant out;
     UA_Variant_init(&out);
     UA_StatusCode retval = UA_Server_getNodeAttribute(server, nodeId, attributeId, &out); 
@@ -893,19 +919,19 @@ UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId nodeId, UA_Method
     if(!node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
     
-    if(node.anyNode->nodeClass != UA_NODECLASS_METHOD) {
+    if(node->nodeClass != UA_NODECLASS_METHOD) {
         UA_NodeStore_release(node);
         return UA_STATUSCODE_BADNODECLASSINVALID;
     }
 
-    *method = ((UA_MethodNode*)node)->attachToMethod;
+    *method = ((const UA_MethodNode*)node)->attachedMethod;
     UA_NodeStore_release(node);
     return UA_STATUSCODE_GOOD;
 }
 #endif
 
 UA_StatusCode
-UA_Server_getNodeAttribute_valueDataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource *dataSource) {
+UA_Server_getNodeAttribute_value_dataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource *dataSource) {
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, &nodeId);
     if(!node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;

+ 89 - 148
src/server/ua_services_attribute.c

@@ -168,13 +168,10 @@ static const UA_String xmlEncoding = {sizeof("DefaultXml")-1, (UA_Byte*)"Default
 /** Reads a single attribute from a node in the nodestore. */
 void Service_Read_single(UA_Server *server, UA_Session *session, const UA_TimestampsToReturn timestamps,
                          const UA_ReadValueId *id, UA_DataValue *v) {
-	if(id->dataEncoding.name.length >= 0) {
-		if(!UA_String_equal(&binEncoding, &id->dataEncoding.name) &&
-           !UA_String_equal(&xmlEncoding, &id->dataEncoding.name)) {
-			v->hasStatus = UA_TRUE;
-			v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
-			return;
-		}
+	if(id->dataEncoding.name.length >= 0 && !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
+           v->hasStatus = UA_TRUE;
+           v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
+           return;
 	}
 
 	//index range for a non-value
@@ -403,28 +400,6 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 /* Write Attribute */
 /*******************/
 
-/**
- * Ownership of data during writing
- *
- * The content of the UA_WriteValue can be moved into the new variable. Not copied. But we need to
- * make sure, that we don't free the data when the updated node points to it. This means resetting
- * the wvalue.value.
- *
- * 1. Clone the node
- * 2. Move the new data into the node by overwriting. Do not deep-copy.
- * 3. Insert the updated node.
- * 3.1 If this fails, we reset the part of the node that points to the new data and retry
- * 3.2 If this succeeds, the data ownership has moved, _init the wvalue.value
- */
-
-typedef void (*initWriteValueContent)(void *value);
-typedef void (*resetMovedData)(UA_Node *node);
-static void resetBrowseName(UA_Node *node) { UA_QualifiedName_init(&editable->browseName); }
-static void resetDisplayName(UA_Node *node) { UA_LocalizedText_init(&editable->displayName); }
-static void resetDescription(UA_Node *node) { UA_LocalizedText_init(&editable->description); }
-static void resetInverseName(UA_Node *node) { UA_LocalizedText_init(&editable->inverseName); }
-static void resetValue(UA_Node *node) { UA_Variant_init(&((UA_VariableNode*)editable)->value.variant); }
-
 #define CHECK_DATATYPE(EXP_DT)                                          \
     if(!wvalue->value.hasValue ||                                       \
        &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type ||      \
@@ -434,20 +409,46 @@ static void resetValue(UA_Node *node) { UA_Variant_init(&((UA_VariableNode*)edit
     }
 
 #define CHECK_NODECLASS_WRITE(CLASS)                                    \
-    if((editable->nodeClass & (CLASS)) == 0) {                          \
+    if((copy->nodeClass & (CLASS)) == 0) {                              \
         retval = UA_STATUSCODE_BADNODECLASSINVALID;                     \
         break;                                                          \
     }
 
 static UA_StatusCode
-Service_Write_single_Value(UA_Server *server, const UA_VariableNode *node, UA_Session *session,
-                           UA_WriteValue *wvalue, UA_Node **outEditable) {
+Service_Write_single_ValueDataSource(UA_Server *server, UA_Session *session, const UA_VariableNode *node,
+                                     UA_WriteValue *wvalue) {
+    UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
+    UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
+    UA_assert(node->valueSource == UA_VALUESOURCE_DATASOURCE);
+
+    UA_StatusCode retval;
+    if(wvalue->indexRange.length <= 0) {
+        retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId,
+                                              &wvalue->value.value, UA_NULL);
+    } else {
+        UA_NumericRange range;
+        retval = parse_numericrange(wvalue->indexRange, &range);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId,
+                                              &wvalue->value.value, &range);
+        UA_free(range.dimensions);
+    }
+    return retval;
+}
+
+/* In the multithreaded case, node is a copy */
+static UA_StatusCode
+Service_Write_single_Value(UA_Server *server, UA_Session *session, UA_VariableNode *node,
+                           UA_WriteValue *wvalue) {
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
-    UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || orig->nodeClass == UA_NODECLASS_VARIABLETYPE);
+    UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
+    UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT);
 
     /* Parse the range */
     UA_Boolean hasRange = UA_FALSE;
     UA_NumericRange range;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(wvalue->indexRange.length > 0) {
         retval = parse_numericrange(wvalue->indexRange, &range);
         if(retval != UA_STATUSCODE_GOOD)
@@ -455,45 +456,13 @@ Service_Write_single_Value(UA_Server *server, const UA_VariableNode *node, UA_Se
         hasRange = UA_TRUE;
     }
 
-    /* Writing into a datasource does not require copying the node */
-    if(node->dataSource == UA_VALUESOURCE_DATASOURCE) {
-        if(!hasRange)
-            retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId, newV, UA_NULL);
-        else
-            retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId, newV, &range);
-        goto clean_up;
-    }
-
-    UA_VariableNode *editable = UA_NULL;
-#ifndef UA_MULTITHREADING
-    editable = (UA_VariableNode*)(uintptr_t)node;
-#else
-    /* Copy the node without the actual value */
-    if(node->nodeClass == UA_NODECLASS_VARIABLE) {
-        editable = UA_VariableNode_new();
-        if(!editable) {
-            retval = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto clean_up;
-        }
-        UA_memcpy(editable, node, sizeof(UA_VariableNode));
-    } else {
-        editable = (UA_VariableNode*)UA_VariableTypeNode_new();
-        if(!editable) {
-            retval = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto clean_up;
-        }
-        UA_memcpy(editable, node, sizeof(UA_VariableTypeNode));
-    }
-    UA_Variant_init(&editable->value.variant);
-#endif
-
     /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings.
-       newV contains the correct type definition. */
+       nodeV contains the correct type definition. */
     UA_Variant *newV = &wvalue->value.value;
     UA_Variant *oldV = &node->value.variant;
     UA_Variant cast_v;
     if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
-        cast_v = *wvalue.value.value;
+        cast_v = wvalue->value.value;
         newV = &cast_v;
         if(oldV->type->namespaceZero && newV->type->namespaceZero &&
            oldV->type->typeIndex == newV->type->typeIndex) {
@@ -508,48 +477,23 @@ Service_Write_single_Value(UA_Server *server, const UA_VariableNode *node, UA_Se
             newV->data = str->data;
             newV->type = &UA_TYPES[UA_TYPES_BYTE];
         } else {
-            retval = UA_STATUSCODE_BADTYPEMISMATCH;
-            goto clean_up;
+            if(hasRange)
+                UA_free(range.dimensions);
+            return UA_STATUSCODE_BADTYPEMISMATCH;
         }
     }
-
     
-#ifndef UA_MULTITHREADING
     if(!hasRange) {
-        /* Move the data pointer */
-        UA_Variant_deleteMembers(&editable->value.variant);
-        editable->value.variant = *newV;
+        // TODO: Avoid copying the whole node and then delete the old value for multithreading
+        UA_Variant_deleteMembers(&node->value.variant);
+        node->value.variant = *newV;
+        UA_Variant_init(&wvalue->value.value);
     } else {
-        retval = UA_Variant_setRange(&editable->value.variant, newV->data, newV->arrayLength, range);
-        UA_free(newV->data);
-    }
-    /* Init the wvalue. We won't have to retry. */
-    UA_Variant_init(&wvalue->value);
-#else
-    if(!hasRange) {
-        /* Move data pointer. The wvalue will be _inited only when the node was successfully replaced. */
-        editable->value.variant = *newV;
-    } else {
-        /* Copy the old variant. Then copy the new value inside */
-        retval = UA_Variant_copy(&node->value.variant, editable->value.variant);
-        if(retval != UA_STATUSCODE_GOOD)
-            goto clean_up;
-        retval = UA_Variant_setRange(&editable->value.variant, newV->data, newV->arrayLength, range);
+        retval = UA_Variant_setRangeCopy(&node->value.variant, newV->data, newV->arrayLength, range);
     }
-#endif
 
- clean_up:
     if(hasRange)
         UA_free(range.dimensions);
-#ifndef UA_MULTITHREADING
-    *outEditable = UA_NULL;
-#else
-    if(!retval == UA_STATUSCODE_GOOD && editable) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)editable);
-        editable = UA_NULL;
-    }
-    *outEditable = editable;
-#endif
     return retval;
 }
 
@@ -557,36 +501,27 @@ UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_Wr
     if(!wvalue->value.hasValue || !wvalue->value.value.data)
         return UA_STATUSCODE_BADNODATA; // TODO: is this the right return code?
     const UA_Node *orig;
+    UA_StatusCode retval;
 
  retryWriteSingle:
+    retval = UA_STATUSCODE_GOOD;
     orig = UA_NodeStore_get(server->nodestore, &wvalue->nodeId);
     if(!orig)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_Node *editable = UA_NULL;
-    if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE &&
-       (orig->nodeClass == UA_NODECLASS_VARIABLE || orig->nodeClass == UA_NODECLASS_VARIABLETYPE)) {
-        /* sets editable if we need to replace a node. Otherwise we can return.  */
-        retval = Service_Write_single_Value(server, orig, session, wvalue, &editable);
-        if(!editable) {
-            UA_NodeStore_release(orig);
-            return retval;
-        }
+    if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE && 
+       orig->nodeClass & (UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLE) &&
+       ((const UA_VariableNode*)orig)->valueSource == UA_VALUESOURCE_DATASOURCE) {
+        return Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)orig, wvalue);
     }
-
-    initWriteValue init = UA_NULL;
+    
 #ifndef UA_MULTITHREADING
-    /* We cheat if multithreading is not enabled and treat the node as mutable. */
-    /* for setting a variable value (non-multithreaded) we never arrive here. */
-    editable = (UA_Node*)(uintptr_t)orig;
+    UA_Node *copy = (UA_Node*)(uintptr_t)orig;
 #else
-    if(!editable) {
-        editable = UA_Node_copyAnyNodeClass(orig);
-        if(!editable) {
-            UA_NodeStore_release(orig);
-            return UA_STATUSCODE_BADOUTOFMEMORY;
-        }
+    UA_Node *copy = UA_Node_copyAnyNodeClass(orig);
+    if(!copy) {
+        UA_NodeStore_release(orig);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 #endif
 
@@ -599,110 +534,116 @@ UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_Wr
 		break;
 	case UA_ATTRIBUTEID_BROWSENAME:
 		CHECK_DATATYPE(QUALIFIEDNAME);
-		UA_QualifiedName_deleteMembers(&editable->browseName);
-        editable->browseName = *(UA_QualifiedName*)value;
+		UA_QualifiedName_deleteMembers(&copy->browseName);
+        copy->browseName = *(UA_QualifiedName*)value;
+        UA_QualifiedName_init((UA_QualifiedName*)value);
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-		UA_LocalizedText_deleteMembers(&editable->displayName);
-		UA_LocalizedText_copy((UA_LocalizedText*)value, &editable->displayName);
+		UA_LocalizedText_deleteMembers(&copy->displayName);
+        copy->displayName = *(UA_LocalizedText*)value;
+		UA_LocalizedText_init((UA_LocalizedText*)value);
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-		UA_LocalizedText_deleteMembers(&editable->description);
-		UA_LocalizedText_copy((UA_LocalizedText*)value, &editable->description);
+		UA_LocalizedText_deleteMembers(&copy->description);
+        copy->description = *(UA_LocalizedText*)value;
+		UA_LocalizedText_init((UA_LocalizedText*)value);
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
 		CHECK_DATATYPE(UINT32);
-		editable->writeMask = *(UA_UInt32*)value;
+		copy->writeMask = *(UA_UInt32*)value;
 		break;
 	case UA_ATTRIBUTEID_USERWRITEMASK:
 		CHECK_DATATYPE(UINT32);
-		editable->userWriteMask = *(UA_UInt32*)value;
+		copy->userWriteMask = *(UA_UInt32*)value;
 		break;    
 	case UA_ATTRIBUTEID_ISABSTRACT:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_REFERENCETYPE |
                               UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
 		CHECK_DATATYPE(BOOLEAN);
-		((UA_ObjectTypeNode*)editable)->isAbstract = *(UA_Boolean*)value;
+		((UA_ObjectTypeNode*)copy)->isAbstract = *(UA_Boolean*)value;
 		break;
 	case UA_ATTRIBUTEID_SYMMETRIC:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_DATATYPE(BOOLEAN);
-		((UA_ReferenceTypeNode*)editable)->symmetric = *(UA_Boolean*)value;
+		((UA_ReferenceTypeNode*)copy)->symmetric = *(UA_Boolean*)value;
 		break;
 	case UA_ATTRIBUTEID_INVERSENAME:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-        UA_ReferenceTypeNode *n = (UA_ReferenceTypeNode*)editable;
+        UA_ReferenceTypeNode *n = (UA_ReferenceTypeNode*)copy;
 		UA_LocalizedText_deleteMembers(&n->inverseName);
-		UA_LocalizedText_copy((UA_LocalizedText*)value, &n->inverseName);
+        n->inverseName = *(UA_LocalizedText*)value;
+		UA_LocalizedText_init((UA_LocalizedText*)value);
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
 		CHECK_DATATYPE(BOOLEAN);
-        ((UA_ViewNode*)editable)->containsNoLoops = *(UA_Boolean*)value;
+        ((UA_ViewNode*)copy)->containsNoLoops = *(UA_Boolean*)value;
 		break;
 	case UA_ATTRIBUTEID_EVENTNOTIFIER:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
 		CHECK_DATATYPE(BYTE);
-        ((UA_ViewNode*)editable)->eventNotifier = *(UA_Byte*)value;
+        ((UA_ViewNode*)copy)->eventNotifier = *(UA_Byte*)value;
 		break;
 	case UA_ATTRIBUTEID_VALUE:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = copyValueIntoNode((UA_VariableNode*)editable, wvalue);
+        retval = Service_Write_single_Value(server, session, (UA_VariableNode*)copy, wvalue);
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
 		CHECK_DATATYPE(BYTE);
-		((UA_VariableNode*)editable)->accessLevel = *(UA_Byte*)value;
+		((UA_VariableNode*)copy)->accessLevel = *(UA_Byte*)value;
 		break;
 	case UA_ATTRIBUTEID_USERACCESSLEVEL:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
 		CHECK_DATATYPE(BYTE);
-		((UA_VariableNode*)editable)->userAccessLevel = *(UA_Byte*)value;
+		((UA_VariableNode*)copy)->userAccessLevel = *(UA_Byte*)value;
 		break;
 	case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
 		CHECK_DATATYPE(DOUBLE);
-		((UA_VariableNode*)editable)->minimumSamplingInterval = *(UA_Double*)value;
+		((UA_VariableNode*)copy)->minimumSamplingInterval = *(UA_Double*)value;
 		break;
 	case UA_ATTRIBUTEID_HISTORIZING:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
 		CHECK_DATATYPE(BOOLEAN);
-		((UA_VariableNode*)editable)->historizing = *(UA_Boolean*)value;
+		((UA_VariableNode*)copy)->historizing = *(UA_Boolean*)value;
 		break;
 	case UA_ATTRIBUTEID_EXECUTABLE:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
 		CHECK_DATATYPE(BOOLEAN);
-		((UA_MethodNode*)editable)->executable = *(UA_Boolean*)value;
+		((UA_MethodNode*)copy)->executable = *(UA_Boolean*)value;
 		break;
 	case UA_ATTRIBUTEID_USEREXECUTABLE:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
 		CHECK_DATATYPE(BOOLEAN);
-		((UA_MethodNode*)editable)->userExecutable = *(UA_Boolean*)value;
+		((UA_MethodNode*)copy)->userExecutable = *(UA_Boolean*)value;
 		break;
 	default:
 		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 	}
 
-#ifndef UA_MULTITHREADING
-    UA_NodeStore_release(orig);
-#else
+#ifdef UA_MULTITHREADING
     if(retval != UA_STATUSCODE_GOOD) {
         UA_NodeStore_release(orig);
-        UA_Node_deleteAnyNodeClass(editable);
+        UA_Node_deleteAnyNodeClass(copy);
         return retval;
     }
+#endif
        
-    retval = UA_NodeStore_replace(server->nodestore, orig, editable, UA_NULL);
+#ifdef UA_MULTITHREADING
+    retval = UA_NodeStore_replace(server->nodestore, orig, copy, UA_NULL);
 	UA_NodeStore_release(orig);
     if(retval != UA_STATUSCODE_GOOD) {
         /* The node was replaced under our feet. Retry. */
-        UA_Node_deleteAnyNodeClass(editable);
+        UA_Node_deleteAnyNodeClass(copy);
         goto retryWriteSingle;
     }
+#else
+	UA_NodeStore_release(orig);
 #endif
 	return retval;
 }

+ 6 - 0
tests/check_services_attributes.c

@@ -545,9 +545,11 @@ START_TEST(WriteSingleAttributeNodeId) {
 		UA_Server *server = makeTestSequence();
 		UA_WriteValue wValue;
 		UA_WriteValue_init(&wValue);
+        UA_NodeId *id = UA_NodeId_new();
 		wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
 		wValue.attributeId = UA_ATTRIBUTEID_NODEID;
 		wValue.value.hasValue = UA_TRUE;
+        UA_Variant_setScalar(&wValue.value.value, id, &UA_TYPES[UA_TYPES_NODEID]);
 		UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
 		ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
         UA_Server_delete(server);
@@ -558,8 +560,10 @@ START_TEST(WriteSingleAttributeNodeclass) {
 		UA_WriteValue wValue;
 		UA_WriteValue_init(&wValue);
 		wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
+        UA_NodeClass *class = UA_NodeClass_new();
 		wValue.attributeId = UA_ATTRIBUTEID_NODECLASS;
 		wValue.value.hasValue = UA_TRUE;
+        UA_Variant_setScalar(&wValue.value.value, class, &UA_TYPES[UA_TYPES_NODECLASS]);
 		UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
 		ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
         UA_Server_delete(server);
@@ -741,9 +745,11 @@ START_TEST(WriteSingleAttributeDataType) {
 		UA_Server *server = makeTestSequence();
 		UA_WriteValue wValue;
 		UA_WriteValue_init(&wValue);
+        UA_NodeId *typeId = UA_NodeId_new();
 		wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
 		wValue.attributeId = UA_ATTRIBUTEID_DATATYPE;
 		wValue.value.hasValue = UA_TRUE;
+        UA_Variant_setScalar(&wValue.value.value, typeId, &UA_TYPES[UA_TYPES_NODEID]);
 		UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
 		ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
         UA_Server_delete(server);