Browse Source

add example with datasource

Julius Pfrommer 9 years ago
parent
commit
404992459b

+ 8 - 4
CMakeLists.txt

@@ -152,21 +152,25 @@ endif()
 # build example server
 # build example server
 option(EXAMPLESERVER "Build a test server" OFF)
 option(EXAMPLESERVER "Build a test server" OFF)
 if(EXAMPLESERVER)
 if(EXAMPLESERVER)
-set(server_sources examples/opcuaServer.c
-                   examples/networklayer_tcp.c
-                   examples/logger_stdout.c)
+set(server_sources examples/networklayer_tcp.c examples/logger_stdout.c)
 if(EXTENSION_UDP)
 if(EXTENSION_UDP)
 	list(APPEND server_sources examples/networklayer_udp.c)
 	list(APPEND server_sources examples/networklayer_udp.c)
 endif()
 endif()
-add_executable(exampleServer ${server_sources} ${exported_headers} ${generated_headers})
+add_executable(exampleServer examples/opcuaServer.c ${server_sources} ${exported_headers} ${generated_headers})
+add_executable(exampleServerDataSource examples/opcuaServerDataSource.c ${server_sources}
+                                       ${exported_headers} ${generated_headers})
 target_link_libraries(exampleServer open62541)
 target_link_libraries(exampleServer open62541)
+target_link_libraries(exampleServerDataSource open62541)
 if(WIN32)
 if(WIN32)
     target_link_libraries(exampleServer ws2_32)
     target_link_libraries(exampleServer ws2_32)
+    target_link_libraries(exampleServerDataSource ws2_32)
 else()
 else()
     target_link_libraries(exampleServer rt)
     target_link_libraries(exampleServer rt)
+    target_link_libraries(exampleServerDataSource rt)
 endif(WIN32)
 endif(WIN32)
 if(MULTITHREADING)
 if(MULTITHREADING)
     target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
     target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
+    target_link_libraries(exampleServerDataSource urcu-cds urcu urcu-common pthread)
 endif()
 endif()
 endif()
 endif()
 
 

+ 4 - 9
examples/opcuaServer.c

@@ -16,10 +16,6 @@
 // provided by the user, implementations available in the /examples folder
 // provided by the user, implementations available in the /examples folder
 #include "logger_stdout.h"
 #include "logger_stdout.h"
 #include "networklayer_tcp.h"
 #include "networklayer_tcp.h"
-#ifdef EXTENSION_UDP
-#include "networklayer_udp.h"
-#endif
-
 
 
 UA_Boolean running = 1;
 UA_Boolean running = 1;
 
 
@@ -63,16 +59,12 @@ int main(int argc, char** argv) {
 
 
 	UA_Server *server = UA_Server_new();
 	UA_Server *server = UA_Server_new();
     UA_Server_setServerCertificate(server, loadCertificate());
     UA_Server_setServerCertificate(server, loadCertificate());
-#ifdef EXTENSION_UDP
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664));
-#else
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-#endif
 
 
     UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = testCallback, .data = UA_NULL} };
     UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = testCallback, .data = UA_NULL} };
     UA_Server_addRepeatedWorkItem(server, &work, 20000000, UA_NULL); // call every 2 sec
     UA_Server_addRepeatedWorkItem(server, &work, 20000000, UA_NULL); // call every 2 sec
 
 
-	//add a node to the adresspace
+	// add a variable node to the adresspace
     UA_Int32 *myInteger = UA_Int32_new();
     UA_Int32 *myInteger = UA_Int32_new();
     *myInteger = 42;
     *myInteger = 42;
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Variant *myIntegerVariant = UA_Variant_new();
@@ -82,6 +74,9 @@ int main(int argc, char** argv) {
     UA_Server_addVariableNode(server, myIntegerVariant, &UA_NODEID_NULL, &myIntegerName,
     UA_Server_addVariableNode(server, myIntegerVariant, &UA_NODEID_NULL, &myIntegerName,
                               &UA_NODEID_STATIC(UA_NS0ID_OBJECTSFOLDER,0),
                               &UA_NODEID_STATIC(UA_NS0ID_OBJECTSFOLDER,0),
                               &UA_NODEID_STATIC(UA_NS0ID_ORGANIZES,0));
                               &UA_NODEID_STATIC(UA_NS0ID_ORGANIZES,0));
+
+    // add node with a callback to the userspace
+    
     
     
 #ifdef BENCHMARK
 #ifdef BENCHMARK
     UA_UInt32 nodeCount = 500;
     UA_UInt32 nodeCount = 500;

+ 73 - 0
examples/opcuaServerDataSource.c

@@ -0,0 +1,73 @@
+/*
+ * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ */
+#include <time.h>
+#include "ua_types.h"
+
+#include <stdio.h>
+#include <stdlib.h> 
+#include <signal.h>
+#include <errno.h> // errno, EINTR
+
+// provided by the open62541 lib
+#include "ua_server.h"
+
+// provided by the user, implementations available in the /examples folder
+#include "logger_stdout.h"
+#include "networklayer_tcp.h"
+
+// data source
+static UA_StatusCode readTimeData(const void *handle, UA_VariantData* data) {
+    UA_DateTime *time = UA_DateTime_new();
+    if(!time)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    *time = UA_DateTime_now();
+    data->arrayLength = 1;
+    data->dataPtr = time;
+    data->arrayDimensionsSize = -1;
+    data->arrayDimensions = UA_NULL;
+    return UA_STATUSCODE_GOOD;
+}
+
+static void releaseTimeData(const void *handle, UA_VariantData* data) {
+    UA_DateTime_delete((UA_DateTime*)data->dataPtr);
+}
+
+static void destroyTimeDataSource(const void *handle) {
+    return;
+}
+
+UA_Boolean running = 1;
+
+static void stopHandler(int sign) {
+    printf("Received Ctrl-C\n");
+	running = 0;
+}
+
+int main(int argc, char** argv) {
+	signal(SIGINT, stopHandler); /* catches ctrl-c */
+
+	UA_Server *server = UA_Server_new();
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+    // add node with a callback to the userspace
+    UA_Variant *myDateTimeVariant = UA_Variant_new();
+    myDateTimeVariant->storageType = UA_VARIANT_DATASOURCE;
+    myDateTimeVariant->storage.datasource = (UA_VariantDataSource)
+        {.handle = UA_NULL, .read = readTimeData, .release = releaseTimeData,
+         .write = (UA_StatusCode (*)(const void*, const UA_VariantData*))UA_NULL,
+         .destroy = destroyTimeDataSource};
+    myDateTimeVariant->type = &UA_TYPES[UA_TYPES_DATETIME];
+    myDateTimeVariant->typeId = UA_NODEID_STATIC(UA_TYPES_IDS[UA_TYPES_DATETIME],0);
+    UA_QualifiedName myDateTimeName;
+    UA_QUALIFIEDNAME_ASSIGN(myDateTimeName, "the time");
+    UA_Server_addVariableNode(server, myDateTimeVariant, &UA_NODEID_NULL, &myDateTimeName,
+                              &UA_NODEID_STATIC(UA_NS0ID_OBJECTSFOLDER,0),
+                              &UA_NODEID_STATIC(UA_NS0ID_ORGANIZES,0));
+
+    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+	UA_Server_delete(server);
+
+	return retval;
+}

+ 1 - 1
include/ua_server.h

@@ -242,7 +242,7 @@ typedef struct UA_ExternalNodeStore {
 	UA_ExternalNodeStore_browseNodes browseNodes;
 	UA_ExternalNodeStore_browseNodes browseNodes;
 	UA_ExternalNodeStore_addReferences addReferences;
 	UA_ExternalNodeStore_addReferences addReferences;
 	UA_ExternalNodeStore_deleteReferences deleteReferences;
 	UA_ExternalNodeStore_deleteReferences deleteReferences;
-	UA_ExternalNodeStore_delete deleteNodeStore;
+	UA_ExternalNodeStore_delete destroy;
 } UA_ExternalNodeStore;
 } UA_ExternalNodeStore;
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT

+ 4 - 4
include/ua_types.h

@@ -206,10 +206,10 @@ typedef struct {
  *  datasource is via the write-service. */
  *  datasource is via the write-service. */
 typedef struct {
 typedef struct {
     const void *handle;
     const void *handle;
-    UA_StatusCode (*read)(const void *handle, const UA_VariantData **);
-    void (*release)(const void *handle, const UA_VariantData *);
-    UA_StatusCode (*write)(const void **handle, const UA_VariantData *);
-    void (*free)(const void *handle);
+    UA_StatusCode (*read)(const void *handle, UA_VariantData *data);
+    void (*release)(const void *handle, UA_VariantData *data);
+    UA_StatusCode (*write)(const void *handle, const UA_VariantData *data);
+    void (*destroy)(const void *handle);
 } UA_VariantDataSource;
 } UA_VariantDataSource;
 
 
 struct UA_DataType;
 struct UA_DataType;

+ 0 - 19
src/server/ua_nodes.c

@@ -101,7 +101,6 @@ void UA_VariableNode_init(UA_VariableNode *p) {
 	UA_Node_init((UA_Node*)p);
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_VARIABLE;
     p->nodeClass = UA_NODECLASS_VARIABLE;
     UA_Variant_init(&p->value);
     UA_Variant_init(&p->value);
-    UA_NodeId_init(&p->dataType);
     p->valueRank = -2; // scalar or array of any dimension
     p->valueRank = -2; // scalar or array of any dimension
     p->accessLevel = 0;
     p->accessLevel = 0;
     p->userAccessLevel = 0;
     p->userAccessLevel = 0;
@@ -129,10 +128,7 @@ void UA_VariableNode_delete(UA_VariableNode *p) {
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
     UA_VariableNode_init(dst);
     UA_VariableNode_init(dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    if(retval)
-        return retval;
     retval = UA_Variant_copy(&src->value, &dst->value);
     retval = UA_Variant_copy(&src->value, &dst->value);
-    retval |= UA_NodeId_copy(&src->dataType, &dst->dataType);
     if(retval) {
     if(retval) {
         UA_VariableNode_deleteMembers(dst);
         UA_VariableNode_deleteMembers(dst);
         return retval;
         return retval;
@@ -149,10 +145,7 @@ void UA_VariableTypeNode_init(UA_VariableTypeNode *p) {
 	UA_Node_init((UA_Node*)p);
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_VARIABLETYPE;
     p->nodeClass = UA_NODECLASS_VARIABLETYPE;
     UA_Variant_init(&p->value);
     UA_Variant_init(&p->value);
-    UA_NodeId_init(&p->dataType);
     p->valueRank = 0;
     p->valueRank = 0;
-    p->arrayDimensionsSize = -1;
-    p->arrayDimensions = UA_NULL;
     p->isAbstract = UA_FALSE;
     p->isAbstract = UA_FALSE;
 }
 }
 
 
@@ -166,8 +159,6 @@ UA_VariableTypeNode * UA_VariableTypeNode_new(void) {
 void UA_VariableTypeNode_deleteMembers(UA_VariableTypeNode *p) {
 void UA_VariableTypeNode_deleteMembers(UA_VariableTypeNode *p) {
     UA_Node_deleteMembers((UA_Node*)p);
     UA_Node_deleteMembers((UA_Node*)p);
     UA_Variant_deleteMembers(&p->value);
     UA_Variant_deleteMembers(&p->value);
-    UA_Array_delete(p->arrayDimensions, p->arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
-    p->arrayDimensionsSize = -1;
 }
 }
 
 
 void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
 void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
@@ -178,21 +169,11 @@ void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
 UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) {
 UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) {
     UA_VariableTypeNode_init(dst);
     UA_VariableTypeNode_init(dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    if(retval)
-        return retval;
     retval = UA_Variant_copy(&src->value, &dst->value);
     retval = UA_Variant_copy(&src->value, &dst->value);
-    retval |= UA_NodeId_copy(&src->dataType, &dst->dataType);
-    if(retval) {
-        UA_VariableTypeNode_deleteMembers(dst);
-        return retval;
-    }
-    retval = UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize, (void**)&dst->arrayDimensions,
-                           &UA_TYPES[UA_TYPES_UINT32]);
     if(retval) {
     if(retval) {
         UA_VariableTypeNode_deleteMembers(dst);
         UA_VariableTypeNode_deleteMembers(dst);
         return retval;
         return retval;
     }
     }
-    dst->arrayDimensionsSize = src->arrayDimensionsSize;
     dst->isAbstract = src->isAbstract;
     dst->isAbstract = src->isAbstract;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }

+ 4 - 5
src/server/ua_nodes.h

@@ -34,13 +34,13 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 typedef struct {
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
     UA_Variant value;
     UA_Variant value;
-    UA_NodeId dataType;
+    // datatype is taken from the value
     UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
     UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
                              n = 0: the value is an array with one or more dimensions.
                              n = 0: the value is an array with one or more dimensions.
                              n = -1: the value is a scalar.
                              n = -1: the value is a scalar.
                              n = -2: the value can be a scalar or an array with any number of dimensions.
                              n = -2: the value can be a scalar or an array with any number of dimensions.
                              n = -3:  the value can be a scalar or a one dimensional array. */
                              n = -3:  the value can be a scalar or a one dimensional array. */
-    // Array Dimensions taken from the value-variant
+    // array dimensions are taken from the value-variant
     UA_Byte accessLevel;
     UA_Byte accessLevel;
     UA_Byte userAccessLevel;
     UA_Byte userAccessLevel;
     UA_Double minimumSamplingInterval;
     UA_Double minimumSamplingInterval;
@@ -51,10 +51,9 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_VariableNode)
 typedef struct {
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
     UA_Variant value;
     UA_Variant value;
-    UA_NodeId dataType;
+    // datatype is taken from the value
     UA_Int32 valueRank;
     UA_Int32 valueRank;
-    UA_Int32 arrayDimensionsSize;
-    UA_UInt32 *arrayDimensions;
+    // array dimensions are taken from the value-variant
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
 } UA_VariableTypeNode;
 } UA_VariableTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)
 UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)

+ 1 - 2
src/server/ua_server.c

@@ -22,7 +22,7 @@ static void UA_ExternalNamespace_init(UA_ExternalNamespace *ens) {
 
 
 static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
 static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
 	UA_String_deleteMembers(&ens->url);
 	UA_String_deleteMembers(&ens->url);
-    ens->externalNodeStore.delete(ens->externalNodeStore.ensHandle);
+    ens->externalNodeStore.destroy(ens->externalNodeStore.ensHandle);
 }
 }
 
 
 /*****************/
 /*****************/
@@ -481,7 +481,6 @@ UA_Server * UA_Server_new(void) {
                           &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[0]);
                           &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[0]);
     UA_String_copycstring("urn:myServer:myApplication",
     UA_String_copycstring("urn:myServer:myApplication",
                           &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[1]);
                           &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[1]);
-    namespaceArray->dataType.identifier.numeric = UA_TYPES_IDS[UA_TYPES_STRING];
     namespaceArray->valueRank = 1;
     namespaceArray->valueRank = 1;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->historizing = UA_FALSE;
     namespaceArray->historizing = UA_FALSE;

+ 31 - 10
src/server/ua_services_attribute.c

@@ -40,8 +40,9 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
         break;
         break;
 
 
     case UA_ATTRIBUTEID_DISPLAYNAME:
     case UA_ATTRIBUTEID_DISPLAYNAME:
-        v->hasVariant = UA_TRUE;
         retval |= UA_Variant_copySetValue(&v->value, &node->displayName, UA_TYPES_LOCALIZEDTEXT);
         retval |= UA_Variant_copySetValue(&v->value, &node->displayName, UA_TYPES_LOCALIZEDTEXT);
+        if(retval == UA_STATUSCODE_GOOD)
+            v->hasVariant = UA_TRUE;
         break;
         break;
 
 
     case UA_ATTRIBUTEID_DESCRIPTION:
     case UA_ATTRIBUTEID_DESCRIPTION:
@@ -56,8 +57,7 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
 
 
     case UA_ATTRIBUTEID_USERWRITEMASK:
     case UA_ATTRIBUTEID_USERWRITEMASK:
         v->hasVariant = UA_TRUE;
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &node->userWriteMask,
-                                          UA_TYPES_UINT32);
+        retval |= UA_Variant_copySetValue(&v->value, &node->userWriteMask, UA_TYPES_UINT32);
         break;
         break;
 
 
     case UA_ATTRIBUTEID_ISABSTRACT:
     case UA_ATTRIBUTEID_ISABSTRACT:
@@ -98,14 +98,15 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
 
 
     case UA_ATTRIBUTEID_VALUE:
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copy(&((const UA_VariableNode *)node)->value, &v->value); // todo: zero-copy
+        retval = UA_Variant_copy(&((const UA_VariableNode *)node)->value, &v->value);
+        if(retval == UA_STATUSCODE_GOOD)
+            v->hasVariant = UA_TRUE;
         break;
         break;
 
 
     case UA_ATTRIBUTEID_DATATYPE:
     case UA_ATTRIBUTEID_DATATYPE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         v->hasVariant = UA_TRUE;
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableTypeNode *)node)->dataType,
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableTypeNode *)node)->value.typeId,
                                           UA_TYPES_NODEID);
                                           UA_TYPES_NODEID);
         break;
         break;
 
 
@@ -118,9 +119,25 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
 
 
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->hasVariant = UA_TRUE;
-        UA_Variant_copySetArray(&v->value, &((const UA_VariableTypeNode *)node)->arrayDimensions,
-                                ((const UA_VariableTypeNode *)node)->arrayDimensionsSize, UA_TYPES_UINT32);
+        {
+            const UA_VariantData *data = UA_NULL;
+            UA_VariantData datasourceData;
+            const UA_VariableNode *vn = (const UA_VariableNode *)node;
+            if(vn->value.storageType == UA_VARIANT_DATA || vn->value.storageType == UA_VARIANT_DATA_NODELETE)
+                data = &vn->value.storage.data;
+            else {
+                if((retval = vn->value.storage.datasource.read(vn->value.storage.datasource.handle,
+                                                               &datasourceData)) != UA_STATUSCODE_GOOD)
+                    break;
+                data = &datasourceData;
+            }
+            retval = UA_Variant_copySetArray(&v->value, data->arrayDimensions, data->arrayDimensionsSize,
+                                             UA_TYPES_INT32);
+            if(retval == UA_STATUSCODE_GOOD)
+                v->hasVariant = UA_TRUE;
+            if(vn->value.storageType == UA_VARIANT_DATASOURCE)
+                vn->value.storage.datasource.release(vn->value.storage.datasource.handle, &datasourceData);
+        }
         break;
         break;
 
 
     case UA_ATTRIBUTEID_ACCESSLEVEL:
     case UA_ATTRIBUTEID_ACCESSLEVEL:
@@ -172,7 +189,11 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
     }
     }
 
 
     UA_NodeStore_release(node);
     UA_NodeStore_release(node);
-
+#include "stdio.h"
+    if(v->hasVariant && v->value.type == UA_NULL) {
+        printf("%i", id->attributeId);
+        UA_assert(UA_FALSE);
+    }
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         v->hasStatus = UA_TRUE;
         v->hasStatus = UA_TRUE;
         v->status = UA_STATUSCODE_BADNOTREADABLE;
         v->status = UA_STATUSCODE_BADNOTREADABLE;

+ 6 - 5
src/server/ua_services_nodemanagement.c

@@ -63,11 +63,12 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     /*     attr.arrayDimensions = UA_NULL; */
     /*     attr.arrayDimensions = UA_NULL; */
     /* } */
     /* } */
 
 
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE ||
-       attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) {
-        vnode->dataType = attr.dataType;
-        UA_NodeId_init(&attr.dataType);
-    }
+    // don't use the extra type id. This comes from the value.
+    /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE || */
+    /*    attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) { */
+    /*     vnode->dataType = attr.dataType; */
+    /*     UA_NodeId_init(&attr.dataType); */
+    /* } */
 
 
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
         vnode->value = attr.value;
         vnode->value = attr.value;

+ 33 - 46
src/ua_types.c

@@ -504,7 +504,7 @@ UA_StatusCode UA_LocalizedText_copycstring(char const *src, UA_LocalizedText *ds
 }
 }
 
 
 UA_StatusCode UA_LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst) {
 UA_StatusCode UA_LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst) {
-    UA_Int32 retval = UA_String_copy(&src->locale, &dst->locale);
+    UA_StatusCode retval = UA_String_copy(&src->locale, &dst->locale);
     retval |= UA_String_copy(&src->text, &dst->text);
     retval |= UA_String_copy(&src->text, &dst->text);
     if(retval)
     if(retval)
         UA_LocalizedText_deleteMembers(dst);
         UA_LocalizedText_deleteMembers(dst);
@@ -579,66 +579,51 @@ void UA_Variant_init(UA_Variant *p) {
 
 
 UA_TYPE_DELETE_DEFAULT(UA_Variant)
 UA_TYPE_DELETE_DEFAULT(UA_Variant)
 void UA_Variant_deleteMembers(UA_Variant *p) {
 void UA_Variant_deleteMembers(UA_Variant *p) {
+    UA_NodeId_deleteMembers(&p->typeId);
     if(p->storageType == UA_VARIANT_DATA) {
     if(p->storageType == UA_VARIANT_DATA) {
         if(p->storage.data.dataPtr) {
         if(p->storage.data.dataPtr) {
             UA_Array_delete(p->storage.data.dataPtr, p->storage.data.arrayLength, p->type);
             UA_Array_delete(p->storage.data.dataPtr, p->storage.data.arrayLength, p->type);
             p->storage.data.dataPtr = UA_NULL;
             p->storage.data.dataPtr = UA_NULL;
             p->storage.data.arrayLength = 0;
             p->storage.data.arrayLength = 0;
         }
         }
-
         if(p->storage.data.arrayDimensions) {
         if(p->storage.data.arrayDimensions) {
             UA_free(p->storage.data.arrayDimensions);
             UA_free(p->storage.data.arrayDimensions);
             p->storage.data.arrayDimensions = UA_NULL;
             p->storage.data.arrayDimensions = UA_NULL;
         }
         }
-        return;
-    }
-
-    UA_NodeId_deleteMembers(&p->typeId);
-
-    if(p->storageType == UA_VARIANT_DATASOURCE) {
-        p->storage.datasource.delete(p->storage.datasource.handle);
+    } else if(p->storageType == UA_VARIANT_DATASOURCE) {
+        p->storage.datasource.destroy(p->storage.datasource.handle);
     }
     }
 }
 }
 
 
-
-/** This function performs a deep copy. The resulting StorageType is UA_VARIANT_DATA. */
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
     UA_Variant_init(dst);
     UA_Variant_init(dst);
-    /* 1) Uniform access to the data */
-    UA_VariantData *dstdata = &dst->storage.data;
-    const UA_VariantData *srcdata;
-
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    if(src->storageType == UA_VARIANT_DATA || src->storageType == UA_VARIANT_DATA_NODELETE)
-        srcdata = &src->storage.data;
-    else {
-        retval |= src->storage.datasource.read(src->storage.datasource.handle, &srcdata);
-        if(retval)
-            return retval;
+    UA_StatusCode retval = UA_NodeId_copy(&src->typeId, &dst->typeId);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    dst->type = src->type;
+    if(src->storageType == UA_VARIANT_DATASOURCE) {
+        dst->storageType = UA_VARIANT_DATASOURCE;
+        dst->storage = src->storage;
+        return UA_STATUSCODE_GOOD;
     }
     }
-
-    /* 2) Copy the data to the destination */
+    
+    UA_VariantData *dstdata = &dst->storage.data;
+    const UA_VariantData *srcdata = &src->storage.data;
+    dst->storageType = UA_VARIANT_DATA;
     retval |= UA_Array_copy(srcdata->dataPtr, srcdata->arrayLength, &dstdata->dataPtr, src->type);
     retval |= UA_Array_copy(srcdata->dataPtr, srcdata->arrayLength, &dstdata->dataPtr, src->type);
-    if(retval == UA_STATUSCODE_GOOD) {
-        dst->storageType = UA_VARIANT_DATA;
-        dst->type= src->type;
-        UA_NodeId_copy(&src->typeId, &dst->typeId);
-        dstdata->arrayLength = srcdata->arrayLength;
-        if(srcdata->arrayDimensions) {
-            retval |= UA_Array_copy(srcdata->arrayDimensions, srcdata->arrayDimensionsSize,
-                                    (void **)&dstdata->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
-            if(retval == UA_STATUSCODE_GOOD)
-                dstdata->arrayDimensionsSize = srcdata->arrayDimensionsSize;
-            else {
-                UA_Variant_deleteMembers(dst);
-                UA_Variant_init(dst);
-            }
-        }
-    } 
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Variant_deleteMembers(dst);
+        return retval;
+    }
+    dstdata->arrayLength = srcdata->arrayLength;
 
 
-    /* 3) Release the data source if necessary */
-    if(src->storageType == UA_VARIANT_DATASOURCE)
-        src->storage.datasource.release(src->storage.datasource.handle, srcdata);
+    if(srcdata->arrayDimensions) {
+        retval |= UA_Array_copy(srcdata->arrayDimensions, srcdata->arrayDimensionsSize,
+                                (void **)&dstdata->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
+        if(retval != UA_STATUSCODE_GOOD)
+            UA_Variant_deleteMembers(dst);
+    }
+    dstdata->arrayDimensionsSize = srcdata->arrayDimensionsSize;
 
 
     return retval;
     return retval;
 }
 }
@@ -650,8 +635,11 @@ UA_StatusCode UA_Variant_setValue(UA_Variant *v, void *p, UA_UInt16 typeIndex) {
 UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const void *p, UA_UInt16 typeIndex) {
 UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const void *p, UA_UInt16 typeIndex) {
     if(typeIndex >= UA_TYPES_COUNT)
     if(typeIndex >= UA_TYPES_COUNT)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
-    void *new;
-    UA_StatusCode retval = UA_copy(p, &new, &UA_TYPES[typeIndex]);
+    const UA_DataType *type = &UA_TYPES[typeIndex];
+    void *new = UA_malloc(type->memSize);
+    if(!new)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    UA_StatusCode retval = UA_copy(p, new, &UA_TYPES[typeIndex]);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
     return UA_Variant_setArray(v, new, 1, typeIndex);
     return UA_Variant_setArray(v, new, 1, typeIndex);
@@ -662,7 +650,6 @@ UA_StatusCode UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElement
     if(typeIndex >= UA_TYPES_COUNT)
     if(typeIndex >= UA_TYPES_COUNT)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
 
 
-    UA_Variant_deleteMembers(v);
     v->type = &UA_TYPES[typeIndex];
     v->type = &UA_TYPES[typeIndex];
     v->typeId = UA_NODEID_STATIC(UA_TYPES_IDS[typeIndex], 0);
     v->typeId = UA_NODEID_STATIC(UA_TYPES_IDS[typeIndex], 0);
     v->storage.data.arrayLength = noElements;
     v->storage.data.arrayLength = noElements;

+ 24 - 22
src/ua_types_encoding_binary.c

@@ -680,53 +680,55 @@ enum UA_VARIANT_ENCODINGMASKTYPE_enum {
 };
 };
 
 
 size_t UA_Variant_calcSizeBinary(UA_Variant const *p) {
 size_t UA_Variant_calcSizeBinary(UA_Variant const *p) {
-    UA_UInt32 arrayLength;
-    const UA_VariantData *data;
-    if(!p->type)
+    if(p->type == UA_NULL) // type is not set after init
         return 0;
         return 0;
-    if(p->storageType == UA_VARIANT_DATA)
+    const UA_VariantData *data;
+    UA_VariantData datasourceData;
+    if(p->storageType == UA_VARIANT_DATA || p->storageType == UA_VARIANT_DATA_NODELETE)
         data = &p->storage.data;
         data = &p->storage.data;
     else {
     else {
-        if(p->storage.datasource.read(p->storage.datasource.handle, &data) != UA_STATUSCODE_GOOD)
+        if(p->storage.datasource.read(p->storage.datasource.handle, &datasourceData) != UA_STATUSCODE_GOOD)
             return 0;
             return 0;
+        data = &datasourceData;
     }
     }
 
 
-    arrayLength = data->arrayLength;
-    if(data->dataPtr == UA_NULL)
-        arrayLength = -1;
-
     size_t length = sizeof(UA_Byte); //p->encodingMask
     size_t length = sizeof(UA_Byte); //p->encodingMask
-    if(arrayLength < 1) {
-        length += 4; // length
-    } else {
-        if(arrayLength > 1)
-            length += UA_Array_calcSizeBinary(data->dataPtr, arrayLength, p->type);
-        else
-            length += UA_calcSizeBinary(data->dataPtr, p->type);
-        // if the type is not builtin, we encode it as an extensionobject
-        if(!p->type->namespaceZero || p->type->typeIndex > 24)
-            length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte encoding + 4 byte bytestring length
+    UA_Int32 arrayLength = data->arrayLength;
+    if(arrayLength <= 0 || data->dataPtr == UA_NULL) {
+        length += 4;
+        arrayLength = 0; // for adding the extensionobject overhead...
     }
     }
+    else if(arrayLength == 1)
+        length += UA_calcSizeBinary(data->dataPtr, p->type);
+    else
+        length += UA_Array_calcSizeBinary(data->dataPtr, arrayLength, p->type);
+        
+    // if the type is not builtin, we encode it as an extensionobject
+    if(p->type->typeIndex > 24 || !p->type->namespaceZero)
+        length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
+                                    // encoding + 4 byte bytestring length
 
 
     if(arrayLength != 1 && data->arrayDimensions != UA_NULL)
     if(arrayLength != 1 && data->arrayDimensions != UA_NULL)
         length += UA_Array_calcSizeBinary(data->arrayDimensions, data->arrayDimensionsSize,
         length += UA_Array_calcSizeBinary(data->arrayDimensions, data->arrayDimensionsSize,
                                           &UA_TYPES[UA_TYPES_INT32]);
                                           &UA_TYPES[UA_TYPES_INT32]);
     
     
     if(p->storageType == UA_VARIANT_DATASOURCE)
     if(p->storageType == UA_VARIANT_DATASOURCE)
-        p->storage.datasource.release(p->storage.datasource.handle, data);
+        p->storage.datasource.release(p->storage.datasource.handle, &datasourceData);
 
 
     return length;
     return length;
 }
 }
 
 
 UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst, size_t *offset) {
 UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst, size_t *offset) {
     const UA_VariantData  *data;
     const UA_VariantData  *data;
+    UA_VariantData datasourceData;
     if(!src->type)
     if(!src->type)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     if(src->storageType == UA_VARIANT_DATA)
     if(src->storageType == UA_VARIANT_DATA)
         data = &src->storage.data;
         data = &src->storage.data;
     else {
     else {
-        if(src->storage.datasource.read(src->storage.datasource.handle, &data) != UA_STATUSCODE_GOOD)
+        if(src->storage.datasource.read(src->storage.datasource.handle, &datasourceData) != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADENCODINGERROR;
             return UA_STATUSCODE_BADENCODINGERROR;
+        data = &datasourceData;
     }
     }
     
     
     UA_Byte encodingByte = 0;
     UA_Byte encodingByte = 0;
@@ -768,7 +770,7 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
                                         &UA_TYPES[UA_TYPES_INT32], dst, offset);
                                         &UA_TYPES[UA_TYPES_INT32], dst, offset);
 
 
     if(src->storageType == UA_VARIANT_DATASOURCE)
     if(src->storageType == UA_VARIANT_DATASOURCE)
-        src->storage.datasource.release(src->storage.datasource.handle, data);
+        src->storage.datasource.release(src->storage.datasource.handle, &datasourceData);
                      
                      
     return retval;
     return retval;
 }
 }

+ 1 - 1
tests/check_memory.c

@@ -194,7 +194,7 @@ int main(void) {
 	suite_add_tcase(s, tc);
 	suite_add_tcase(s, tc);
 
 
 	sr = srunner_create(s);
 	sr = srunner_create(s);
-	//srunner_set_fork_status(sr, CK_NOFORK);
+	srunner_set_fork_status(sr, CK_NOFORK);
 	srunner_run_all (sr, CK_NORMAL);
 	srunner_run_all (sr, CK_NORMAL);
 	number_failed += srunner_ntests_failed(sr);
 	number_failed += srunner_ntests_failed(sr);
 	srunner_free(sr);
 	srunner_free(sr);