Ver código fonte

Merge pull request #378 from acplt/inline_setattribute

use inline methods for type safety; userspace functions call the normal services internally
Julius Pfrommer 9 anos atrás
pai
commit
999205c795

+ 4 - 5
CMakeLists.txt

@@ -43,7 +43,7 @@ endif()
 if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
 if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
     add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat -Wno-unused-parameter
     add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat -Wno-unused-parameter
                       -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
                       -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
-                      -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wshadow -Wconversion
+                      -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes #-Wshadow #-Wconversion
                       -Winit-self -Wuninitialized -Wformat-security -Wformat-nonliteral)
                       -Winit-self -Wuninitialized -Wformat-security -Wformat-nonliteral)
     # binary size reduction settings
     # binary size reduction settings
     add_definitions(-ffunction-sections -fdata-sections -fno-stack-protector -fno-unwind-tables
     add_definitions(-ffunction-sections -fdata-sections -fno-stack-protector -fno-unwind-tables
@@ -113,7 +113,6 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
                 ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
                 ${PROJECT_SOURCE_DIR}/src/ua_session.c
                 ${PROJECT_SOURCE_DIR}/src/ua_session.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_server_addressspace.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_binary.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_binary.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_worker.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_worker.c
@@ -234,9 +233,9 @@ if(ENABLE_EXTERNAL_NAMESPACES)
 endif()
 endif()
 
 
 ## enable dynamic nodeset
 ## enable dynamic nodeset
-option(ENABLE_ADDNODES "Enable dynamic addition of nodes" ON)
-if(ENABLE_ADDNODES)
-    add_definitions(-DENABLE_ADDNODES )
+option(ENABLE_NODEMANAGEMENT "Enable dynamic addition and removal of nodes" ON)
+if(ENABLE_NODEMANAGEMENT)
+    add_definitions(-DENABLE_NODEMANAGEMENT)
 endif()
 endif()
 
 
 ## set the precompiler flags
 ## set the precompiler flags

+ 2 - 2
doc/building.rst

@@ -119,8 +119,8 @@ ENABLE_* group
 
 
 This group contains build options related to the supported OPC UA features.
 This group contains build options related to the supported OPC UA features.
 
 
-**ENABLE_ADDNODES**
-   AddNodes services in sever and client
+**ENABLE_NODEMANAGEMENT**
+   Node management services (adding and removing nodes and references) in server and client
 **ENABLE_AMALGAMATION**
 **ENABLE_AMALGAMATION**
    Compile a single-file release files open62541.c and open62541.h
    Compile a single-file release files open62541.c and open62541.h
 **ENABLE_COVERAGE**
 **ENABLE_COVERAGE**

+ 1 - 1
examples/client.c

@@ -157,7 +157,7 @@ int main(int argc, char *argv[]) {
 
 
 #endif
 #endif
 
 
-#ifdef ENABLE_ADDNODES 
+#ifdef ENABLE_NODEMANAGEMENT 
     /* Create a new object type node */
     /* Create a new object type node */
     // New ReferenceType
     // New ReferenceType
     UA_AddNodesResponse *adResp = UA_Client_createReferenceTypeNode(client,
     UA_AddNodesResponse *adResp = UA_Client_createReferenceTypeNode(client,

+ 2 - 0
examples/networklayer_tcp.c

@@ -384,6 +384,8 @@ static size_t ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job
 }
 }
 
 
 static size_t ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
 static size_t ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
+    shutdown(layer->serversockfd,2);
+    CLOSESOCKET(layer->serversockfd);
     UA_Job *items = malloc(sizeof(UA_Job) * layer->mappingsSize * 2);
     UA_Job *items = malloc(sizeof(UA_Job) * layer->mappingsSize * 2);
     if(!items)
     if(!items)
         return 0;
         return 0;

+ 242 - 213
examples/server.c

@@ -46,7 +46,9 @@ UA_Logger logger;
 /*************************/
 /*************************/
 /* Read-only data source */
 /* Read-only data source */
 /*************************/
 /*************************/
-static UA_StatusCode readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
+static UA_StatusCode
+readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
+             const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
     if(range) {
         value->hasStatus = UA_TRUE;
         value->hasStatus = UA_TRUE;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
@@ -72,7 +74,9 @@ static UA_StatusCode readTimeData(void *handle, const UA_NodeId nodeId, UA_Boole
 /*      Only on Linux        */
 /*      Only on Linux        */
 /*****************************/
 /*****************************/
 FILE* temperatureFile = NULL;
 FILE* temperatureFile = NULL;
-static UA_StatusCode readTemperature(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
+static UA_StatusCode
+readTemperature(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
+                const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
     if(range) {
         value->hasStatus = UA_TRUE;
         value->hasStatus = UA_TRUE;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
@@ -115,24 +119,29 @@ FILE* triggerFile = NULL;
 FILE* ledFile = NULL;
 FILE* ledFile = NULL;
 UA_Boolean ledStatus = 0;
 UA_Boolean ledStatus = 0;
 
 
-static UA_StatusCode readLedStatus(void *handle, UA_NodeId nodeid, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
-  if(range)
-    return UA_STATUSCODE_BADINDEXRANGEINVALID;
+static UA_StatusCode
+readLedStatus(void *handle, UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+              const UA_NumericRange *range, UA_DataValue *value) {
+    if(range)
+        return UA_STATUSCODE_BADINDEXRANGEINVALID;
 
 
-  value->hasValue = UA_TRUE;
-  UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, &ledStatus, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    value->hasValue = UA_TRUE;
+    UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, &ledStatus,
+                                                    &UA_TYPES[UA_TYPES_BOOLEAN]);
 
 
-  if(retval != UA_STATUSCODE_GOOD)
-    return retval;
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
   
   
-  if(sourceTimeStamp) {
-          value->sourceTimestamp = UA_DateTime_now();
-          value->hasSourceTimestamp = UA_TRUE;
-  }
-  return UA_STATUSCODE_GOOD;
+    if(sourceTimeStamp) {
+        value->sourceTimestamp = UA_DateTime_now();
+        value->hasSourceTimestamp = UA_TRUE;
+    }
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static UA_StatusCode writeLedStatus(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range) {
+static UA_StatusCode
+writeLedStatus(void *handle, const UA_NodeId nodeid,
+               const UA_Variant *data, const UA_NumericRange *range) {
     if(range)
     if(range)
         return UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_BADINDEXRANGEINVALID;
 
 
@@ -159,9 +168,10 @@ static UA_StatusCode writeLedStatus(void *handle, const UA_NodeId nodeid, const
 }
 }
 
 
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
-static UA_StatusCode getMonitoredItems(const UA_NodeId objectId, const UA_Variant *input, UA_Variant *output, void *handle) {
+static UA_StatusCode
+getMonitoredItems(const UA_NodeId objectId, const UA_Variant *input,
+                  UA_Variant *output, void *handle) {
     UA_String tmp = UA_STRING("Hello World");
     UA_String tmp = UA_STRING("Hello World");
-    //UA_Server *theServer = (UA_Server *) handle; // Commented, would result in "unused variable" error
     UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]);
     UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]);
     printf("getMonitoredItems was called\n");
     printf("getMonitoredItems was called\n");
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
@@ -197,234 +207,253 @@ static UA_ByteString loadCertificate(void) {
     return certificate;
     return certificate;
 }
 }
 
 
-UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle);
-UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) {  
-  /*printf("References ns=%d;i=%d using i=%d ", childId.namespaceIndex, childId.identifier.numeric, referenceTypeId.identifier.numeric);
-  if (isInverse == UA_TRUE) {
-    printf(" (inverse)");
-  }
-  printf("\n");*/
-  
-  return UA_STATUSCODE_GOOD;
+static UA_StatusCode
+nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) {  
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
-  signal(SIGINT, stopHandler); /* catches ctrl-c */
+    signal(SIGINT, stopHandler); /* catches ctrl-c */
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-  pthread_rwlock_init(&writeLock, 0);
+    pthread_rwlock_init(&writeLock, 0);
 #endif
 #endif
 
 
-  UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-  logger = Logger_Stdout_new();
-  UA_Server_setLogger(server, logger);
-  UA_ByteString certificate = loadCertificate();
-  UA_Server_setServerCertificate(server, certificate);
-  UA_ByteString_deleteMembers(&certificate);
-  UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-
-  // add node with the datetime data source
-  UA_NodeId nodeId_currentTime;
-  UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
-  const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
-  const UA_LocalizedText dateNameBrowseName = UA_LOCALIZEDTEXT("en_US","current time");
-  UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, dateName, dateNameBrowseName, dateNameBrowseName, 0, 0,
-
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-
-                                  dateDataSource,
-
-                                  &nodeId_currentTime);
-
-  // Get and reattach the datasource
-  UA_DataSource *dataSourceCopy = NULL;
-  UA_Server_getAttribute_DataSource(server, nodeId_currentTime, &dataSourceCopy);
-  if (dataSourceCopy == NULL)
-    UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "The returned dataSource is invalid");
-  else 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_setAttribute_DataSource(server, nodeId_currentTime, *dataSourceCopy);
-  free(dataSourceCopy);
+    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+    logger = Logger_Stdout_new();
+    UA_Server_setLogger(server, logger);
+    UA_ByteString certificate = loadCertificate();
+    UA_Server_setServerCertificate(server, certificate);
+    UA_ByteString_deleteMembers(&certificate);
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+    // add node with the datetime data source
+    UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
+    UA_VariableAttributes v_attr;
+    UA_VariableAttributes_init(&v_attr);
+    v_attr.description = UA_LOCALIZEDTEXT("en_US","current time");
+    v_attr.displayName = UA_LOCALIZEDTEXT("en_US","current time");
+    const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
+    UA_NodeId dataSourceId;
+    UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL,
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,
+                                        UA_NODEID_NULL, v_attr, dateDataSource, &dataSourceId);
+
+    // Get and reattach the datasource
+    UA_DataSource dataSourceCopy;
+    UA_Server_getNodeAttribute_value_dataSource(server, dataSourceId, &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_value_dataSource(server, dataSourceId, dataSourceCopy);
 #ifndef _WIN32
 #ifndef _WIN32
-  //cpu temperature monitoring for linux machines
-  if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))) {
-          // add node with the data source
-          UA_DataSource temperatureDataSource = (UA_DataSource) {.handle = NULL, .read = readTemperature, .write = NULL};
-          const UA_QualifiedName tempName = UA_QUALIFIEDNAME(1, "cpu temperature");
-          const UA_LocalizedText tempNameBrowseName = UA_LOCALIZEDTEXT("en_US","temperature");
-          UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, tempName, tempNameBrowseName, tempNameBrowseName, 0, 0,
-
+    /* cpu temperature monitoring for linux machines */
+    if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))) {
+        // add node with the data source
+        UA_DataSource temperatureDataSource = (UA_DataSource) {
+            .handle = NULL, .read = readTemperature, .write = NULL};
+        const UA_QualifiedName tempName = UA_QUALIFIEDNAME(1, "cpu temperature");
+        UA_VariableAttributes_init(&v_attr);
+        v_attr.description = UA_LOCALIZEDTEXT("en_US","temperature");
+        v_attr.displayName = UA_LOCALIZEDTEXT("en_US","temperature");
+        UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL,
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-
-                                            temperatureDataSource,
-
-                                            NULL);
-  }
-
-  //LED control for rpi
-  if(access("/sys/class/leds/led0/trigger", F_OK ) != -1 || access("/sys/class/leds/led0/brightness", F_OK ) != -1) {
-    if((triggerFile = fopen("/sys/class/leds/led0/trigger", "w")) && (ledFile = fopen("/sys/class/leds/led0/brightness", "w"))) {
-      //setting led mode to manual
-      fprintf(triggerFile, "%s", "none");
-      fflush(triggerFile);
-
-      //turning off led initially
-      fprintf(ledFile, "%s", "1");
-      fflush(ledFile);
-
-      // add node with the LED status data source
-      UA_DataSource ledStatusDataSource = (UA_DataSource) {.handle = NULL, .read = readLedStatus, .write = writeLedStatus};
-      const UA_QualifiedName statusName = UA_QUALIFIEDNAME(0, "status LED");
-      const UA_LocalizedText statusNameBrowseName = UA_LOCALIZEDTEXT("en_US","status LED");
-      UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, statusName, statusNameBrowseName, statusNameBrowseName, 0, 0,
-
-                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-
-                                        ledStatusDataSource,
+                                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), tempName,
+                                            UA_NODEID_NULL, v_attr, temperatureDataSource, NULL);
+    }
 
 
-                                        NULL);
-    } else {
-      UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "[Raspberry Pi] LED file exist, but I have no access (try to run server with sudo)");
+    /* LED control for rpi */
+    if(access("/sys/class/leds/led0/trigger", F_OK ) != -1 ||
+       access("/sys/class/leds/led0/brightness", F_OK ) != -1) {
+        if((triggerFile = fopen("/sys/class/leds/led0/trigger", "w")) &&
+           (ledFile = fopen("/sys/class/leds/led0/brightness", "w"))) {
+            //setting led mode to manual
+            fprintf(triggerFile, "%s", "none");
+            fflush(triggerFile);
+
+            //turning off led initially
+            fprintf(ledFile, "%s", "1");
+            fflush(ledFile);
+
+            // add node with the LED status data source
+            UA_DataSource ledStatusDataSource = (UA_DataSource) {
+                .handle = NULL, .read = readLedStatus, .write = writeLedStatus};
+            UA_VariableAttributes_init(&v_attr);
+            v_attr.description = UA_LOCALIZEDTEXT("en_US","status LED");
+            v_attr.displayName = UA_LOCALIZEDTEXT("en_US","status LED");
+            const UA_QualifiedName statusName = UA_QUALIFIEDNAME(0, "status LED");
+            UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL,
+                                                UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                                UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), statusName,
+                                                UA_NODEID_NULL, v_attr, ledStatusDataSource, NULL);
+        } else
+            UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND,
+                           "[Raspberry Pi] LED file exist, but is not accessible (try to run server with sudo)");
     }
     }
-  }
 #endif
 #endif
 
 
-  // add a static variable node to the adresspace
-  UA_Variant *myIntegerVariant = UA_Variant_new();
-  UA_Int32 myInteger = 42;
-  UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-  const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-  const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
-  UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
-  UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-  UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, UA_LOCALIZEDTEXT("en_US", "the answer"), UA_LOCALIZEDTEXT("en_US", "the answer"),  0, 0,
-                            parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
-  /**************/
-  /* Demo Nodes */
-  /**************/
+    // add a static variable node to the adresspace
+    UA_VariableAttributes myVar;
+    UA_VariableAttributes_init(&myVar);
+    myVar.description = UA_LOCALIZEDTEXT("en_US", "the answer");
+    myVar.displayName = UA_LOCALIZEDTEXT("en_US", "the answer");
+    UA_Int32 myInteger = 42;
+    UA_Variant_setScalarCopy(&myVar.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
+    const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
+                              myIntegerName, UA_NODEID_NULL, myVar, NULL);
+    UA_Variant_deleteMembers(&myVar.value);
+
+    /**************/
+    /* Demo Nodes */
+    /**************/
 
 
 #define DEMOID 50000
 #define DEMOID 50000
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID), UA_QUALIFIEDNAME(1, "Demo"), UA_LOCALIZEDTEXT("en_US","Demo"),
-                          UA_LOCALIZEDTEXT("en_US","Demo"), 0, 0, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
+    UA_ObjectAttributes object_attr;
+    UA_ObjectAttributes_init(&object_attr);
+    object_attr.description = UA_LOCALIZEDTEXT("en_US","Demo");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Demo");
+    UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
 
 #define SCALARID 50001
 #define SCALARID 50001
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID), UA_QUALIFIEDNAME(1, "Scalar"), UA_LOCALIZEDTEXT("en_US","Scalar"),
-                          UA_LOCALIZEDTEXT("en_US","Scalar"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
+    object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Scalar");
+    UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
+                            UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                            UA_QUALIFIEDNAME(1, "Scalar"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
 
 #define ARRAYID 50002
 #define ARRAYID 50002
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID), UA_QUALIFIEDNAME(1, "Array"), UA_LOCALIZEDTEXT("en_US","Array"),
-                          UA_LOCALIZEDTEXT("en_US","Array"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
+    object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Array");
+    UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
+                            UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                            UA_QUALIFIEDNAME(1, "Array"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
 
 #define MATRIXID 50003
 #define MATRIXID 50003
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_QUALIFIEDNAME(1, "Matrix"), UA_LOCALIZEDTEXT("en_US","Matrix"),
-                          UA_LOCALIZEDTEXT("en_US","Matrix"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
-
-  UA_UInt32 id = 51000; //running id in namespace 0
-  for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
-    if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
-        continue;
-    //add a scalar node for every built-in type
-    void *value = UA_new(&UA_TYPES[type]);
-    UA_Variant *variant = UA_Variant_new();
-    UA_Variant_setScalar(variant, value, &UA_TYPES[type]);
-    char name[15];
-    sprintf(name, "%02d", type);
-    UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name);
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name), 0, 0,
-                              UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), variant, NULL);
-
-    //add an array node for every built-in type
-    UA_Variant *arrayvar = UA_Variant_new();
-    UA_Variant_setArray(arrayvar, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name), 0, 0,
-                              UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), arrayvar, NULL);
-
-    //add an matrix node for every built-in type
-    arrayvar = UA_Variant_new();
-    void* myMultiArray = UA_Array_new(&UA_TYPES[type],9);
-    arrayvar->arrayDimensions = UA_Array_new(&UA_TYPES[UA_TYPES_INT32],2);
-    arrayvar->arrayDimensions[0] = 3;
-    arrayvar->arrayDimensions[1] = 3;
-    arrayvar->arrayDimensionsSize = 2;
-    arrayvar->arrayLength = 9;
-    arrayvar->data = myMultiArray;
-    arrayvar->type = &UA_TYPES[type];
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name),
-                              0, 0, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), arrayvar, NULL);
-  }
+    object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
+    UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+
+    UA_UInt32 id = 51000; // running id in namespace 0
+    for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
+        if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
+            continue;
+
+        UA_VariableAttributes attr;
+        UA_VariableAttributes_init(&attr);
+        char name[15];
+        sprintf(name, "%02d", type);
+        attr.displayName = UA_LOCALIZEDTEXT("en_US",name);
+        UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name);
+
+        /* add a scalar node for every built-in type */
+        void *value = UA_new(&UA_TYPES[type]);
+        UA_Variant_setScalar(&attr.value, value, &UA_TYPES[type]);
+        UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
+                                  UA_NODEID_NUMERIC(1, SCALARID),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+        UA_Variant_deleteMembers(&attr.value);
+
+        /* add an array node for every built-in type */
+        UA_Variant_setArray(&attr.value, UA_Array_new(&UA_TYPES[type], 10),
+                            10, &UA_TYPES[type]);
+        UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
+                                  UA_NODEID_NUMERIC(1, ARRAYID),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+        UA_Variant_deleteMembers(&attr.value);
+
+        /* add an matrix node for every built-in type */
+        void* myMultiArray = UA_Array_new(&UA_TYPES[type],9);
+        attr.value.arrayDimensions = UA_Array_new(&UA_TYPES[UA_TYPES_INT32],2);
+        attr.value.arrayDimensions[0] = 3;
+        attr.value.arrayDimensions[1] = 3;
+        attr.value.arrayDimensionsSize = 2;
+        attr.value.arrayLength = 9;
+        attr.value.data = myMultiArray;
+        attr.value.type = &UA_TYPES[type];
+        UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
+                                  UA_NODEID_NUMERIC(1, MATRIXID),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+        UA_Variant_deleteMembers(&attr.value);
+    }
 
 
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
-  UA_Argument inputArguments;
-  UA_Argument_init(&inputArguments);
-  inputArguments.arrayDimensionsSize = -1;
-  inputArguments.arrayDimensions = NULL;
-  inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
-  inputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
-  inputArguments.name = UA_STRING("Input an integer");
-  inputArguments.valueRank = -1;
-
-  UA_Argument outputArguments;
-  UA_Argument_init(&outputArguments);
-  outputArguments.arrayDimensionsSize = -1;
-  outputArguments.arrayDimensions = NULL;
-  outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
-  outputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
-  outputArguments.name = UA_STRING("Input an integer");
-  outputArguments.valueRank = -1;
-
-  UA_NodeId methodId; // Retrieve the actual ID if this node if a random id as in UA_NODEID_NUMERIC(1,0) is used
-  UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541), UA_QUALIFIEDNAME(1,"ping"), UA_LOCALIZEDTEXT("en_US", "ping"),
-                          UA_LOCALIZEDTEXT("en_US", "Return a single argument as passed by the caller"),
-                          UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                          0, 0,
-                          &getMonitoredItems, // Call this method
-                          (void *) server,    // Pass our server pointer as a handle to the method
-                          1, &inputArguments, 1, &outputArguments, &methodId);
-  
-  // Dettach the method from the methodNode
-  UA_Server_setAttribute_method(server, UA_NODEID_NUMERIC(1,62541), NULL, NULL);
-  
-  // Reaettach the method from the methodNode
-  UA_Server_setAttribute_method(server, UA_NODEID_NUMERIC(1,62541), &getMonitoredItems, (void *) server);
+    UA_Argument inputArguments;
+    UA_Argument_init(&inputArguments);
+    inputArguments.arrayDimensionsSize = -1;
+    inputArguments.arrayDimensions = NULL;
+    inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
+    inputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
+    inputArguments.name = UA_STRING("Input an integer");
+    inputArguments.valueRank = -1;
+
+    UA_Argument outputArguments;
+    UA_Argument_init(&outputArguments);
+    outputArguments.arrayDimensionsSize = -1;
+    outputArguments.arrayDimensions = NULL;
+    outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
+    outputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
+    outputArguments.name = UA_STRING("Input an integer");
+    outputArguments.valueRank = -1;
+
+    UA_MethodAttributes addmethodattributes;
+    UA_MethodAttributes_init(&addmethodattributes);
+    addmethodattributes.description = UA_LOCALIZEDTEXT("en_US", "Return a single argument as passed by the caller");
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "ping");
+    addmethodattributes.executable = UA_TRUE;
+    addmethodattributes.userExecutable = UA_TRUE;
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1,"ping"), addmethodattributes,
+                            &getMonitoredItems, // Call this method
+                            (void *) server,    // Pass our server pointer as a handle to the method
+                            1, &inputArguments, 1, &outputArguments, NULL);
 #endif
 #endif
    
    
-  // Example for iterating over all nodes referenced by "Objects":
-  //printf("Nodes connected to 'Objects':\n=============================\n");
-  UA_Server_forEachChildNodeCall(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIter, NULL);
+    // Example for iterating over all nodes referenced by "Objects":
+    //printf("Nodes connected to 'Objects':\n=============================\n");
+    UA_Server_forEachChildNodeCall(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIter, NULL);
   
   
-  // Some easy localization
-  UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("de_DE", "Objekte");
-  UA_Server_setAttribute_displayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), &objectsName);
+    // Some easy localization
+    UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("de_DE", "Objekte");
+    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
+    //start server
+    UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
 
 
-  //ctrl-c received -> clean up
-  UA_Server_delete(server);
+    //ctrl-c received -> clean up
+    UA_Server_delete(server);
 
 
-  if(temperatureFile)
-          fclose(temperatureFile);
+    if(temperatureFile)
+        fclose(temperatureFile);
 
 
-  if(triggerFile) {
-          fseek(triggerFile, 0, SEEK_SET);
-          //setting led mode to default
-          fprintf(triggerFile, "%s", "mmc0");
-          fclose(triggerFile);
-  }
+    if(triggerFile) {
+        fseek(triggerFile, 0, SEEK_SET);
+        //setting led mode to default
+        fprintf(triggerFile, "%s", "mmc0");
+        fclose(triggerFile);
+    }
   
   
-  if(ledFile)
-    fclose(ledFile);
+    if(ledFile)
+        fclose(ledFile);
 
 
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-  pthread_rwlock_destroy(&writeLock);
+    pthread_rwlock_destroy(&writeLock);
 #endif
 #endif
 
 
-  return retval;
+    return retval;
 }
 }

+ 29 - 14
examples/server.cpp

@@ -2,6 +2,8 @@
  * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
  */
+
+#include <signal.h>
 #include <iostream>
 #include <iostream>
 #include <cstring>
 #include <cstring>
 
 
@@ -21,29 +23,42 @@
 
 
 using namespace std;
 using namespace std;
 
 
-int main()
-{
+UA_Logger logger;
+UA_Boolean running = 1;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = 0;
+}
+
+int main() {
+    signal(SIGINT, stopHandler); /* catches ctrl-c */
+
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-
-    UA_Logger logger = Logger_Stdout_new();
+    logger = Logger_Stdout_new();
     UA_Server_setLogger(server, logger);
     UA_Server_setLogger(server, logger);
 
 
     // add a variable node to the adresspace
     // add a variable node to the adresspace
-    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
-    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
+    UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    attr.description = UA_LOCALIZEDTEXT_ALLOC("en_US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US","the answer");
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME_ALLOC(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName,
-                              UA_LOCALIZEDTEXT("", "the.answer"),
-                              UA_LOCALIZEDTEXT("", ""), 0, 0,
-                              parentNodeId, parentReferenceNodeId,
-                              myIntegerVariant, NULL);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NULL, attr, NULL);
+
+    /* allocations on the heap need to be freed */
+    UA_VariableAttributes_deleteMembers(&attr);
+    UA_NodeId_deleteMembers(&myIntegerNodeId);
+    UA_QualifiedName_deleteMembers(&myIntegerName);
 
 
-    UA_Boolean running = UA_TRUE;
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
 	UA_Server_delete(server);
 	UA_Server_delete(server);
 
 

+ 12 - 13
examples/server_datasource.c

@@ -54,20 +54,19 @@ int main(int argc, char** argv) {
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
 
 
     /* add a variable node to the address space */
     /* add a variable node to the address space */
-    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); /* UA_NODEID_NULL would assign a random free nodeid */
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","the answer");
-
-    UA_DataSource dateDataSource = (UA_DataSource) {.handle = &myInteger, .read = readInteger, .write = writeInteger};
-
-    UA_Server_addDataSourceVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName, myIntegerBrowseName, 0, 0,
-
-                                    UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                    UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-
-                                    dateDataSource,
-
-                                    NULL);
+    UA_DataSource dateDataSource = (UA_DataSource) {
+        .handle = &myInteger, .read = readInteger, .write = writeInteger};
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
+    attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
+
+    UA_Server_addDataSourceVariableNode(server, myIntegerNodeId,
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource, NULL);
 
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);

+ 37 - 22
examples/server_method.c

@@ -18,7 +18,9 @@
 UA_Boolean running = UA_TRUE;
 UA_Boolean running = UA_TRUE;
 UA_Logger logger;
 UA_Logger logger;
 
 
-static UA_StatusCode helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input, UA_Variant *output, void *handle) {
+static UA_StatusCode
+helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input,
+                 UA_Variant *output, void *handle) {
         UA_String *inputStr = (UA_String*)input->data;
         UA_String *inputStr = (UA_String*)input->data;
         UA_String tmp = UA_STRING_ALLOC("Hello ");
         UA_String tmp = UA_STRING_ALLOC("Hello ");
         if(inputStr->length > 0) {
         if(inputStr->length > 0) {
@@ -32,15 +34,12 @@ static UA_StatusCode helloWorldMethod(const UA_NodeId objectId, const UA_Variant
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
 } 
 } 
 
 
-static UA_StatusCode IncInt32ArrayValuesMethod(const UA_NodeId objectId,
-                                         const UA_Variant *input, UA_Variant *output, void *handle) {
-
-
-	UA_Variant_setArrayCopy(output,input->data,5,&UA_TYPES[UA_TYPES_INT32]);
-	for(int i = 0; i< input->arrayLength; i++){
+static UA_StatusCode
+IncInt32ArrayValuesMethod(const UA_NodeId objectId, const UA_Variant *input,
+                          UA_Variant *output, void *handle) {
+	UA_Variant_setArrayCopy(output, input->data, 5, &UA_TYPES[UA_TYPES_INT32]);
+	for(int i = 0; i< input->arrayLength; i++)
 		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;
 		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;
-	}
-
 	return UA_STATUSCODE_GOOD;
 	return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -48,6 +47,7 @@ static void stopHandler(int sign) {
     UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
     UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
     running = 0;
     running = 0;
 }
 }
+
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
 
@@ -77,10 +77,18 @@ int main(int argc, char** argv) {
     outputArguments.name = UA_STRING("MyOutput");
     outputArguments.name = UA_STRING("MyOutput");
     outputArguments.valueRank = -1;
     outputArguments.valueRank = -1;
         
         
-    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541), UA_QUALIFIEDNAME(1, "hello world"), 
-                            UA_LOCALIZEDTEXT("en_US","Hello World"), UA_LOCALIZEDTEXT("en_US","Say `Hello World`"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                            0, 0, &helloWorldMethod, NULL, 1, &inputArguments, 1, &outputArguments, NULL);
+    UA_MethodAttributes helloAttr;
+    UA_MethodAttributes_init(&helloAttr);
+    helloAttr.description = UA_LOCALIZEDTEXT("en_US","Say `Hello World`");
+    helloAttr.displayName = UA_LOCALIZEDTEXT("en_US","Hello World");
+    helloAttr.executable = UA_TRUE;
+    helloAttr.userExecutable = UA_TRUE;
+    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "hello world"), 
+                            helloAttr, &helloWorldMethod, NULL,
+                            1, &inputArguments, 1, &outputArguments, NULL);
 
 
     //END OF EXAMPLE 1
     //END OF EXAMPLE 1
 
 
@@ -105,20 +113,27 @@ int main(int argc, char** argv) {
     pOutputDimensions[0] = 5;
     pOutputDimensions[0] = 5;
     outputArguments.arrayDimensions = pOutputDimensions;
     outputArguments.arrayDimensions = pOutputDimensions;
     outputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     outputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
-    outputArguments.description = UA_LOCALIZEDTEXT("en_US",
-                    "increment each array index");
-    outputArguments.name = UA_STRING(
-                    "output is the array, each index is incremented by one");
+    outputArguments.description = UA_LOCALIZEDTEXT("en_US", "increment each array index");
+    outputArguments.name = UA_STRING("output is the array, each index is incremented by one");
     outputArguments.valueRank = 1;
     outputArguments.valueRank = 1;
 
 
-    UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"), UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
-                            UA_LOCALIZEDTEXT("en_US","1dArrayExample"), UA_LOCALIZEDTEXT("en_US","1dArrayExample"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), 
-                            0, 0, &IncInt32ArrayValuesMethod, NULL, 1, &inputArguments, 1, &outputArguments, NULL);
+    
+    UA_MethodAttributes incAttr;
+    UA_MethodAttributes_init(&incAttr);
+    incAttr.description = UA_LOCALIZEDTEXT("en_US","1dArrayExample");
+    incAttr.displayName = UA_LOCALIZEDTEXT("en_US","1dArrayExample");
+    incAttr.executable = UA_TRUE;
+    incAttr.userExecutable = UA_TRUE;
+    UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), 
+                            UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
+                            incAttr, &IncInt32ArrayValuesMethod, NULL,
+                            1, &inputArguments, 1, &outputArguments, NULL);
     //END OF EXAMPLE 2
     //END OF EXAMPLE 2
 
 
     /* start server */
     /* start server */
-    UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
+    UA_StatusCode retval = UA_Server_run(server, 1, &running);
 
 
     /* ctrl-c received -> clean up */
     /* ctrl-c received -> clean up */
     UA_UInt32_delete(pInputDimensions);
     UA_UInt32_delete(pInputDimensions);

+ 10 - 8
examples/server_udp.c

@@ -30,17 +30,19 @@ int main(int argc, char** argv) {
     UA_Server_addNetworkLayer(server, nl);
     UA_Server_addNetworkLayer(server, nl);
 
 
 	// add a variable node to the adresspace
 	// add a variable node to the adresspace
-    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
-    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
-    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","the answer");
+    UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName,
-                              myIntegerBrowseName, 0,0,
-                              parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NULL, attr, NULL);
 
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
 	UA_Server_delete(server);
 	UA_Server_delete(server);

+ 20 - 14
examples/server_variable.c

@@ -22,12 +22,15 @@ static void stopHandler(int sign) {
     running = 0;
     running = 0;
 }
 }
 
 
-static void onRead(void *handle, const UA_NodeId nodeid,  const UA_Variant *data, const UA_NumericRange *range){
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "onRead; handle is: %i", (uintptr_t)handle);
+static void onRead(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
+                   const UA_NumericRange *range) {
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "onRead; handle is: %i", (uintptr_t)handle);
 }
 }
 
 
-static void onWrite(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range){
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "onWrite; handle is: %i", (uintptr_t)handle);
+static void onWrite(void *h, const UA_NodeId nodeid, const UA_Variant *data,
+                    const UA_NumericRange *range) {
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "onWrite; handle: %i", (uintptr_t)h);
 }
 }
 
 
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
@@ -36,24 +39,27 @@ int main(int argc, char** argv) {
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     logger = Logger_Stdout_new();
     logger = Logger_Stdout_new();
     UA_Server_setLogger(server, logger);
     UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    UA_ServerNetworkLayer *nl;
+    nl = ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664);
+    UA_Server_addNetworkLayer(server, nl);
 
 
     /* add a variable node to the address space */
     /* add a variable node to the address space */
-    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
-    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    //NOTE: the link between myInteger and the value of the node is lost here, you can safely reuse myInteger
+    UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); /* UA_NODEID_NULL would assign a random free nodeid */
-    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-
-    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName, myIntegerBrowseName, 0, 0,
-                              parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NULL, attr, NULL);
 
 
     UA_ValueCallback callback = {(void*)7, onRead, onWrite};
     UA_ValueCallback callback = {(void*)7, onRead, onWrite};
-    UA_Server_setAttribute_valueCallback(server, myIntegerNodeId, callback);
+    UA_Server_setAttribute_value_callback(server, myIntegerNodeId, callback);
 
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);

+ 381 - 385
include/ua_server.h

@@ -28,11 +28,9 @@ extern "C" {
 #include "ua_job.h"
 #include "ua_job.h"
 #include "ua_connection.h"
 #include "ua_connection.h"
 
 
-/**
- * @defgroup server Server
- *
- * @{
- */
+/*********************************/
+/* Initialize and run the server */
+/*********************************/
 
 
 typedef struct UA_ServerConfig {
 typedef struct UA_ServerConfig {
     UA_Boolean  Login_enableAnonymous;
     UA_Boolean  Login_enableAnonymous;
@@ -54,31 +52,112 @@ void UA_EXPORT UA_Server_delete(UA_Server *server);
 
 
 /** Sets the logger used by the server */
 /** Sets the logger used by the server */
 void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
 void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
-UA_Logger UA_EXPORT UA_Server_getLogger(UA_Server *server);
 
 
 /**
 /**
  * Runs the main loop of the server. In each iteration, this calls into the networklayers to see if
  * Runs the main loop of the server. In each iteration, this calls into the networklayers to see if
  * jobs have arrived and checks if repeated jobs need to be triggered.
  * jobs have arrived and checks if repeated jobs need to be triggered.
  *
  *
  * @param server The server object
  * @param server The server object
- *
  * @param nThreads The number of worker threads. Is ignored if MULTITHREADING is not activated.
  * @param nThreads The number of worker threads. Is ignored if MULTITHREADING is not activated.
- *
  * @param running Points to a boolean value on the heap. When running is set to false, the worker
  * @param running Points to a boolean value on the heap. When running is set to false, the worker
- * threads and the main loop close and the server is shut down.
- *
+ *        threads and the main loop close and the server is shut down.
  * @return Indicates whether the server shut down cleanly
  * @return Indicates whether the server shut down cleanly
- *
  */
  */
 UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
 UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
 
 
-/* The prologue part of UA_Server_run (no need to use if you call UA_Server_run) */
+/** The prologue part of UA_Server_run (no need to use if you call UA_Server_run) */
 UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
 UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
-/* The epilogue part of UA_Server_run (no need to use if you call UA_Server_run) */
+
+/** The epilogue part of UA_Server_run (no need to use if you call UA_Server_run) */
 UA_StatusCode UA_EXPORT UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads);
 UA_StatusCode UA_EXPORT UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads);
-/* One iteration of UA_Server_run (no need to use if you call UA_Server_run) */
+
+/** One iteration of UA_Server_run (no need to use if you call UA_Server_run) */
 UA_StatusCode UA_EXPORT UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running);
 UA_StatusCode UA_EXPORT UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running);
 
 
+/**
+ * @param server The server object.
+ * @param job The job that shall be added.
+ * @param interval The job shall be repeatedly executed with the given interval (in ms). The
+ *        interval must be larger than 5ms. The first execution occurs at now() + interval at the
+ *        latest.
+ * @param jobId Set to the guid of the repeated job. This can be used to cancel the job later on. If
+ *        the pointer is null, the guid is not set.
+ * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code otherwise.
+ */
+UA_StatusCode UA_EXPORT UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
+                                                 UA_UInt32 interval, UA_Guid *jobId);
+
+/**
+ * Remove repeated job. The entry will be removed asynchronously during the next iteration of the
+ * server main loop.
+ *
+ * @param server The server object.
+ * @param jobId The id of the job that shall be removed.
+ * @return Upon sucess, UA_STATUSCODE_GOOD is returned. An error code otherwise.
+ */
+UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId);
+
+/**
+ * Interface to the binary network layers. This structure is returned from the
+ * function that initializes the network layer. The layer is already bound to a
+ * specific port and listening. The functions in the structure are never called
+ * in parallel but only sequentially from the server's main loop. So the network
+ * layer does not need to be thread-safe.
+ */
+typedef struct UA_ServerNetworkLayer {
+    UA_String discoveryUrl;
+    UA_Logger logger; ///< Set during _start
+
+    /**
+     * Starts listening on the the networklayer.
+     *
+     * @param nl The network layer
+     * @param logger The logger
+     * @return Returns UA_STATUSCODE_GOOD or an error code.
+     */
+    UA_StatusCode (*start)(struct UA_ServerNetworkLayer *nl, UA_Logger logger);
+    
+    /**
+     * Gets called from the main server loop and returns the jobs (accumulated messages and close
+     * events) for dispatch.
+     *
+     * @param nl The network layer
+     * @param jobs When the returned integer is >0, *jobs points to an array of UA_Job of the
+     * returned size.
+     * @param timeout The timeout during which an event must arrive in microseconds
+     * @return The size of the jobs array. If the result is negative, an error has occurred.
+     */
+    size_t (*getJobs)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
+
+    /**
+     * Closes the network connection and returns all the jobs that need to be finished before the
+     * network layer can be safely deleted.
+     *
+     * @param nl The network layer
+     * @param jobs When the returned integer is >0, jobs points to an array of UA_Job of the
+     * returned size.
+     * @return The size of the jobs array. If the result is negative, an error has occurred.
+     */
+    size_t (*stop)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs);
+
+    /** Deletes the network layer. Call only after a successful shutdown. */
+    void (*deleteMembers)(struct UA_ServerNetworkLayer *nl);
+} UA_ServerNetworkLayer;
+
+/**
+ * Adds a network layer to the server. The network layer is destroyed together
+ * with the server. Do not use it after adding it as it might be moved around on
+ * the heap.
+ */
+void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *networkLayer);
+
+/** @brief Add a new namespace to the server. Returns the index of the new namespace */
+UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
+
+/***************/
+/* Data Source */
+/***************/
+
 /**
 /**
  * Datasources are the interface to local data providers. It is expected that
  * Datasources are the interface to local data providers. It is expected that
  * the read and release callbacks are implemented. The write callback can be set
  * the read and release callbacks are implemented. The write callback can be set
@@ -126,398 +205,346 @@ typedef struct {
     void (*onWrite)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
     void (*onWrite)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
 } UA_ValueCallback;
 } UA_ValueCallback;
 
 
-/** @brief Add a new namespace to the server. Returns the index of the new namespace */
-UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
+/*******************/
+/* Node Management */
+/*******************/
 
 
 /** Add a reference to the server's address space */
 /** Add a reference to the server's address space */
-UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
-                                               const UA_NodeId refTypeId, const UA_ExpandedNodeId targetId);
-
-/** Deletes a node from the nodestore.
- *
- * @param server The server object
- * @param nodeId ID of the node to be deleted
+UA_StatusCode UA_EXPORT
+UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
+                       const UA_ExpandedNodeId targetId, UA_Boolean isForward);
 
 
- * @return Return UA_STATUSCODE_GOOD if the node was deleted or an appropriate errorcode if the node was not found
- *         or cannot be deleted.
- */
+/* Don't use this function. There are typed versions as inline functions. */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId);
+UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
+                  const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                  const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+                  const UA_NodeAttributes *attr, const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
 
 
-#define UA_SERVER_DELETENODEALIAS_DECL(TYPE) \
-UA_StatusCode UA_EXPORT UA_Server_delete##TYPE##Node(UA_Server *server, UA_NodeId nodeId);
+static UA_INLINE UA_StatusCode
+UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+                          const UA_VariableAttributes attr, UA_NodeId *outNewNodeId) {
+    return UA_Server_addNode(server, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                              const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
+                              UA_NodeId *outNewNodeId) {
+    return UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
+    return UA_Server_addNode(server, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                            const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                            const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
+                            UA_NodeId *outNewNodeId) {
+    return UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                      const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                      const UA_QualifiedName browseName, const UA_ViewAttributes attr,
+                      UA_NodeId *outNewNodeId) {
+    return UA_Server_addNode(server, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                               const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
+                               UA_NodeId *outNewNodeId) {
+    return UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
+                          UA_NodeId *outNewNodeId) {
+    return UA_Server_addNode(server, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
+                             &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId); }
 
 
-UA_SERVER_DELETENODEALIAS_DECL(Object)
-UA_SERVER_DELETENODEALIAS_DECL(Variable)
-UA_SERVER_DELETENODEALIAS_DECL(ReferenceType)
-UA_SERVER_DELETENODEALIAS_DECL(View)
-UA_SERVER_DELETENODEALIAS_DECL(VariableType)
-UA_SERVER_DELETENODEALIAS_DECL(DataType)
+UA_StatusCode UA_EXPORT
+UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                                    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                                    const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+                                    const UA_VariableAttributes attr, const UA_DataSource dataSource,
+                                    UA_NodeId *outNewNodeId);
 
 
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
-UA_SERVER_DELETENODEALIAS_DECL(Method)
+typedef UA_StatusCode (*UA_MethodCallback)(const UA_NodeId objectId, const UA_Variant *input,
+                                           UA_Variant *output, void *handle);
+UA_StatusCode UA_EXPORT
+UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName, const UA_MethodAttributes attr,
+                        UA_MethodCallback method, void *handle,
+                        UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
+                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments,
+                        UA_NodeId *outNewNodeId);
 #endif
 #endif
 
 
-/** Deletes a copied instance of a node by deallocating it and all its attributes. This assumes that the node was
- * priorly copied using getNodeCopy. To delete nodes that are located in the nodestore, use UA_Server_deleteNode()
- * instead.
- *
- * @param server The server object
- * @param node   A copy of any node-type struct created with getNodeCopy; must *not* be managed by the nodestore.
- * 
- * @return Return UA_STATUSCODE_GOOD if the node was deleted or an appropriate errorcode if the node was not found
- *         or cannot be deleted.
- */
-UA_StatusCode UA_EXPORT 
-UA_Server_deleteNodeCopy(UA_Server *server, void **node);
+UA_StatusCode UA_EXPORT UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId);
 
 
-/** Creates a deep copy of a node located in the nodestore and returns it to the userspace. Note that any manipulation
- * of this copied node is not reflected by the server, but otherwise not accessible attributes of the node's struct
- * can be examined in bulk. node->nodeClass can be used to cast the node to a specific node type. Use 
- * UA_Server_deleteNodeCopy() to deallocate this node.
- *
- * @param server The server object
- * @param nodeId ID of the node copy to be copied
- * @param copyInto Pointer to a NULL pointer that will hold the copy of the node on a successfull return.
- * 
- * @return Return UA_STATUSCODE_GOOD if the node was copied or an appropriate errorcode if the node was not found
- *         or cannot be copied.
- */
-UA_StatusCode UA_EXPORT 
-UA_Server_getNodeCopy(UA_Server *server, UA_NodeId nodeId, void **copyInto);
+typedef UA_StatusCode (*UA_NodeIteratorCallback) (UA_NodeId childId, UA_Boolean isInverse,
+                                                  UA_NodeId referenceTypeId, void *handle);
 
 
-/** A new variable Node with a value passed in variant.
- *
- * @param server The server object
- * @param nodeId        The requested nodeId of the new node. Use the numeric id with i=0 to get a new ID from the server.
- * @param browseName    The qualified name of this node
- * @param displayName   The localized text shown when displaying the node
- * @param description   The localized human readable description
- * @param userWriteMask Bitmask defining the user write permissions
- * @param writeMask     Bitmask defining the write permissions
- * @param parentNodeId  The node under which this node exists ("parent")
- * @param referenceTypeId Reference type used by the parent to reference this node
- * @param value         A variant containing the value to be assigned to this node.
- * @param createdNodeId Pointer to a NULL pointer that will hold the copy of the nodeId on a successfull return.
+/** Iterate over all nodes referenced by parentNodeId by calling the callback function for each
+ * child node
  * 
  * 
- * @return Return UA_STATUSCODE_GOOD if the node was created or an appropriate error code if not.
+ * @param server The server object.
+ *
+ * @param parentNodeId The NodeId of the parent whose references are to be iterated over
+ *
+ * @param callback The function of type UA_NodeIteratorCallback to be called for each referenced child
+ *
+ * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code otherwise.
  */
  */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_addVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                          const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
+                               UA_NodeIteratorCallback callback, void *handle);
+
+/***********************/
+/* Set Node Attributes */
+/***********************/
+
+/* The following node attributes cannot be changed once the node is created
+   - NodeClass
+   - NodeId
+   - Symmetric
+   
+   The following attributes will eventually be managed by a userrights layer and are unsupported yet
+   - WriteMask
+   - UserWriteMask
+   - AccessLevel
+   - UserAccessLevel
+   - UserExecutable
+
+   The following attributes are currently taken from the value variant:
+   - DataType
+   - ValueRank
+   - ArrayDimensions
+   
+   - Historizing is currently unsupported
+  */
 
 
-                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-
-                          UA_Variant *value,
-
-                          UA_NodeId *createdNodeId);
-
-// Missing: eventNotifier
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_addObjectNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-
-                        const UA_ExpandedNodeId typeDefinition,
-
-                        UA_NodeId *createdNodeId);
-
-// Missing: isAbstract, symmetric
-UA_StatusCode UA_EXPORT 
-UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                               const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+UA_Server_setNodeAttribute_value(UA_Server *server, const UA_NodeId nodeId,
+                                 const UA_DataType *type, const UA_Variant value);
 
 
-                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-
-                               const UA_ExpandedNodeId typeDefinition,
-                               const UA_LocalizedText inverseName,
-
-                               UA_NodeId *createdNodeId );
+/* The value is moved into the node (not copied). The value variant is _inited internally. */
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeAttribute_value_destructive(UA_Server *server, const UA_NodeId nodeId,
+                                             const UA_DataType *type, UA_Variant *value);
 
 
+/* Succeeds only if the node contains a variant value */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                            const UA_LocalizedText displayName, const UA_LocalizedText description,  const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+UA_Server_setAttribute_value_callback(UA_Server *server, const UA_NodeId nodeId,
+                                      const UA_ValueCallback callback);
 
 
-                            const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeAttribute_value_dataSource(UA_Server *server, const UA_NodeId nodeId,
+                                            const UA_DataSource dataSource);
 
 
-                            const UA_ExpandedNodeId typeDefinition,
-                            const UA_Boolean isAbstract,
+/* Don't use this function. There are typed versions with no additional overhead. */
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId,
+                           const UA_DataType *type, const void *value);
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_browseName(UA_Server *server, const UA_NodeId nodeId,
+                                      const UA_QualifiedName browseName) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME,
+                                      &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_displayName(UA_Server *server, const UA_NodeId nodeId,
+                                       const UA_LocalizedText displayName) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_description(UA_Server *server, const UA_NodeId nodeId,
+                                       const UA_LocalizedText description) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_isAbstract(UA_Server *server, const UA_NodeId nodeId,
+                                      const UA_Boolean isAbstract) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT,
+                                      &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_inverseName(UA_Server *server, const UA_NodeId nodeId,
+                                       const UA_LocalizedText inverseName) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_containtsNoLoops(UA_Server *server, const UA_NodeId nodeId,
+                                            const UA_Boolean containsNoLoops) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
+                                      &UA_TYPES[UA_TYPES_BOOLEAN], &containsNoLoops); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_eventNotifier(UA_Server *server, const UA_NodeId nodeId,
+                                         const UA_Byte eventNotifier) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
+                                      &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_minimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId,
+                                                   const UA_Double miniumSamplingInterval) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                                      &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_setNodeAttribute_executable(UA_Server *server, const UA_NodeId nodeId,
+                                      const UA_Boolean executable) {
+    return UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE,
+                                      &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
 
 
-                            UA_NodeId *createdNodeId );
+#ifdef ENABLE_METHODCALLS
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId,
+                                  UA_MethodCallback method, void *handle);
+#endif
 
 
-UA_StatusCode UA_EXPORT 
-UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                              const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+typedef struct {
+    void * (*constructor)(const UA_NodeId instance); ///< Returns the instance handle attached to the node
+    void (*destructor)(const UA_NodeId instance, void *instanceHandle);
+} UA_ObjectInstanceManagement;
 
 
-                              const UA_NodeId parentNodeId,
-                              const UA_NodeId referenceTypeId,
+UA_StatusCode UA_EXPORT
+UA_Server_setObjectInstanceManagement(UA_Server *server, UA_NodeId nodeId,
+                                      UA_ObjectInstanceManagement oim);
 
 
-                              UA_Variant *value,
-                              const UA_Int32 valueRank,
-                              const UA_Boolean isAbstract,
+/***********************/
+/* Get Node Attributes */
+/***********************/
 
 
-                              UA_NodeId *createdNodeId);
+/* The following attributes cannot be read. They make no sense to read internally since the "admin"
+   user always has all rights.
+   - UserWriteMask
+   - UserAccessLevel
+   - UserExecutable
+*/
 
 
+/* Don't use this function. There are typed versions for every supported attribute. */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                          const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+UA_Server_getNodeAttribute(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_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
 
 
-                          const UA_NodeId parentNodeId,
-                          const UA_NodeId referenceTypeId,
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_nodeClass(UA_Server *server, UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
 
 
-                          const UA_ExpandedNodeId typeDefinition,
-                          const UA_Boolean isAbstract,
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_browseName(UA_Server *server, UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
 
 
-                          UA_NodeId *createdNodeId);
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_displayName(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
+    return UA_Server_getNodeAttribute(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_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
 
 
-UA_StatusCode UA_EXPORT
-UA_Server_addViewNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                      const UA_LocalizedText displayName, const UA_LocalizedText description, const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-
-                      const UA_NodeId parentNodeId,
-                      const UA_NodeId referenceTypeId,
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_writeMask(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK, outWriteMask); }
 
 
-                      const UA_ExpandedNodeId typeDefinition,
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_isAbstract(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
 
 
-                      UA_NodeId *createdNodeId);
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_symmetric(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outSymmetric) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
 
 
-UA_StatusCode UA_EXPORT
-UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                                    const UA_LocalizedText displayName, const UA_LocalizedText description,  const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_inverseName(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
 
 
-                                    const UA_NodeId parentNodeId,
-                                    const UA_NodeId referenceTypeId,
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_containsNoLoops(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
 
 
-                                    const UA_DataSource dataSource,
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_eventNotifier(UA_Server *server, UA_NodeId nodeId, UA_Byte *outEventNotifier) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
 
 
-                                    UA_NodeId *createdNodeId);
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_value(UA_Server *server, UA_NodeId nodeId, UA_Variant *outValue) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
 
 
-/* --------------------- */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_addMonodirectionalReference(UA_Server *server, UA_NodeId sourceNodeId,
-                                      UA_ExpandedNodeId targetNodeId, UA_NodeId referenceTypeId,
-                                      UA_Boolean isforward);
+UA_Server_getNodeAttribute_value_dataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource *dataSource);
 
 
-#ifdef ENABLE_METHODCALLS
-typedef UA_StatusCode (*UA_MethodCallback)(const UA_NodeId objectId, const UA_Variant *input,
-                                           UA_Variant *output, void *handle);
-/** Creates a serverside method including input- and output variable descriptions
- * 
- * @param server The server object.
- * 
- * @param browseName BrowseName to be used for the new method.
- * 
- * @param nodeId Requested NodeId for the new method. If a numeric ID with i=0 is used, the server will assign a random unused id.
- * 
- * @param parentNodeId Parent node containing this method. Note that an ObjectNode needs to reference the method with hasProperty in order for the method to be callable.
- * 
- * @param referenceTypeId Reference type ID to be used by the parent to reference the new method.
- * 
- * @param method Userspace Method/Function of type UA_MethodCallback to be called when a client invokes the method using the Call Service Set.
- * 
- * @param inputArgumentsSize Number of input arguments expected to be passed by a calling client.
- * 
- * @param inputArguments Description of input arguments expected to be passed by a calling client.
- * 
- * @param outputArgumentsSize Description of output arguments expected to be passed by a calling client.
- * 
- * @param outputArguments Description of output arguments expected to be passed by a calling client.
- * 
- * @param createdNodeId Actual nodeId of the new method node if UA_StatusCode indicates success. Can be used to determine the random unique ID assigned by the server if i=0 was passed as a nodeId.
- * 
- */
-UA_StatusCode UA_EXPORT
-UA_Server_addMethodNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId, 
-                        const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask, 
-                        UA_MethodCallback method, void *handle, UA_Int32 inputArgumentsSize, const UA_Argument *inputArguments, 
-                        UA_Int32 outputArgumentsSize, const UA_Argument *outputArguments,
-                        UA_NodeId *createdNodeId);
-#endif
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_dataType(UA_Server *server, UA_NodeId nodeId, UA_Variant *outDataType) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
 
 
-#ifndef _HAVE_UA_NODEITERATORCALLBACK_D
-#define _HAVE_UA_NODEITERATORCALLBACK_D
-typedef UA_StatusCode (*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle);
-#endif
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_valueRank(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outValueRank) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
 
 
-/** Iterate over all nodes referenced by parentNodeId by calling the callback function for each child node
- * 
- * @param server The server object.
- *
- * @param parentNodeId The NodeId of the parent whose references are to be iterated over
- *
- * @param callback The function of type UA_NodeIteratorCallback to be called for each referenced child
- *
- * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code otherwise.
- */
-UA_StatusCode UA_EXPORT UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId, UA_NodeIteratorCallback callback, void *handle);
-
-UA_StatusCode UA_EXPORT UA_Server_setAttributeValue(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void *value);
-// Attribute specific macros for setAttribute_are defined in ua_server_addressspace.c
-#define UA_Server_setAttribute_nodeId(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_NODEID, (UA_NodeId *) VALUE);
-#define UA_Server_setAttribute_nodeClass(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_NODECLASS, (UA_NodeClass *) VALUE);
-#define UA_Server_setAttribute_browseName(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_BROWSENAME, (UA_QualifiedName *) VALUE);
-#define UA_Server_setAttribute_displayName(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_DISPLAYNAME, (UA_LocalizedText *) VALUE);
-#define UA_Server_setAttribute_description(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_DESCRIPTION, (UA_LocalizedText *) VALUE);
-#define UA_Server_setAttribute_writeMask(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_WRITEMASK, (UA_UInt32 *) VALUE);
-#define UA_Server_setAttribute_userWriteMask(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_USERWRITEMASK, (UA_UInt32 *) VALUE);
-#define UA_Server_setAttribute_isAbstract(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_ISABSTRACT, (UA_Boolean *) VALUE);
-#define UA_Server_setAttribute_symmetric(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_SYMMETRIC, (UA_Boolean *) VALUE);
-#define UA_Server_setAttribute_inverseName(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_INVERSENAME, (UA_LocalizedText *) VALUE);
-#define UA_Server_setAttribute_containsNoLoops(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_CONTAINSNOLOOPS, (UA_Boolean *) VALUE);
-#define UA_Server_setAttribute_eventNotifier(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_EVENTNOTIFIER, (UA_Byte *) VALUE);
-#define UA_Server_setAttribute_value(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_VALUE, (UA_Variant *) VALUE);
-#define UA_Server_setAttribute_dataType(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_DATATYPE, (UA_NodeId *) VALUE);
-#define UA_Server_setAttribute_valueRank(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_VALUERANK, (UA_Int32 *) VALUE);
-#define UA_Server_setAttribute_arrayDimensions(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_ARRAYDIMENSIONS, (UA_Int32 *) VALUE);
-#define UA_Server_setAttribute_accessLevel(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_ACCESSLEVEL, (UA_UInt32 *) VALUE);
-#define UA_Server_setAttribute_userAccessLevel(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_USERACCESSLEVEL, (UA_UInt32 *) VALUE);
-#define UA_Server_setAttribute_minimumSamplingInterval(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, (UA_Double *) VALUE);
-#define UA_Server_setAttribute_historizing(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_HISTORIZING, (UA_Boolean *) VALUE);
-#define UA_Server_setAttribute_executable(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_EXECUTABLE, (UA_Boolean *) VALUE);
-#define UA_Server_setAttribute_userExecutable(SERVER, NODEID, VALUE) UA_Server_setAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_USEREXECUTABLE, (UA_Boolean *) VALUE);
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_arrayDimensions(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outArrayDimensions) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
 
 
-#ifdef ENABLE_METHODCALLS
-UA_StatusCode UA_EXPORT
-UA_Server_setAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_MethodCallback method, void *handle);
-#endif
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_accessLevel(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, outAccessLevel); }
 
 
-UA_StatusCode UA_EXPORT
-UA_Server_setAttribute_DataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource value);
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_minimumSamplingInterval(UA_Server *server, UA_NodeId nodeId,
+                                                   UA_Double *outMinimumSamplingInterval) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                                      outMinimumSamplingInterval); }
 
 
-/* Succeeds only if the node contains a variant value */
-UA_StatusCode UA_EXPORT
-UA_Server_setAttribute_valueCallback(UA_Server *server, UA_NodeId nodeId, UA_ValueCallback callback);
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_historizing(UA_Server *server, UA_NodeId nodeId, UA_Double *outHistorizing) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
 
 
-UA_StatusCode UA_EXPORT
-UA_Server_getAttributeValue(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void **value);
-#define UA_Server_getAttribute_nodeId(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_NODEID, (UA_NodeId **) VALUE);
-#define UA_Server_getAttribute_nodeClass(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_NODECLASS, (UA_NodeClass **) VALUE);
-#define UA_Server_getAttribute_browseName(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_BROWSENAME, (UA_QualifiedName **) VALUE);
-#define UA_Server_getAttribute_displayName(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_DISPLAYNAME, (UA_LocalizedText **) VALUE);
-#define UA_Server_getAttribute_description(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_DESCRIPTION, (UA_LocalizedText **) VALUE);
-#define UA_Server_getAttribute_writeMask(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_WRITEMASK, (UA_UInt32 **) VALUE);
-#define UA_Server_getAttribute_userWriteMask(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_USERWRITEMASK, (UA_UInt32 **) VALUE);
-#define UA_Server_getAttribute_isAbstract(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_ISABSTRACT, (UA_Boolean **) VALUE);
-#define UA_Server_getAttribute_symmetric(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_SYMMETRIC, (UA_Boolean **) VALUE);
-#define UA_Server_getAttribute_inverseName(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_INVERSENAME, (UA_LocalizedText **) VALUE);
-#define UA_Server_getAttribute_containsNoLoops(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_CONTAINSNOLOOPS, (UA_Boolean **) VALUE);
-#define UA_Server_getAttribute_eventNotifier(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_EVENTNOTIFIER, (UA_Byte **) VALUE);
-#define UA_Server_getAttribute_value(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_VALUE, (UA_Variant **) VALUE);
-#define UA_Server_getAttribute_dataType(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_DATATYPE, (UA_NodeId **) VALUE);
-#define UA_Server_getAttribute_valueRank(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_VALUERANK, (UA_Int32 **) VALUE);
-#define UA_Server_getAttribute_arrayDimensions(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_ARRAYDIMENSIONS, (UA_Int32 **) VALUE);
-#define UA_Server_getAttribute_accessLevel(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_ACCESSLEVEL, (UA_UInt32 **) VALUE);
-#define UA_Server_getAttribute_userAccessLevel(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_USERACCESSLEVEL, (UA_UInt32 **) VALUE);
-#define UA_Server_getAttribute_minimumSamplingInterval(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, (UA_Double **) VALUE);
-#define UA_Server_getAttribute_historizing(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_HISTORIZING, (UA_Boolean **) VALUE);
-#define UA_Server_getAttribute_executable(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_EXECUTABLE, (UA_Boolean **) VALUE);
-#define UA_Server_getAttribute_userExecutable(SERVER, NODEID, VALUE) UA_Server_getAttributeValue(SERVER, NODEID, UA_ATTRIBUTEID_USEREXECUTABLE, (UA_Boolean **) VALUE);
+static UA_INLINE UA_StatusCode
+UA_Server_getNodeAttribute_executable(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outExecutable) {
+    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE, outExecutable); }
 
 
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_getAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_MethodCallback *method);
+UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_MethodCallback *method);
 #endif
 #endif
 
 
-UA_StatusCode UA_EXPORT
-UA_Server_getAttribute_DataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource **value);
-
-/**
- * @param server The server object.
- *
- * @param job Pointer to the job that shall be added. The pointer is not freed but copied to an
- *        internal representation.
- *
- * @param interval The job shall be repeatedly executed with the given interval (in ms). The
- *        interval must be larger than 5ms. The first execution occurs at now() + interval at the
- *        latest.
- *
- * @param jobId Set to the guid of the repeated job. This can be used to cancel the job later on. If
- *        the pointer is null, the guid is not set.
- *
- * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code otherwise.
- */
-UA_StatusCode UA_EXPORT UA_Server_addRepeatedJob(UA_Server *server, UA_Job job, UA_UInt32 interval,
-                                                 UA_Guid *jobId);
-
-/**
- * Remove repeated job. The entry will be removed asynchronously during the next iteration of the
- * server main loop.
- *
- * @param server The server object.
- *
- * @param jobId The id of the job that shall be removed.
- *
- * @return Upon sucess, UA_STATUSCODE_GOOD is returned. An error code otherwise.
- */
-UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId);
-
-/**
- * Interface to the binary network layers. This structure is returned from the
- * function that initializes the network layer. The layer is already bound to a
- * specific port and listening. The functions in the structure are never called
- * in parallel but only sequentially from the server's main loop. So the network
- * layer does not need to be thread-safe.
- */
-typedef struct UA_ServerNetworkLayer {
-    UA_String discoveryUrl;
-    UA_Logger logger; ///< Set during _start
-
-    /**
-     * Starts listening on the the networklayer.
-     *
-     * @param nl The network layer
-     * @param logger The logger
-     * @return Returns UA_STATUSCODE_GOOD or an error code.
-     */
-    UA_StatusCode (*start)(struct UA_ServerNetworkLayer *nl, UA_Logger logger);
-    
-    /**
-     * Gets called from the main server loop and returns the jobs (accumulated messages and close
-     * events) for dispatch.
-     *
-     * @param nl The network layer
-     * @param jobs When the returned integer is >0, *jobs points to an array of UA_Job of the
-     * returned size.
-     * @param timeout The timeout during which an event must arrive in microseconds
-     * @return The size of the jobs array. If the result is negative, an error has occurred.
-     */
-    size_t (*getJobs)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
-
-    /**
-     * Closes the network connection and returns all the jobs that need to be finished before the
-     * network layer can be safely deleted.
-     *
-     * @param nl The network layer
-     * @param jobs When the returned integer is >0, jobs points to an array of UA_Job of the
-     * returned size.
-     * @return The size of the jobs array. If the result is negative, an error has occurred.
-     */
-    size_t (*stop)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs);
-
-    /** Deletes the network layer. Call only after a successful shutdown. */
-    void (*deleteMembers)(struct UA_ServerNetworkLayer *nl);
-} UA_ServerNetworkLayer;
-
-/**
- * Adds a network layer to the server. The network layer is destroyed together
- * with the server. Do not use it after adding it as it might be moved around on
- * the heap.
- */
-void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *networkLayer);
-
-/** @} */
-
+#ifdef UA_EXTERNAL_NAMESPACES
 /**
 /**
- * @ingroup nodestore
- *
- * @defgroup external_nodestore External Nodestore
- *
- * @brief An external application that manages its own data and data model
- *
- * To plug in outside data sources, one can use
+ * An external application that manages its own data and data model. To plug in
+ * outside data sources, one can use
  *
  *
  * - VariableNodes with a data source (functions that are called for read and write access)
  * - VariableNodes with a data source (functions that are called for read and write access)
  * - An external nodestore that is mapped to specific namespaces
  * - An external nodestore that is mapped to specific namespaces
@@ -580,44 +607,13 @@ typedef struct UA_ExternalNodeStore {
 	UA_ExternalNodeStore_delete destroy;
 	UA_ExternalNodeStore_delete destroy;
 } UA_ExternalNodeStore;
 } UA_ExternalNodeStore;
 
 
-#ifdef UA_EXTERNAL_NAMESPACES
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, const UA_String *url, UA_ExternalNodeStore *nodeStore);
-#endif /* UA_EXTERNAL_NAMESPACES*/
-/** @} */
-
-
-#ifndef _HAVE_UA_INSTANTIONCALLBACK_D
-#define _HAVE_UA_INSTANTIONCALLBACK_D
-typedef UA_StatusCode (*UA_InstantiationCallback)(UA_NodeId objectId, UA_NodeId definitionId, void *handle);
+UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, const UA_String *url,
+                               UA_ExternalNodeStore *nodeStore);
 #endif
 #endif
 
 
-typedef struct arrayOfNodeIds_s {
-  UA_Int32  size;
-  UA_NodeId *ids;
-} arrayOfNodeIds;
-
-UA_StatusCode UA_EXPORT
-UA_Server_appendInstanceOfSupertype(UA_Server *server, UA_NodeId nodeId, UA_NodeId appendToNodeId, 
-                                    arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs, 
-                                    UA_InstantiationCallback callback, arrayOfNodeIds *instantiatedTypes, 
-                                    void *handle);
-
-void UA_EXPORT
-UA_Server_addInstanceOf_instatiateChildNode(UA_Server *server, 
-                                                 arrayOfNodeIds *subtypeRefs, arrayOfNodeIds *componentRefs, arrayOfNodeIds *typedefRefs,
-                                                 UA_NodeId objectRoot, UA_InstantiationCallback callback, void *typeDefNode,
-                                                 UA_Boolean instantiateObjects, arrayOfNodeIds *instantiatedTypes, void *handle);
-                                                 
-UA_StatusCode UA_EXPORT
-UA_Server_addInstanceOf(UA_Server *server, UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId, 
-                        const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask, 
-                        const UA_ExpandedNodeId typeDefinition, UA_InstantiationCallback callback, void *handle, 
-                        UA_NodeId *createdNodeId);
-
 #ifdef __cplusplus
 #ifdef __cplusplus
-} // extern "C"
+}
 #endif
 #endif
 
 
 #endif /* UA_SERVER_H_ */
 #endif /* UA_SERVER_H_ */

+ 143 - 35
include/ua_types.h

@@ -318,11 +318,15 @@ void UA_EXPORT UA_String_init(UA_String *p);
 void UA_EXPORT UA_String_delete(UA_String *p);
 void UA_EXPORT UA_String_delete(UA_String *p);
 void UA_EXPORT UA_String_deleteMembers(UA_String *p);
 void UA_EXPORT UA_String_deleteMembers(UA_String *p);
 UA_StatusCode UA_EXPORT UA_String_copy(const UA_String *src, UA_String *dst);
 UA_StatusCode UA_EXPORT UA_String_copy(const UA_String *src, UA_String *dst);
-UA_String UA_EXPORT UA_String_fromChars(char const src[]); ///> Copies the char-array on the heap. Returns a null-string when alloc fails.
-UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2); ///> Compares two strings
+UA_String UA_EXPORT UA_String_fromChars(char const src[]); ///> Copies the content on the heap. Returns a null-string when alloc fails.
+UA_Boolean UA_EXPORT UA_String_equal(const UA_String *s1, const UA_String *s2); ///> Compares two strings
 UA_StatusCode UA_EXPORT UA_String_copyprintf(char const fmt[], UA_String *dst, ...); ///> Printf a char-array into a UA_String. Memory for the string data is allocated.
 UA_StatusCode UA_EXPORT UA_String_copyprintf(char const fmt[], UA_String *dst, ...); ///> Printf a char-array into a UA_String. Memory for the string data is allocated.
-#define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
-#define UA_STRING(CHARS) (UA_String) {strlen(CHARS), (UA_Byte*)CHARS }
+UA_EXPORT extern const UA_String UA_STRING_NULL;
+static UA_INLINE UA_String UA_STRING(char *chars) {
+    UA_String str;
+    str.length = strlen(chars);
+    str.data = (UA_Byte*)chars;
+    return str; }
 #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
 #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
 
 
 /* DateTime */
 /* DateTime */
@@ -350,7 +354,7 @@ UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
 
 
 /* Guid */
 /* Guid */
 UA_Guid UA_EXPORT * UA_Guid_new(void);
 UA_Guid UA_EXPORT * UA_Guid_new(void);
-static UA_INLINE void UA_Guid_init(UA_Guid *p) { *p = (UA_Guid){0,0,0,{0,0,0,0,0,0,0,0}}; }
+static UA_INLINE void UA_Guid_init(UA_Guid *p) { memset(p, 0, sizeof(UA_Guid)); }
 void UA_EXPORT UA_Guid_delete(UA_Guid *p);
 void UA_EXPORT UA_Guid_delete(UA_Guid *p);
 static UA_INLINE void UA_Guid_deleteMembers(UA_Guid *p) { }
 static UA_INLINE void UA_Guid_deleteMembers(UA_Guid *p) { }
 static UA_INLINE UA_StatusCode UA_Guid_copy(const UA_Guid *src, UA_Guid *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
 static UA_INLINE UA_StatusCode UA_Guid_copy(const UA_Guid *src, UA_Guid *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
@@ -362,17 +366,32 @@ static UA_INLINE UA_ByteString * UA_ByteString_new(void) { return UA_String_new(
 static UA_INLINE void UA_ByteString_init(UA_ByteString *p) { UA_String_init(p); }
 static UA_INLINE void UA_ByteString_init(UA_ByteString *p) { UA_String_init(p); }
 static UA_INLINE void UA_ByteString_delete(UA_ByteString *p) { UA_String_delete(p); }
 static UA_INLINE void UA_ByteString_delete(UA_ByteString *p) { UA_String_delete(p); }
 static UA_INLINE void UA_ByteString_deleteMembers(UA_ByteString *p) { UA_String_deleteMembers(p); }
 static UA_INLINE void UA_ByteString_deleteMembers(UA_ByteString *p) { UA_String_deleteMembers(p); }
-static UA_INLINE UA_StatusCode UA_ByteString_copy(const UA_ByteString *src, UA_ByteString *dst) { return UA_String_copy(src, dst); }
-#define UA_BYTESTRING_NULL (UA_ByteString) {-1, (UA_Byte*)0 }
+static UA_INLINE UA_StatusCode UA_ByteString_copy(const UA_ByteString *src, UA_ByteString *dst) {
+    return UA_String_copy(src, dst); }
 #define UA_ByteString_equal(string1, string2) UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
 #define UA_ByteString_equal(string1, string2) UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
-UA_StatusCode UA_EXPORT UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length); ///> Allocates memory of size length for the bytestring. The content is not set to zero.
+/* Allocates memory of size length for the bytestring. The content is not set to zero. */
+UA_StatusCode UA_EXPORT UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length);
+UA_EXPORT extern const UA_ByteString UA_BYTESTRING_NULL;
+static UA_INLINE UA_ByteString UA_BYTESTRING(char *chars) {
+    UA_ByteString str;
+    str.length = strlen(chars);
+    str.data = (UA_Byte*)chars;
+    return str; }
+static UA_INLINE UA_ByteString UA_BYTESTRING_ALLOC(const char *chars) {
+    UA_String str = UA_String_fromChars(chars);
+    UA_ByteString bstr;
+    bstr.length = str.length;
+    bstr.data = str.data;
+    return bstr;
+}
 
 
 /* XmlElement */
 /* XmlElement */
 static UA_INLINE UA_XmlElement * UA_XmlElement_new(void) { return UA_String_new(); }
 static UA_INLINE UA_XmlElement * UA_XmlElement_new(void) { return UA_String_new(); }
 static UA_INLINE void UA_XmlElement_init(UA_XmlElement *p) { UA_String_init(p); }
 static UA_INLINE void UA_XmlElement_init(UA_XmlElement *p) { UA_String_init(p); }
 static UA_INLINE void UA_XmlElement_delete(UA_XmlElement *p) { UA_String_delete(p); }
 static UA_INLINE void UA_XmlElement_delete(UA_XmlElement *p) { UA_String_delete(p); }
 static UA_INLINE void UA_XmlElement_deleteMembers(UA_XmlElement *p) { UA_String_deleteMembers(p); }
 static UA_INLINE void UA_XmlElement_deleteMembers(UA_XmlElement *p) { UA_String_deleteMembers(p); }
-static UA_INLINE UA_StatusCode UA_XmlElement_copy(const UA_XmlElement *src, UA_XmlElement *dst) { return UA_String_copy(src, dst); }
+static UA_INLINE UA_StatusCode UA_XmlElement_copy(const UA_XmlElement *src, UA_XmlElement *dst) {
+    return UA_String_copy(src, dst); }
 
 
 /* NodeId */
 /* NodeId */
 UA_NodeId UA_EXPORT * UA_NodeId_new(void);
 UA_NodeId UA_EXPORT * UA_NodeId_new(void);
@@ -392,13 +411,43 @@ UA_NodeId UA_EXPORT UA_NodeId_fromCharByteString(UA_UInt16 nsIndex, char identif
 UA_NodeId UA_EXPORT UA_NodeId_fromCharByteStringCopy(UA_UInt16 nsIndex, char const identifier[]);
 UA_NodeId UA_EXPORT UA_NodeId_fromCharByteStringCopy(UA_UInt16 nsIndex, char const identifier[]);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteString(UA_UInt16 nsIndex, UA_ByteString identifier);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteString(UA_UInt16 nsIndex, UA_ByteString identifier);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteString identifier);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteString identifier);
-#define UA_NODEID_NUMERIC(NSID, NUMERICID) UA_NodeId_fromInteger(NSID, NUMERICID)
-#define UA_NODEID_STRING(NSID, CHARS) UA_NodeId_fromCharString(NSID, CHARS)
-#define UA_NODEID_STRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharStringCopy(NSID, CHARS)
-#define UA_NODEID_GUID(NSID, GUID) UA_NodeId_fromGuid(NSID, GUID)
-#define UA_NODEID_BYTESTRING(NSID, CHARS) UA_NodeId_fromCharByteString(NSID, CHARS)
-#define UA_NODEID_BYTESTRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharByteStringCopy(NSID, CHARS)
-#define UA_NODEID_NULL (UA_NodeId){0, UA_NODEIDTYPE_NUMERIC, {0}}
+UA_EXPORT extern const UA_NodeId UA_NODEID_NULL;
+static UA_INLINE UA_NodeId UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_NUMERIC;
+    id.identifier.numeric = identifier;
+    return id; }
+static UA_INLINE UA_NodeId UA_NODEID_STRING(UA_UInt16 nsIndex, char *chars) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_STRING;
+    id.identifier.string = UA_STRING(chars);
+    return id; }
+static UA_INLINE UA_NodeId UA_NODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_STRING;
+    id.identifier.string = UA_STRING_ALLOC(chars);
+    return id; }
+static UA_INLINE UA_NodeId UA_NODEID_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_GUID;
+    id.identifier.guid = guid;
+    return id; }
+static UA_INLINE UA_NodeId UA_NODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
+    id.identifier.byteString = UA_BYTESTRING(chars);
+    return id; }
+static UA_INLINE UA_NodeId UA_NODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
+    id.identifier.byteString = UA_BYTESTRING_ALLOC(chars);
+    return id; }
 
 
 /* ExpandedNodeId */
 /* ExpandedNodeId */
 UA_ExpandedNodeId UA_EXPORT * UA_ExpandedNodeId_new(void);
 UA_ExpandedNodeId UA_EXPORT * UA_ExpandedNodeId_new(void);
@@ -406,18 +455,51 @@ void UA_EXPORT UA_ExpandedNodeId_init(UA_ExpandedNodeId *p);
 void UA_EXPORT UA_ExpandedNodeId_delete(UA_ExpandedNodeId *p);
 void UA_EXPORT UA_ExpandedNodeId_delete(UA_ExpandedNodeId *p);
 void UA_EXPORT UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p);
 void UA_EXPORT UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p);
 UA_StatusCode UA_EXPORT UA_ExpandedNodeId_copy(const UA_ExpandedNodeId *src, UA_ExpandedNodeId *dst);
 UA_StatusCode UA_EXPORT UA_ExpandedNodeId_copy(const UA_ExpandedNodeId *src, UA_ExpandedNodeId *dst);
-UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
-#define UA_EXPANDEDNODEID_NUMERIC(NSID, NUMERICID) (UA_ExpandedNodeId) {            \
-        .nodeId = {.namespaceIndex = NSID, .identifierType = UA_NODEIDTYPE_NUMERIC, \
-                   .identifier = {.numeric = NUMERICID }},                          \
-        .namespaceUri = {.length = -1, .data = (UA_Byte*)0}, .serverIndex = 0 }
+UA_EXPORT extern const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL;
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
+    UA_ExpandedNodeId id;
+    id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier);
+    id.serverIndex = 0;
+    id.namespaceUri = UA_STRING_NULL;
+    return id; }
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING(UA_UInt16 nsIndex, char *chars) {
+    UA_ExpandedNodeId id;
+    id.nodeId = UA_NODEID_STRING(nsIndex, chars);
+    id.serverIndex = 0;
+    id.namespaceUri = UA_STRING_NULL;
+    return id; }
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_ExpandedNodeId id;
+    id.nodeId = UA_NODEID_STRING_ALLOC(nsIndex, chars);
+    id.serverIndex = 0;
+    id.namespaceUri = UA_STRING_NULL;
+    return id; }
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_STRING_GUID(UA_UInt16 nsIndex, UA_Guid guid) {
+    UA_ExpandedNodeId id;
+    id.nodeId = UA_NODEID_GUID(nsIndex, guid);
+    id.serverIndex = 0;
+    id.namespaceUri = UA_STRING_NULL;
+    return id; }
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING(UA_UInt16 nsIndex, char *chars) {
+    UA_ExpandedNodeId id;
+    id.nodeId = UA_NODEID_BYTESTRING(nsIndex, chars);
+    id.serverIndex = 0;
+    id.namespaceUri = UA_STRING_NULL;
+    return id; }
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_BYTESTRING_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_ExpandedNodeId id;
+    id.nodeId = UA_NODEID_BYTESTRING_ALLOC(nsIndex, chars);
+    id.serverIndex = 0;
+    id.namespaceUri = UA_STRING_NULL;
+    return id; }
 
 
 /* StatusCode */
 /* StatusCode */
-UA_StatusCode UA_EXPORT * UA_StatusCode_new(void);
+static UA_INLINE UA_StatusCode * UA_StatusCode_new(void) { return (UA_StatusCode*)UA_Int32_new(); }
 static UA_INLINE void UA_StatusCode_init(UA_StatusCode *p) { *p = UA_STATUSCODE_GOOD; }
 static UA_INLINE void UA_StatusCode_init(UA_StatusCode *p) { *p = UA_STATUSCODE_GOOD; }
 void UA_EXPORT UA_StatusCode_delete(UA_StatusCode *p);
 void UA_EXPORT UA_StatusCode_delete(UA_StatusCode *p);
 static UA_INLINE void UA_StatusCode_deleteMembers(UA_StatusCode *p) { }
 static UA_INLINE void UA_StatusCode_deleteMembers(UA_StatusCode *p) { }
-static UA_INLINE UA_StatusCode UA_StatusCode_copy(const UA_StatusCode *src, UA_StatusCode *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+static UA_INLINE UA_StatusCode UA_StatusCode_copy(const UA_StatusCode *src, UA_StatusCode *dst) {
+    *dst = *src; return UA_STATUSCODE_GOOD; }
 
 
 /* QualifiedName */
 /* QualifiedName */
 UA_QualifiedName UA_EXPORT * UA_QualifiedName_new(void);
 UA_QualifiedName UA_EXPORT * UA_QualifiedName_new(void);
@@ -425,8 +507,16 @@ void UA_EXPORT UA_QualifiedName_init(UA_QualifiedName *p);
 void UA_EXPORT UA_QualifiedName_delete(UA_QualifiedName *p);
 void UA_EXPORT UA_QualifiedName_delete(UA_QualifiedName *p);
 void UA_EXPORT UA_QualifiedName_deleteMembers(UA_QualifiedName *p);
 void UA_EXPORT UA_QualifiedName_deleteMembers(UA_QualifiedName *p);
 UA_StatusCode UA_EXPORT UA_QualifiedName_copy(const UA_QualifiedName *src, UA_QualifiedName *dst);
 UA_StatusCode UA_EXPORT UA_QualifiedName_copy(const UA_QualifiedName *src, UA_QualifiedName *dst);
-#define UA_QUALIFIEDNAME(NSID, CHARS) (const UA_QualifiedName) { .namespaceIndex = NSID, .name = UA_STRING(CHARS) }
-#define UA_QUALIFIEDNAME_ALLOC(NSID, CHARS) (UA_QualifiedName) { .namespaceIndex = NSID, .name = UA_STRING_ALLOC(CHARS) }
+static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME(UA_UInt16 nsIndex, char *chars) {
+    UA_QualifiedName qn;
+    qn.namespaceIndex = nsIndex;
+    qn.name = UA_STRING(chars);
+    return qn; }
+static UA_INLINE UA_QualifiedName UA_QUALIFIEDNAME_ALLOC(UA_UInt16 nsIndex, const char *chars) {
+    UA_QualifiedName qn;
+    qn.namespaceIndex = nsIndex;
+    qn.name = UA_STRING_ALLOC(chars);
+    return qn; }
 
 
 /* LocalizedText */
 /* LocalizedText */
 UA_LocalizedText UA_EXPORT * UA_LocalizedText_new(void);
 UA_LocalizedText UA_EXPORT * UA_LocalizedText_new(void);
@@ -434,8 +524,16 @@ void UA_EXPORT UA_LocalizedText_init(UA_LocalizedText *p);
 void UA_EXPORT UA_LocalizedText_delete(UA_LocalizedText *p);
 void UA_EXPORT UA_LocalizedText_delete(UA_LocalizedText *p);
 void UA_EXPORT UA_LocalizedText_deleteMembers(UA_LocalizedText *p);
 void UA_EXPORT UA_LocalizedText_deleteMembers(UA_LocalizedText *p);
 UA_StatusCode UA_EXPORT UA_LocalizedText_copy(const UA_LocalizedText *src, UA_LocalizedText *dst);
 UA_StatusCode UA_EXPORT UA_LocalizedText_copy(const UA_LocalizedText *src, UA_LocalizedText *dst);
-#define UA_LOCALIZEDTEXT(LOCALE, TEXT) (const UA_LocalizedText) { .locale = UA_STRING(LOCALE), .text = UA_STRING(TEXT) }
-#define UA_LOCALIZEDTEXT_ALLOC(LOCALE, TEXT) (UA_LocalizedText) { .locale = UA_STRING_ALLOC(LOCALE), .text = UA_STRING_ALLOC(TEXT) }
+static UA_INLINE UA_LocalizedText UA_LOCALIZEDTEXT(char *locale, char *text) {
+    UA_LocalizedText lt;
+    lt.locale = UA_STRING(locale);
+    lt.text = UA_STRING(text);
+    return lt; }
+static UA_INLINE UA_LocalizedText UA_LOCALIZEDTEXT_ALLOC(const char *locale, const char *text) {
+    UA_LocalizedText lt;
+    lt.locale = UA_STRING_ALLOC(locale);
+    lt.text = UA_STRING_ALLOC(text);
+    return lt; }
 
 
 /* ExtensionObject */
 /* ExtensionObject */
 UA_ExtensionObject UA_EXPORT * UA_ExtensionObject_new(void);
 UA_ExtensionObject UA_EXPORT * UA_ExtensionObject_new(void);
@@ -491,7 +589,8 @@ UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, c
  * @param type The datatype of the array
  * @param type The datatype of the array
  * @return Indicates whether the operation succeeded or returns an error code
  * @return Indicates whether the operation succeeded or returns an error code
  */
  */
-UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 elements, const UA_DataType *type);
+UA_StatusCode UA_EXPORT
+UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 elements, const UA_DataType *type);
 
 
 /**
 /**
  * Set the variant to an array that is copied from an existing array.
  * Set the variant to an array that is copied from an existing array.
@@ -502,7 +601,8 @@ UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32
  * @param type The datatype of the array
  * @param type The datatype of the array
  * @return Indicates whether the operation succeeded or returns an error code
  * @return Indicates whether the operation succeeded or returns an error code
  */
  */
-UA_StatusCode UA_EXPORT UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32 elements, const UA_DataType *type);
+UA_StatusCode UA_EXPORT
+UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32 elements, const UA_DataType *type);
 
 
 /**
 /**
  * Copy the variant, but use only a subset of the (multidimensional) array into a variant. Returns
  * Copy the variant, but use only a subset of the (multidimensional) array into a variant. Returns
@@ -513,12 +613,13 @@ UA_StatusCode UA_EXPORT UA_Variant_setArrayCopy(UA_Variant *v, const void *array
  * @param range The range of the copied data
  * @param range The range of the copied data
  * @return Returns UA_STATUSCODE_GOOD or an error code
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
  */
-UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range);
+UA_StatusCode UA_EXPORT
+UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range);
 
 
 /**
 /**
  * Insert a range of data into an existing variant. The data array can't be reused afterwards if it
  * Insert a range of data into an existing variant. The data array can't be reused afterwards if it
- * contains types without a fixed size (e.g. strings) since they take on the lifetime of the
- * variant.
+ * contains types without a fixed size (e.g. strings) since the members are moved into the variant
+ * and take on its lifecycle.
  *
  *
  * @param v The variant
  * @param v The variant
  * @param dataArray The data array. The type must match the variant
  * @param dataArray The data array. The type must match the variant
@@ -526,7 +627,8 @@ UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *
  * @param range The range of where the new data is inserted
  * @param range The range of where the new data is inserted
  * @return Returns UA_STATUSCODE_GOOD or an error code
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
  */
-UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_Int32 dataArraySize, const UA_NumericRange range);
+UA_StatusCode UA_EXPORT
+UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_Int32 dataArraySize, const UA_NumericRange range);
 
 
 /**
 /**
  * Deep-copy a range of data into an existing variant.
  * Deep-copy a range of data into an existing variant.
@@ -537,7 +639,9 @@ UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_I
  * @param range The range of where the new data is inserted
  * @param range The range of where the new data is inserted
  * @return Returns UA_STATUSCODE_GOOD or an error code
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
  */
-UA_StatusCode UA_EXPORT UA_Variant_setRangeCopy(UA_Variant *v, const void *dataArray, UA_Int32 dataArraySize, const UA_NumericRange range);
+UA_StatusCode UA_EXPORT
+UA_Variant_setRangeCopy(UA_Variant *v, const void *dataArray, UA_Int32 dataArraySize,
+                        const UA_NumericRange range);
 
 
 /* DataValue */
 /* DataValue */
 UA_DataValue UA_EXPORT * UA_DataValue_new(void);
 UA_DataValue UA_EXPORT * UA_DataValue_new(void);
@@ -626,7 +730,7 @@ UA_StatusCode UA_EXPORT UA_copy(const void *src, void *dst, const UA_DataType *d
  */
  */
 void UA_EXPORT UA_deleteMembers(void *p, const UA_DataType *dataType);
 void UA_EXPORT UA_deleteMembers(void *p, const UA_DataType *dataType);
 
 
-void UA_EXPORT UA_deleteMembersUntil(void *p, const UA_DataType *dataType, UA_Int32 lastMember);
+void UA_EXPORT UA_deleteMembersUntil(void *p, const UA_DataType *dataType, size_t lastMember);
 
 
 /**
 /**
  * Deletes (frees) a variable and all of its content.
  * Deletes (frees) a variable and all of its content.
@@ -671,6 +775,10 @@ UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, void **dst, const UA_Data
  */
  */
 void UA_EXPORT UA_Array_delete(void *p, const UA_DataType *dataType, UA_Int32 elements);
 void UA_EXPORT UA_Array_delete(void *p, const UA_DataType *dataType, UA_Int32 elements);
 
 
+/**********************/
+/* Node Attribute Ids */
+/**********************/
+
 /* These are not generated from XML. Server *and* client need them. */
 /* These are not generated from XML. Server *and* client need them. */
 typedef enum {
 typedef enum {
     UA_ATTRIBUTEID_NODEID                  = 1,
     UA_ATTRIBUTEID_NODEID                  = 1,

+ 2 - 1
src/client/ua_client.c

@@ -420,11 +420,12 @@ static UA_StatusCode EndpointsHandshake(UA_Client *client) {
 
 
     UA_Boolean endpointFound = UA_FALSE;
     UA_Boolean endpointFound = UA_FALSE;
     UA_Boolean tokenFound = UA_FALSE;
     UA_Boolean tokenFound = UA_FALSE;
+    UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
     for(UA_Int32 i=0; i<response.endpointsSize; ++i){
     for(UA_Int32 i=0; i<response.endpointsSize; ++i){
         UA_EndpointDescription* endpoint = &response.endpoints[i];
         UA_EndpointDescription* endpoint = &response.endpoints[i];
         /* look out for an endpoint without security */
         /* look out for an endpoint without security */
         if(!UA_String_equal(&endpoint->securityPolicyUri,
         if(!UA_String_equal(&endpoint->securityPolicyUri,
-                            &UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None")))
+                            &securityNone))
             continue;
             continue;
         endpointFound = UA_TRUE;
         endpointFound = UA_TRUE;
         /* endpoint with no security found */
         /* endpoint with no security found */

+ 102 - 2
src/server/ua_nodes.c

@@ -40,11 +40,108 @@ static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 	return retval;
 	return retval;
 }
 }
 
 
+void UA_Node_deleteAnyNodeClass(UA_Node *node) {
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        UA_ObjectNode_delete((UA_ObjectNode*)node);
+        break;
+    case UA_NODECLASS_VARIABLE:
+        UA_VariableNode_delete((UA_VariableNode*)node);
+        break;
+    case UA_NODECLASS_METHOD:
+        UA_MethodNode_delete((UA_MethodNode*)node);
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        UA_ObjectTypeNode_delete((UA_ObjectTypeNode*)node);
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        UA_VariableTypeNode_delete((UA_VariableTypeNode*)node);
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode*)node);
+        break;
+    case UA_NODECLASS_DATATYPE:
+        UA_DataTypeNode_delete((UA_DataTypeNode*)node);
+        break;
+    case UA_NODECLASS_VIEW:
+        UA_ViewNode_delete((UA_ViewNode*)node);
+        break;
+    default:
+        break;
+    }
+}
+
+typedef UA_Node *(*UA_NewNodeFunction)(void);
+typedef UA_StatusCode (*UA_CopyNodeFunction)(const UA_Node *src, UA_Node *dst);
+typedef void (*UA_DeleteNodeFunction)(UA_Node *p);
+
+UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node) {
+    UA_NewNodeFunction newNode;
+    UA_CopyNodeFunction copyNode;
+    UA_DeleteNodeFunction deleteNode;
+
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        newNode = (UA_NewNodeFunction)UA_ObjectNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_ObjectNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_ObjectNode_delete;
+        break;
+    case UA_NODECLASS_VARIABLE:
+        newNode = (UA_NewNodeFunction)UA_VariableNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_VariableNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_VariableNode_delete;
+        break;
+    case UA_NODECLASS_METHOD:
+        newNode = (UA_NewNodeFunction)UA_MethodNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_MethodNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_MethodNode_delete;
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        newNode = (UA_NewNodeFunction)UA_ObjectTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_ObjectTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_ObjectTypeNode_delete;
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        newNode = (UA_NewNodeFunction)UA_VariableTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_VariableTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_VariableTypeNode_delete;
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        newNode = (UA_NewNodeFunction)UA_ReferenceTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_ReferenceTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_ReferenceTypeNode_delete;
+        break;
+    case UA_NODECLASS_DATATYPE:
+        newNode = (UA_NewNodeFunction)UA_DataTypeNode_new;
+        copyNode = (UA_CopyNodeFunction)UA_DataTypeNode_copy;
+        deleteNode = (UA_DeleteNodeFunction)UA_DataTypeNode_delete;
+        break;
+    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();
+    if(!copy)
+        return UA_NULL;
+    if(copyNode(node, copy) != UA_STATUSCODE_GOOD) {
+        deleteNode(copy);
+        return UA_NULL;
+    }
+    return copy;
+}
+
 /* UA_ObjectNode */
 /* UA_ObjectNode */
 void UA_ObjectNode_init(UA_ObjectNode *p) {
 void UA_ObjectNode_init(UA_ObjectNode *p) {
 	UA_Node_init((UA_Node*)p);
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_OBJECT;
     p->nodeClass = UA_NODECLASS_OBJECT;
     p->eventNotifier = 0;
     p->eventNotifier = 0;
+    p->instanceHandle = UA_NULL;
 }
 }
 
 
 UA_ObjectNode * UA_ObjectNode_new(void) {
 UA_ObjectNode * UA_ObjectNode_new(void) {
@@ -65,6 +162,7 @@ void UA_ObjectNode_delete(UA_ObjectNode *p) {
 
 
 UA_StatusCode UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
 UA_StatusCode UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
     dst->eventNotifier = src->eventNotifier;
     dst->eventNotifier = src->eventNotifier;
+    dst->instanceHandle = src->instanceHandle;
 	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 }
 }
 
 
@@ -73,6 +171,7 @@ void UA_ObjectTypeNode_init(UA_ObjectTypeNode *p) {
 	UA_Node_init((UA_Node*)p);
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_OBJECTTYPE;
     p->nodeClass = UA_NODECLASS_OBJECTTYPE;
     p->isAbstract = UA_FALSE;
     p->isAbstract = UA_FALSE;
+    p->instanceManagement = (UA_ObjectInstanceManagement){.constructor = UA_NULL, .destructor = UA_NULL};
 }
 }
 
 
 UA_ObjectTypeNode * UA_ObjectTypeNode_new(void) {
 UA_ObjectTypeNode * UA_ObjectTypeNode_new(void) {
@@ -93,6 +192,7 @@ void UA_ObjectTypeNode_delete(UA_ObjectTypeNode *p) {
 
 
 UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
 UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
     dst->isAbstract = src->isAbstract;
     dst->isAbstract = src->isAbstract;
+    dst->instanceManagement = src->instanceManagement;
 	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 }
 }
 
 
@@ -133,10 +233,10 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
 	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);
     dst->valueRank = src->valueRank;
     dst->valueRank = src->valueRank;
     dst->valueSource = src->valueSource;
     dst->valueSource = src->valueSource;
-    if(src->valueSource == UA_VALUESOURCE_VARIANT){
+    if(src->valueSource == UA_VALUESOURCE_VARIANT) {
         retval = UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
         retval = UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
         dst->value.variant.callback = src->value.variant.callback;
         dst->value.variant.callback = src->value.variant.callback;
-    }else
+    } else
         dst->value.dataSource = src->value.dataSource;
         dst->value.dataSource = src->value.dataSource;
     if(retval) {
     if(retval) {
         UA_VariableNode_deleteMembers(dst);
         UA_VariableNode_deleteMembers(dst);

+ 7 - 1
src/server/ua_nodes.h

@@ -27,6 +27,9 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
 } UA_Node;
 } UA_Node;
 
 
+void UA_Node_deleteAnyNodeClass(UA_Node *node);
+UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node);
+
 /**************/
 /**************/
 /* ObjectNode */
 /* ObjectNode */
 /**************/
 /**************/
@@ -34,6 +37,7 @@ typedef struct {
 typedef struct {
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
     UA_Byte eventNotifier;
     UA_Byte eventNotifier;
+    void *instanceHandle;
 } UA_ObjectNode;
 } UA_ObjectNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectNode)
 UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectNode)
 
 
@@ -44,6 +48,7 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectNode)
 typedef struct {
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
+    UA_ObjectInstanceManagement instanceManagement;
 } UA_ObjectTypeNode;
 } UA_ObjectTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 
 
@@ -134,8 +139,9 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_MethodNode)
 
 
 typedef struct {
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
-    UA_Boolean containsNoLoops;
     UA_Byte eventNotifier;
     UA_Byte eventNotifier;
+    /* <-- the same as objectnode until here --> */
+    UA_Boolean containsNoLoops;
 } UA_ViewNode;
 } UA_ViewNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_ViewNode)
 UA_TYPE_HANDLING_FUNCTIONS(UA_ViewNode)
 
 

Diferenças do arquivo suprimidas por serem muito extensas
+ 465 - 186
src/server/ua_server.c


Diferenças do arquivo suprimidas por serem muito extensas
+ 0 - 1754
src/server/ua_server_addressspace.c


+ 7 - 4
src/server/ua_server_binary.c

@@ -324,9 +324,6 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     case UA_NS0ID_BROWSENEXTREQUEST:
     case UA_NS0ID_BROWSENEXTREQUEST:
         INVOKE_SERVICE(BrowseNext, UA_TYPES_BROWSENEXTRESPONSE);
         INVOKE_SERVICE(BrowseNext, UA_TYPES_BROWSENEXTRESPONSE);
         break;
         break;
-    case UA_NS0ID_ADDREFERENCESREQUEST:
-        INVOKE_SERVICE(AddReferences, UA_TYPES_ADDREFERENCESRESPONSE);
-        break;
     case UA_NS0ID_REGISTERNODESREQUEST:
     case UA_NS0ID_REGISTERNODESREQUEST:
         INVOKE_SERVICE(RegisterNodes, UA_TYPES_REGISTERNODESRESPONSE);
         INVOKE_SERVICE(RegisterNodes, UA_TYPES_REGISTERNODESRESPONSE);
         break;
         break;
@@ -361,13 +358,19 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
         INVOKE_SERVICE(Call, UA_TYPES_CALLRESPONSE);
         INVOKE_SERVICE(Call, UA_TYPES_CALLRESPONSE);
 	break;
 	break;
 #endif
 #endif
-#ifdef ENABLE_ADDNODES 
+#ifdef ENABLE_NODEMANAGEMENT
     case UA_NS0ID_ADDNODESREQUEST:
     case UA_NS0ID_ADDNODESREQUEST:
         INVOKE_SERVICE(AddNodes, UA_TYPES_ADDNODESRESPONSE);
         INVOKE_SERVICE(AddNodes, UA_TYPES_ADDNODESRESPONSE);
         break;
         break;
+    case UA_NS0ID_ADDREFERENCESREQUEST:
+        INVOKE_SERVICE(AddReferences, UA_TYPES_ADDREFERENCESRESPONSE);
+        break;
     case UA_NS0ID_DELETENODESREQUEST:
     case UA_NS0ID_DELETENODESREQUEST:
       INVOKE_SERVICE(DeleteNodes, UA_TYPES_DELETENODESRESPONSE);
       INVOKE_SERVICE(DeleteNodes, UA_TYPES_DELETENODESRESPONSE);
       break;
       break;
+    case UA_NS0ID_DELETEREFERENCESREQUEST:
+      INVOKE_SERVICE(DeleteReferences, UA_TYPES_DELETEREFERENCESRESPONSE);
+      break;
 #endif
 #endif
     default: {
     default: {
         if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787)
         if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787)

+ 15 - 14
src/server/ua_server_internal.h

@@ -15,6 +15,7 @@
 #define ANONYMOUS_POLICY "open62541-anonymous-policy"
 #define ANONYMOUS_POLICY "open62541-anonymous-policy"
 #define USERNAME_POLICY "open62541-username-policy"
 #define USERNAME_POLICY "open62541-username-policy"
 
 
+#ifdef UA_EXTERNAL_NAMESPACES
 /** Mapping of namespace-id and url to an external nodestore. For namespaces
 /** Mapping of namespace-id and url to an external nodestore. For namespaces
     that have no mapping defined, the internal nodestore is used by default. */
     that have no mapping defined, the internal nodestore is used by default. */
 typedef struct UA_ExternalNamespace {
 typedef struct UA_ExternalNamespace {
@@ -22,6 +23,7 @@ typedef struct UA_ExternalNamespace {
 	UA_String url;
 	UA_String url;
 	UA_ExternalNodeStore externalNodeStore;
 	UA_ExternalNodeStore externalNodeStore;
 } UA_ExternalNamespace;
 } UA_ExternalNamespace;
+#endif
 
 
 struct UA_Server {
 struct UA_Server {
     /* Config */
     /* Config */
@@ -49,8 +51,11 @@ struct UA_Server {
     UA_NodeStore *nodestore;
     UA_NodeStore *nodestore;
     size_t namespacesSize;
     size_t namespacesSize;
     UA_String *namespaces;
     UA_String *namespaces;
+
+#ifdef UA_EXTERNAL_NAMESPACES
     size_t externalNamespacesSize;
     size_t externalNamespacesSize;
     UA_ExternalNamespace *externalNamespaces;
     UA_ExternalNamespace *externalNamespaces;
+#endif
      
      
     /* Jobs with a repetition interval */
     /* Jobs with a repetition interval */
     LIST_HEAD(RepeatedJobsList, RepeatedJobs) repeatedJobs;
     LIST_HEAD(RepeatedJobsList, RepeatedJobs) repeatedJobs;
@@ -74,23 +79,19 @@ struct UA_Server {
 #endif
 #endif
 };
 };
 
 
-void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg);
+/* The node is assumed to be "finished", i.e. no instantiation from inheritance is necessary */
+void UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
+                               const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                               UA_AddNodesResult *result);
 
 
-UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
-                                               const UA_ExpandedNodeId parentNodeId,
-                                               const UA_NodeId referenceTypeId);
+typedef UA_StatusCode (*UA_EditNodeCallback)(UA_Server *server, UA_Session*, UA_Node*, const void*);
 
 
-UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
-                                    const UA_NodeId referenceTypeId);
+/* Calls callback on the node. In the multithreaded case, the node is copied before and replaced in
+   the nodestore. */
+UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                                 UA_EditNodeCallback callback, const void *data);
 
 
-UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
-                                                const UA_AddReferencesItem *item);
-
-UA_StatusCode deleteOneWayReferenceWithSession(UA_Server *server, UA_Session *session, 
-                                               const UA_DeleteReferencesItem *item);
-
-UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, 
-                                            const UA_AddReferencesItem *item);
+void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg);
 
 
 UA_StatusCode UA_Server_addDelayedJob(UA_Server *server, UA_Job job);
 UA_StatusCode UA_Server_addDelayedJob(UA_Server *server, UA_Job job);
 
 

+ 5 - 0
src/server/ua_server_worker.c

@@ -628,6 +628,11 @@ UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
 }
 }
 
 
 UA_StatusCode UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads){
 UA_StatusCode UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads){
+    UA_Job *stopJobs;
+    for(size_t i = 0; i < server->networkLayersSize; i++) {
+        size_t stopJobsSize = server->networkLayers[i]->stop(server->networkLayers[i], &stopJobs);
+        processJobs(server, stopJobs, stopJobsSize);
+    }
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     /* Wait for all worker threads to finish */
     /* Wait for all worker threads to finish */
     for(UA_UInt32 i=0;i<nThreads;i++) {
     for(UA_UInt32 i=0;i<nThreads;i++) {

+ 27 - 32
src/server/ua_services.h

@@ -6,6 +6,7 @@
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_server.h"
 #include "ua_server.h"
 #include "ua_session.h"
 #include "ua_session.h"
+#include "ua_nodes.h"
 
 
 /**
 /**
  * @ingroup server
  * @ingroup server
@@ -25,9 +26,8 @@
  * @{
  * @{
  */
  */
 // Service_FindServers
 // Service_FindServers
-void Service_FindServers(UA_Server                    *server,
-                          const UA_FindServersRequest *request,
-                          UA_FindServersResponse      *response);
+void Service_FindServers(UA_Server *server, const UA_FindServersRequest *request,
+                         UA_FindServersResponse *response);
 /**
 /**
  * Returns the Endpoints supported by a Server and all of the configuration
  * Returns the Endpoints supported by a Server and all of the configuration
  * information required to establish a SecureChannel and a Session.
  * information required to establish a SecureChannel and a Session.
@@ -108,18 +108,26 @@ void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_Close
 /** Used to add one or more Nodes into the AddressSpace hierarchy. */
 /** Used to add one or more Nodes into the AddressSpace hierarchy. */
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response);
                       UA_AddNodesResponse *response);
+void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                             UA_NodeAttributes *attr, UA_AddNodesResult *result);
 
 
 /** Used to add one or more References to one or more Nodes. */
 /** Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
 void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
                            UA_AddReferencesResponse *response);
                            UA_AddReferencesResponse *response);
+UA_StatusCode Service_AddReferences_single(UA_Server *server, UA_Session *session,
+                                           const UA_AddReferencesItem *item);
 
 
 /** Used to delete one or more Nodes from the AddressSpace. */
 /** Used to delete one or more Nodes from the AddressSpace. */
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
                          UA_DeleteNodesResponse *response);
                          UA_DeleteNodesResponse *response);
+UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId *nodeId,
+                                         UA_Boolean deleteReferences);
 
 
 /** Used to delete one or more References of a Node. */
 /** Used to delete one or more References of a Node. */
 void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
 void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
                               UA_DeleteReferencesResponse *response);
                               UA_DeleteReferencesResponse *response);
+UA_StatusCode Service_DeleteReferences_single(UA_Server *server, UA_Session *session,
+                                              const UA_DeleteReferencesItem *item);
 
 
 /** @} */
 /** @} */
 
 
@@ -140,6 +148,9 @@ void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_D
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
                     UA_BrowseResponse *response);
                     UA_BrowseResponse *response);
 
 
+void Service_Browse_single(UA_Server *server, UA_Session *session, struct ContinuationPointEntry *cp,
+                           const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result);
+
 /**
 /**
  * Used to request the next set of Browse or BrowseNext response information
  * Used to request the next set of Browse or BrowseNext response information
  * that is too large to be sent in a single response. "Too large" in this
  * that is too large to be sent in a single response. "Too large" in this
@@ -202,12 +213,8 @@ UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range);
  */
  */
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
                   UA_ReadResponse *response);
                   UA_ReadResponse *response);
-
-/* Mock-Up of the function signature for Unit Tests */
-#ifdef BUILD_UNIT_TESTS
-void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
-                      const UA_ReadValueId *id, UA_DataValue *v);
-#endif
+void Service_Read_single(UA_Server *server, UA_Session *session, UA_TimestampsToReturn timestamps,
+                         const UA_ReadValueId *id, UA_DataValue *v);
 
 
 // Service_HistoryRead
 // Service_HistoryRead
 /**
 /**
@@ -219,10 +226,8 @@ void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
                    UA_WriteResponse *response);
                    UA_WriteResponse *response);
 
 
-/* Mock-Up of the function signature for Unit Tests */
-#ifdef BUILD_UNIT_TESTS
-UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue);
-#endif
+/** Single attribute writes are exposed to the userspace. The wvalue may be destroyed (deleteMembers) */
+UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_WriteValue *wvalue);
 
 
 // Service_HistoryUpdate
 // Service_HistoryUpdate
 /** @} */
 /** @} */
@@ -235,7 +240,10 @@ UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue);
  *
  *
  * @{
  * @{
  */
  */
-// Service_Call
+#ifdef ENABLE_METHODCALLS
+void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,
+                  UA_CallResponse *response);
+#endif
 /** @} */
 /** @} */
 
 
 #ifdef ENABLE_SUBSCRIPTIONS
 #ifdef ENABLE_SUBSCRIPTIONS
@@ -291,29 +299,16 @@ void Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
 void Service_Publish(UA_Server *server, UA_Session *session,
 void Service_Publish(UA_Server *server, UA_Session *session,
                      const UA_PublishRequest *request, UA_PublishResponse *response);
                      const UA_PublishRequest *request, UA_PublishResponse *response);
                          
                          
-//~ Service_ModifySubscription
-//~ Service_SetPublishingMode
-//~ UA_Int32 Service_SetPublishingMode(UA_Server *server, UA_Session *session,
-                                    //~ const UA_SetPublishingModeRequest *request,
-                                    //~ UA_SetPublishingModeResponse *response);
+// Service_ModifySubscription
+// Service_SetPublishingMode
+// UA_Int32 Service_SetPublishingMode(UA_Server *server, UA_Session *session,
+                                  // const UA_SetPublishingModeRequest *request,
+                                  // UA_SetPublishingModeResponse *response);
 // Service_Republish
 // Service_Republish
 // Service_TransferSubscription
 // Service_TransferSubscription
 // Service_DeleteSubscription
 // Service_DeleteSubscription
 /** @} */
 /** @} */
 #endif
 #endif
 
 
-#ifdef ENABLE_METHODCALLS
-/**
- * @name Call Service Set
- *
- * Calls are used to execute serverside methods.
- *
- * @{
- */
-void Service_Call(UA_Server *server, UA_Session *session,
-                  const UA_CallRequest *request,
-                  UA_CallResponse *response);
-/** @} */
-#endif
 #endif /* UA_SERVICES_H_ */
 #endif /* UA_SERVICES_H_ */
 /** @} */
 /** @} */

+ 375 - 372
src/server/ua_services_attribute.c

@@ -5,16 +5,20 @@
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 #include "ua_util.h"
 #include "ua_util.h"
 
 
+/******************/
+/* Read Attribute */
+/******************/
+
 #ifndef BUILD_UNIT_TESTS
 #ifndef BUILD_UNIT_TESTS
 static
 static
 #endif
 #endif
 UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range) {
 UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range) {
     if(str.length < 0 || str.length >= 1023)
     if(str.length < 0 || str.length >= 1023)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
-#ifdef NO_ALLOCA
-    char cstring[str.length+1];
+#ifdef _MSC_VER
+    char *cstring = (char*)UA_alloca(sizeof(char)*str.length+1);
 #else
 #else
-    char *cstring = UA_alloca(str.length+1);
+    char cstring[str.length+1];
 #endif
 #endif
     UA_memcpy(cstring, str.data, str.length);
     UA_memcpy(cstring, str.data, str.length);
     cstring[str.length] = 0;
     cstring[str.length] = 0;
@@ -74,14 +78,12 @@ UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range) {
 
 
 #define CHECK_NODECLASS(CLASS)                                  \
 #define CHECK_NODECLASS(CLASS)                                  \
     if(!(node->nodeClass & (CLASS))) {                          \
     if(!(node->nodeClass & (CLASS))) {                          \
-        v->hasStatus = UA_TRUE;                                 \
-        v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;        \
+        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;           \
         break;                                                  \
         break;                                                  \
     }
     }
 
 
 static void handleServerTimestamps(UA_TimestampsToReturn timestamps, UA_DataValue* v) {
 static void handleServerTimestamps(UA_TimestampsToReturn timestamps, UA_DataValue* v) {
-	if (v && (timestamps == UA_TIMESTAMPSTORETURN_SERVER
-			|| timestamps == UA_TIMESTAMPSTORETURN_BOTH)) {
+	if(v && (timestamps == UA_TIMESTAMPSTORETURN_SERVER || timestamps == UA_TIMESTAMPSTORETURN_BOTH)) {
 		v->hasServerTimestamp = UA_TRUE;
 		v->hasServerTimestamp = UA_TRUE;
 		v->serverTimestamp = UA_DateTime_now();
 		v->serverTimestamp = UA_DateTime_now();
 	}
 	}
@@ -94,20 +96,88 @@ static void handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValu
 	}
 	}
 }
 }
 
 
+static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_TimestampsToReturn timestamps,
+                                          const UA_ReadValueId *id, UA_DataValue *v) {
+    UA_NumericRange range;
+    UA_NumericRange *rangeptr = UA_NULL;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(id->indexRange.length > 0) {
+        retval = parse_numericrange(id->indexRange, &range);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        rangeptr = &range;
+    }
+
+    if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
+        if(vn->value.variant.callback.onRead)
+            vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId,
+                                              &v->value, rangeptr);
+        if(rangeptr)
+            retval = UA_Variant_copyRange(&vn->value.variant.value, &v->value, range);
+        else
+            retval = UA_Variant_copy(&vn->value.variant.value, &v->value);
+        if(retval == UA_STATUSCODE_GOOD)
+            handleSourceTimestamps(timestamps, v);
+    } else {
+        UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
+                                      timestamps == UA_TIMESTAMPSTORETURN_BOTH);
+        retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId,
+                                           sourceTimeStamp, rangeptr, v);
+    }
+
+    if(rangeptr)
+        UA_free(range.dimensions);
+    return retval;
+}
+
+static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataValue *v) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
+        retval = UA_Variant_setScalarCopy(&v->value, &vn->value.variant.value.type->typeId,
+                                          &UA_TYPES[UA_TYPES_NODEID]);
+    } else {
+        /* Read from the datasource to see the data type */
+        UA_DataValue val;
+        UA_DataValue_init(&val);
+        retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, UA_FALSE, UA_NULL, &val);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
+        UA_DataValue_deleteMembers(&val);
+    }
+    return retval;
+}
+
+static UA_StatusCode getVariableNodeArrayDimensions(const UA_VariableNode *vn, UA_DataValue *v) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
+        retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.value.arrayDimensions,
+                                         vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+    } else {
+        /* Read the datasource to see the array dimensions */
+        UA_DataValue val;
+        UA_DataValue_init(&val);
+        retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, UA_FALSE, UA_NULL, &val);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions,
+                                         val.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+        UA_DataValue_deleteMembers(&val);
+    }
+    return retval;
+}
+
+static const UA_String binEncoding = {sizeof("DefaultBinary")-1, (UA_Byte*)"DefaultBinary"};
+/* clang complains about unused variables */
+// static const UA_String xmlEncoding = {sizeof("DefaultXml")-1, (UA_Byte*)"DefaultXml"};
+
 /** Reads a single attribute from a node in the nodestore. */
 /** Reads a single attribute from a node in the nodestore. */
-#ifndef BUILD_UNIT_TESTS
-static
-#endif
-void readValue(UA_Server *server, UA_TimestampsToReturn timestamps, const UA_ReadValueId *id, UA_DataValue *v) {
-    UA_String binEncoding = UA_STRING("DefaultBinary");
-    UA_String xmlEncoding = UA_STRING("DefaultXml");
-	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;
-		}
+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 && !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
+           v->hasStatus = UA_TRUE;
+           v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
+           return;
 	}
 	}
 
 
 	//index range for a non-value
 	//index range for a non-value
@@ -117,224 +187,131 @@ void readValue(UA_Server *server, UA_TimestampsToReturn timestamps, const UA_Rea
 		return;
 		return;
 	}
 	}
 
 
-    UA_Node const *node = UA_NodeStore_get(server->nodestore, &(id->nodeId));
+    UA_Node const *node = UA_NodeStore_get(server->nodestore, &id->nodeId);
     if(!node) {
     if(!node) {
         v->hasStatus = UA_TRUE;
         v->hasStatus = UA_TRUE;
         v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
         v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
         return;
         return;
     }
     }
 
 
+    /* When setting the value fails in the switch, we get an error code and set hasValue to false */
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    v->hasValue = UA_TRUE;
+
     switch(id->attributeId) {
     switch(id->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODEID:
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
+        retval = UA_Variant_setScalarCopy(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
         break;
         break;
     case UA_ATTRIBUTEID_NODECLASS:
     case UA_ATTRIBUTEID_NODECLASS:
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
+        retval = UA_Variant_setScalarCopy(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
         break;
         break;
     case UA_ATTRIBUTEID_BROWSENAME:
     case UA_ATTRIBUTEID_BROWSENAME:
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+        retval = UA_Variant_setScalarCopy(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
         break;
         break;
     case UA_ATTRIBUTEID_DISPLAYNAME:
     case UA_ATTRIBUTEID_DISPLAYNAME:
-        retval |= UA_Variant_setScalarCopy(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
-        if(retval == UA_STATUSCODE_GOOD)
-            v->hasValue = UA_TRUE;
+        retval = UA_Variant_setScalarCopy(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
         break;
     case UA_ATTRIBUTEID_DESCRIPTION:
     case UA_ATTRIBUTEID_DESCRIPTION:
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        retval = UA_Variant_setScalarCopy(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
         break;
     case UA_ATTRIBUTEID_WRITEMASK:
     case UA_ATTRIBUTEID_WRITEMASK:
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
+        retval = UA_Variant_setScalarCopy(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
         break;
     case UA_ATTRIBUTEID_USERWRITEMASK:
     case UA_ATTRIBUTEID_USERWRITEMASK:
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
+        retval = UA_Variant_setScalarCopy(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
         break;
     case UA_ATTRIBUTEID_ISABSTRACT:
     case UA_ATTRIBUTEID_ISABSTRACT:
-        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE |
-                        UA_NODECLASS_DATATYPE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->isAbstract,
+        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE |
+                        UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->isAbstract,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_SYMMETRIC:
     case UA_ATTRIBUTEID_SYMMETRIC:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->symmetric,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_INVERSENAME:
     case UA_ATTRIBUTEID_INVERSENAME:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->inverseName,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName,
                                           &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
                                           &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
         break;
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode *)node)->containsNoLoops,
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->containsNoLoops,
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
                                           &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
-        v->hasValue = UA_TRUE;
-        if(node->nodeClass == UA_NODECLASS_VIEW){
-        	retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode *)node)->eventNotifier,
-                                          	  &UA_TYPES[UA_TYPES_BYTE]);
-        } else {
-        	retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ObjectNode *)node)->eventNotifier,
-                                              &UA_TYPES[UA_TYPES_BYTE]);
-        }
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->eventNotifier,
+                                          &UA_TYPES[UA_TYPES_BYTE]);
         break;
         break;
-
     case UA_ATTRIBUTEID_VALUE:
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        {
-        	if(node->nodeClass != UA_NODECLASS_VARIABLE) {
-    			v->hasValue = UA_FALSE;
-    			handleSourceTimestamps(timestamps, v);
-            }
-
-            UA_NumericRange range;
-            UA_NumericRange *rangeptr = UA_NULL;
-            if(id->indexRange.length > 0) {
-                retval = parse_numericrange(id->indexRange, &range);
-                if(retval != UA_STATUSCODE_GOOD)
-                    break;
-                rangeptr = &range;
-            }
-
-            const UA_VariableNode *vn = (const UA_VariableNode*)node;
-
-            if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-                if(rangeptr)
-                    retval |= UA_Variant_copyRange(&vn->value.variant.value, &v->value, range);
-                else
-                    retval |= UA_Variant_copy(&vn->value.variant.value, &v->value);
-                if(retval == UA_STATUSCODE_GOOD) {
-                    v->hasValue = UA_TRUE;
-                    handleSourceTimestamps(timestamps, v);
-                }
-                if(vn->value.variant.callback.onRead)
-                    vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId, &v->value, rangeptr);
-            } else {
-                UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE || timestamps == UA_TIMESTAMPSTORETURN_BOTH);
-                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, sourceTimeStamp, rangeptr, v);
-            }
-
-            if(rangeptr)
-                UA_free(range.dimensions);
-        }
+        retval = getVariableNodeValue((const UA_VariableNode*)node, timestamps, id, v);
         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);
-        const UA_VariableNode *vn = (const UA_VariableNode*)node;
-        if(vn->valueSource == UA_VALUESOURCE_VARIANT){
-            retval = UA_Variant_setScalarCopy(&v->value, &vn->value.variant.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
-            if(vn->value.variant.callback.onRead)
-                vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId, &vn->value.variant.value, UA_NULL);
-        } else {
-            UA_DataValue val;
-            UA_DataValue_init(&val);
-            retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, UA_FALSE, UA_NULL, &val);
-            if(retval != UA_STATUSCODE_GOOD)
-                break;
-            retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
-            UA_DataValue_deleteMembers(&val);
-        }
-
-        if(retval == UA_STATUSCODE_GOOD)
-            v->hasValue = UA_TRUE;
-        }
+        retval = getVariableNodeDataType((const UA_VariableNode*)node, v);
         break;
         break;
-
     case UA_ATTRIBUTEID_VALUERANK:
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode *)node)->valueRank, &UA_TYPES[UA_TYPES_INT32]);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode*)node)->valueRank,
+                                           &UA_TYPES[UA_TYPES_INT32]);
         break;
         break;
-
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        {
-            const UA_VariableNode *vn = (const UA_VariableNode *)node;
-            if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-                retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.value.arrayDimensions, vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
-                if(retval == UA_STATUSCODE_GOOD)
-                    v->hasValue = UA_TRUE;
-            } else {
-                UA_DataValue val;
-                UA_DataValue_init(&val);
-                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, node->nodeId, UA_FALSE, UA_NULL, &val);
-                if(retval != UA_STATUSCODE_GOOD)
-                    break;
-                retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions, val.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
-                UA_DataValue_deleteMembers(&val);
-            }
-        }
+        retval = getVariableNodeArrayDimensions((const UA_VariableNode*)node, v);
         break;
         break;
-
     case UA_ATTRIBUTEID_ACCESSLEVEL:
     case UA_ATTRIBUTEID_ACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->accessLevel, &UA_TYPES[UA_TYPES_BYTE]);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->accessLevel,
+                                          &UA_TYPES[UA_TYPES_BYTE]);
         break;
         break;
-
     case UA_ATTRIBUTEID_USERACCESSLEVEL:
     case UA_ATTRIBUTEID_USERACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->userAccessLevel, &UA_TYPES[UA_TYPES_BYTE]);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->userAccessLevel,
+                                          &UA_TYPES[UA_TYPES_BYTE]);
         break;
         break;
-
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->minimumSamplingInterval, &UA_TYPES[UA_TYPES_DOUBLE]);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval,
+                                          &UA_TYPES[UA_TYPES_DOUBLE]);
         break;
         break;
-
     case UA_ATTRIBUTEID_HISTORIZING:
     case UA_ATTRIBUTEID_HISTORIZING:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->historizing, &UA_TYPES[UA_TYPES_BOOLEAN]);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->historizing,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
-
     case UA_ATTRIBUTEID_EXECUTABLE:
     case UA_ATTRIBUTEID_EXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode *)node)->executable, &UA_TYPES[UA_TYPES_BOOLEAN]);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->executable,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
-
     case UA_ATTRIBUTEID_USEREXECUTABLE:
     case UA_ATTRIBUTEID_USEREXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        v->hasValue = UA_TRUE;
-        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode *)node)->userExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]);
+        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->userExecutable,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
-
     default:
     default:
-        v->hasStatus = UA_TRUE;
-        v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
+        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
         break;
         break;
     }
     }
 
 
     UA_NodeStore_release(node);
     UA_NodeStore_release(node);
 
 
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
+        v->hasValue = UA_FALSE;
         v->hasStatus = UA_TRUE;
         v->hasStatus = UA_TRUE;
         v->status = retval;
         v->status = retval;
     }
     }
 
 
+    // Todo: what if the timestamp from the datasource are already present?
     handleServerTimestamps(timestamps, v);
     handleServerTimestamps(timestamps, v);
 }
 }
 
 
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
                   UA_ReadResponse *response) {
                   UA_ReadResponse *response) {
-
     if(request->nodesToReadSize <= 0) {
     if(request->nodesToReadSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
         return;
@@ -361,13 +338,8 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
     }
 
 
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
-#ifdef NO_ALLOCA
     UA_Boolean isExternal[size];
     UA_Boolean isExternal[size];
     UA_UInt32 indices[size];
     UA_UInt32 indices[size];
-#else
-    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
-    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-#endif /*NO_ALLOCA */
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     for(size_t j = 0;j<server->externalNamespacesSize;j++) {
     for(size_t j = 0;j<server->externalNamespacesSize;j++) {
         size_t indexSize = 0;
         size_t indexSize = 0;
@@ -390,7 +362,8 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
 #endif
 #endif
-            readValue(server, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]);
+            Service_Read_single(server, session, request->timestampsToReturn,
+                                &request->nodesToRead[i], &response->results[i]);
     }
     }
 
 
 #ifdef EXTENSION_STATELESS
 #ifdef EXTENSION_STATELESS
@@ -427,234 +400,269 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
     }
 #endif
 #endif
 }
 }
-#define SETATTRIBUTE_IF_DATATYPE_IS(EXP_DT)                                                                             \
-/* The Userspace setAttribute expects the value being passed being the correct type and has no own means for checking   \
-   We need to check for setAttribute if the dataType is correct                                                         \
-*/                                                                                                                      \
-expectType = UA_NODEID_NUMERIC(0, UA_NS0ID_##EXP_DT);                                                                   \
-if (! UA_NodeId_equal(&expectType, &wvalue->value.value.type->typeId))                                                  \
-  retval |= UA_STATUSCODE_BADTYPEMISMATCH;                                                                              \
-else                                                                                                                    \
-  retval = UA_Server_setAttributeValue(server, wvalue->nodeId, wvalue->attributeId, (void *) wvalue->value.value.data); \
-
-#ifndef BUILD_UNIT_TESTS
-static
-#endif
-UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
 
 
-    /* is there a value at all */
-    if(!wvalue->value.hasValue)
-        return UA_STATUSCODE_BADTYPEMISMATCH;
+/*******************/
+/* Write Attribute */
+/*******************/
 
 
-    // we might repeat writing, e.g. when the node got replaced mid-work
-    UA_Boolean done = UA_FALSE;
-    UA_NodeId expectType;
-    while(!done) {
-        const UA_Node *node = UA_NodeStore_get(server->nodestore, &wvalue->nodeId);
+UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                                 UA_EditNodeCallback callback, const void *data) {
+    UA_StatusCode retval;
+    do {
+        const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
         if(!node)
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
+#ifndef UA_MULTITHREADING
+        retval = callback(server, session, (UA_Node*)(uintptr_t)node, data);
+        UA_NodeStore_release(node);
+        return retval;
+#else
+        UA_Node *copy = UA_Node_copyAnyNodeClass(node);
+        UA_NodeStore_release(node);
+        if(!copy)
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        retval = callback(server, session, copy, data);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_Node_deleteAnyNodeClass(copy);
+            return retval;
+        }
+        retval = UA_NodeStore_replace(server->nodestore, node, copy, UA_NULL);
+        if(retval != UA_STATUSCODE_GOOD)
+            UA_Node_deleteAnyNodeClass(copy);
+#endif
+    } while(retval != UA_STATUSCODE_GOOD);
+    return UA_STATUSCODE_GOOD;
+}
 
 
-        switch(wvalue->attributeId) {
-        case UA_ATTRIBUTEID_BROWSENAME:
-          SETATTRIBUTE_IF_DATATYPE_IS(QUALIFIEDNAME)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_DISPLAYNAME:
-          SETATTRIBUTE_IF_DATATYPE_IS(LOCALIZEDTEXT)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_DESCRIPTION:
-          SETATTRIBUTE_IF_DATATYPE_IS(LOCALIZEDTEXT)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_WRITEMASK:
-          SETATTRIBUTE_IF_DATATYPE_IS(UINT32)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_USERWRITEMASK:
-          SETATTRIBUTE_IF_DATATYPE_IS(UINT32)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_ISABSTRACT:
-          SETATTRIBUTE_IF_DATATYPE_IS(BOOLEAN)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_SYMMETRIC:
-          SETATTRIBUTE_IF_DATATYPE_IS(BOOLEAN)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_INVERSENAME:
-          SETATTRIBUTE_IF_DATATYPE_IS(LOCALIZEDTEXT)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
-          SETATTRIBUTE_IF_DATATYPE_IS(BOOLEAN)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_EVENTNOTIFIER:
-          SETATTRIBUTE_IF_DATATYPE_IS(BYTE)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_VALUERANK:
-          SETATTRIBUTE_IF_DATATYPE_IS(INT32)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
-          SETATTRIBUTE_IF_DATATYPE_IS(INT32)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_ACCESSLEVEL:
-          SETATTRIBUTE_IF_DATATYPE_IS(UINT32)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_USERACCESSLEVEL:
-          SETATTRIBUTE_IF_DATATYPE_IS(UINT32)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
-          SETATTRIBUTE_IF_DATATYPE_IS(DOUBLE)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_HISTORIZING:
-          SETATTRIBUTE_IF_DATATYPE_IS(BOOLEAN)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_EXECUTABLE:
-          SETATTRIBUTE_IF_DATATYPE_IS(BOOLEAN)
-          done = UA_TRUE;
-          break;
-        case UA_ATTRIBUTEID_USEREXECUTABLE:
-          SETATTRIBUTE_IF_DATATYPE_IS(BOOLEAN)
-          done = UA_TRUE;
-          break;
-        // The value logic implemented by jpfr is far more advanced that that in the userspace, so we use that
-        // here
-        case UA_ATTRIBUTEID_VALUE: {
-            if(node->nodeClass != UA_NODECLASS_VARIABLE &&
-               node->nodeClass != UA_NODECLASS_VARIABLETYPE) {
-                retval = UA_STATUSCODE_BADTYPEMISMATCH;
-                break;
-            }
+#define CHECK_DATATYPE(EXP_DT)                                          \
+    if(!wvalue->value.hasValue ||                                       \
+       &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type ||      \
+       !UA_Variant_isScalar(&wvalue->value.value)) {                    \
+        retval = UA_STATUSCODE_BADTYPEMISMATCH;                         \
+        break;                                                          \
+    }
 
 
-            /* parse the range */
-            UA_Boolean hasRange = UA_FALSE;
-            UA_NumericRange range;
-            if(wvalue->indexRange.length > 0) {
-                retval = parse_numericrange(wvalue->indexRange, &range);
-                if(retval != UA_STATUSCODE_GOOD)
-                    break;
-                hasRange = UA_TRUE;
-            }
+#define CHECK_NODECLASS_WRITE(CLASS)                                    \
+    if((node->nodeClass & (CLASS)) == 0) {                              \
+        retval = UA_STATUSCODE_BADNODECLASSINVALID;                     \
+        break;                                                          \
+    }
 
 
-            /* the relevant members are similar for variables and variabletypes */
-            const UA_VariableNode *vn = (const UA_VariableNode*)node;
-            if(vn->valueSource == UA_VALUESOURCE_DATASOURCE) {
-                if(!vn->value.dataSource.write) {
-                    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-                    goto clean_up_range;
-                }
-                // todo: writing ranges
-                if(hasRange)
-                    retval = vn->value.dataSource.write(vn->value.dataSource.handle, wvalue->nodeId, &wvalue->value.value, &range);
-                else
-                    retval = vn->value.dataSource.write(vn->value.dataSource.handle, wvalue->nodeId, &wvalue->value.value, UA_NULL);
-                done = UA_TRUE;
-                goto clean_up_range;
-            }
-            const UA_Variant *oldV = &vn->value.variant.value;
-
-            /* the nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings */
-            if(!UA_NodeId_equal(&oldV->type->typeId, &wvalue->value.value.type->typeId)) {
-                if(oldV->type->namespaceZero && wvalue->value.value.type->namespaceZero &&
-                   oldV->type->typeIndex == wvalue->value.value.type->typeIndex)
-                    /* An enum was sent as an int32, or an opaque type as a bytestring. This is
-                       detected with the typeIndex indicated the "true" datatype. */
-
-                    wvalue->value.value.type = oldV->type;
-                else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
-                        wvalue->value.value.type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
-                        UA_Variant_isScalar(&wvalue->value.value)) {
-                    /* a string is written to a byte array */
-                    UA_ByteString *str = (UA_ByteString*) wvalue->value.value.data;
-                    wvalue->value.value.arrayLength = str->length;
-                    wvalue->value.value.data = str->data;
-                    wvalue->value.value.type = &UA_TYPES[UA_TYPES_BYTE];
-                    UA_free(str);
-                } else {
-                    retval = UA_STATUSCODE_BADTYPEMISMATCH;
-                    goto clean_up_range;
-                }
-            }
+static UA_StatusCode
+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;
+}
 
 
-            /* copy the node */
-            UA_VariableNode *newVn = (node->nodeClass == UA_NODECLASS_VARIABLE) ?
-                UA_VariableNode_new() : (UA_VariableNode*)UA_VariableTypeNode_new();
-            if(!newVn) {
-                retval = UA_STATUSCODE_BADOUTOFMEMORY;
-                goto clean_up_range;
-            }
-            retval = (node->nodeClass == UA_NODECLASS_VARIABLE) ? UA_VariableNode_copy(vn, newVn) : 
-                UA_VariableTypeNode_copy((const UA_VariableTypeNode*)vn, (UA_VariableTypeNode*)newVn);
-            if(retval != UA_STATUSCODE_GOOD)
-                goto clean_up;
-                
-            /* insert the new value */
-            if(hasRange)
-                retval = UA_Variant_setRangeCopy(&newVn->value.variant.value, wvalue->value.value.data,
-                                                 wvalue->value.value.arrayLength, range);
-            else {
-                UA_Variant_deleteMembers(&newVn->value.variant.value);
-                retval = UA_Variant_copy(&wvalue->value.value, &newVn->value.variant.value);
-            }
+/* In the multithreaded case, node is a copy */
+static UA_StatusCode
+MoveValueIntoNode(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 || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
+    UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT);
 
 
-            if(retval == UA_STATUSCODE_GOOD && UA_NodeStore_replace(server->nodestore, node,
-                                                   (UA_Node*)newVn, UA_NULL) == UA_STATUSCODE_GOOD) {
-                //trigger onWrite
-                if(vn->value.variant.callback.onWrite){
-                    if(hasRange)
-                        vn->value.variant.callback.onWrite(vn->value.variant.callback.handle,
-                                                           wvalue->nodeId, &wvalue->value.value, &range);
-                    else
-                        vn->value.variant.callback.onWrite(vn->value.variant.callback.handle,
-                                                           wvalue->nodeId, &wvalue->value.value, UA_NULL);
-                }
-
-                done = UA_TRUE;
-                goto clean_up_range;
-            }
+    /* Parse the range */
+    UA_NumericRange range;
+    UA_NumericRange *rangeptr = UA_NULL;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(wvalue->indexRange.length > 0) {
+        retval = parse_numericrange(wvalue->indexRange, &range);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        rangeptr = &range;
+    }
 
 
-            clean_up:
-            if(node->nodeClass == UA_NODECLASS_VARIABLE)
-                UA_VariableNode_delete(newVn);
-            else
-                UA_VariableTypeNode_delete((UA_VariableTypeNode*)newVn);
-            clean_up_range:
-            if(hasRange)
+    /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings.
+       nodeV contains the correct type definition. */
+    UA_Variant *newV = &wvalue->value.value;
+    UA_Variant *oldV = &node->value.variant.value;
+    UA_Variant cast_v;
+    if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
+        cast_v = wvalue->value.value;
+        newV = &cast_v;
+        if(oldV->type->namespaceZero && newV->type->namespaceZero &&
+           oldV->type->typeIndex == newV->type->typeIndex) {
+            /* An enum was sent as an int32, or an opaque type as a bytestring. This is
+               detected with the typeIndex indicated the "true" datatype. */
+            newV->type = oldV->type;
+        } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
+                  newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) {
+            /* a string is written to a byte array */
+            UA_ByteString *str = (UA_ByteString*) newV->data;
+            newV->arrayLength = str->length;
+            newV->data = str->data;
+            newV->type = &UA_TYPES[UA_TYPES_BYTE];
+        } else {
+            if(rangeptr)
                 UA_free(range.dimensions);
                 UA_free(range.dimensions);
-            }
-            break;
-        case UA_ATTRIBUTEID_NODEID:
-        case UA_ATTRIBUTEID_NODECLASS:
-        case UA_ATTRIBUTEID_DATATYPE:
-        default:
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
+            return UA_STATUSCODE_BADTYPEMISMATCH;
         }
         }
-
-        UA_NodeStore_release(node);
-        if(retval != UA_STATUSCODE_GOOD)
-            break;
     }
     }
+    
+    if(!rangeptr) {
+        // TODO: Avoid copying the whole node and then delete the old value for multithreading
+        UA_Variant_deleteMembers(&node->value.variant.value);
+        node->value.variant.value = *newV;
+        UA_Variant_init(&wvalue->value.value);
+    } else {
+        retval = UA_Variant_setRangeCopy(&node->value.variant.value, newV->data, newV->arrayLength, range);
+    }
+    if(node->value.variant.callback.onWrite)
+        node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,
+                                             &node->value.variant.value, rangeptr);
 
 
+    if(rangeptr)
+        UA_free(range.dimensions);
     return retval;
     return retval;
 }
 }
 
 
+static UA_StatusCode
+MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_WriteValue *wvalue) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    void *value = wvalue->value.value.data;
+	switch(wvalue->attributeId) {
+    case UA_ATTRIBUTEID_NODEID:
+    case UA_ATTRIBUTEID_NODECLASS:
+    case UA_ATTRIBUTEID_DATATYPE:
+		retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+		break;
+	case UA_ATTRIBUTEID_BROWSENAME:
+		CHECK_DATATYPE(QUALIFIEDNAME);
+		UA_QualifiedName_deleteMembers(&node->browseName);
+        node->browseName = *(UA_QualifiedName*)value;
+        UA_QualifiedName_init((UA_QualifiedName*)value);
+		break;
+	case UA_ATTRIBUTEID_DISPLAYNAME:
+		CHECK_DATATYPE(LOCALIZEDTEXT);
+		UA_LocalizedText_deleteMembers(&node->displayName);
+        node->displayName = *(UA_LocalizedText*)value;
+		UA_LocalizedText_init((UA_LocalizedText*)value);
+		break;
+	case UA_ATTRIBUTEID_DESCRIPTION:
+		CHECK_DATATYPE(LOCALIZEDTEXT);
+		UA_LocalizedText_deleteMembers(&node->description);
+        node->description = *(UA_LocalizedText*)value;
+		UA_LocalizedText_init((UA_LocalizedText*)value);
+		break;
+	case UA_ATTRIBUTEID_WRITEMASK:
+		CHECK_DATATYPE(UINT32);
+		node->writeMask = *(UA_UInt32*)value;
+		break;
+	case UA_ATTRIBUTEID_USERWRITEMASK:
+		CHECK_DATATYPE(UINT32);
+		node->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*)node)->isAbstract = *(UA_Boolean*)value;
+		break;
+	case UA_ATTRIBUTEID_SYMMETRIC:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
+		CHECK_DATATYPE(BOOLEAN);
+		((UA_ReferenceTypeNode*)node)->symmetric = *(UA_Boolean*)value;
+		break;
+	case UA_ATTRIBUTEID_INVERSENAME:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
+		CHECK_DATATYPE(LOCALIZEDTEXT);
+        UA_ReferenceTypeNode *n = (UA_ReferenceTypeNode*)node;
+		UA_LocalizedText_deleteMembers(&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*)node)->containsNoLoops = *(UA_Boolean*)value;
+		break;
+	case UA_ATTRIBUTEID_EVENTNOTIFIER:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
+		CHECK_DATATYPE(BYTE);
+        ((UA_ViewNode*)node)->eventNotifier = *(UA_Byte*)value;
+		break;
+	case UA_ATTRIBUTEID_VALUE:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+        retval = MoveValueIntoNode(server, session, (UA_VariableNode*)node, wvalue);
+		break;
+	case UA_ATTRIBUTEID_ACCESSLEVEL:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
+		CHECK_DATATYPE(BYTE);
+		((UA_VariableNode*)node)->accessLevel = *(UA_Byte*)value;
+		break;
+	case UA_ATTRIBUTEID_USERACCESSLEVEL:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
+		CHECK_DATATYPE(BYTE);
+		((UA_VariableNode*)node)->userAccessLevel = *(UA_Byte*)value;
+		break;
+	case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
+		CHECK_DATATYPE(DOUBLE);
+		((UA_VariableNode*)node)->minimumSamplingInterval = *(UA_Double*)value;
+		break;
+	case UA_ATTRIBUTEID_HISTORIZING:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
+		CHECK_DATATYPE(BOOLEAN);
+		((UA_VariableNode*)node)->historizing = *(UA_Boolean*)value;
+		break;
+	case UA_ATTRIBUTEID_EXECUTABLE:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
+		CHECK_DATATYPE(BOOLEAN);
+		((UA_MethodNode*)node)->executable = *(UA_Boolean*)value;
+		break;
+	case UA_ATTRIBUTEID_USEREXECUTABLE:
+		CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
+		CHECK_DATATYPE(BOOLEAN);
+		((UA_MethodNode*)node)->userExecutable = *(UA_Boolean*)value;
+		break;
+	default:
+		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
+		break;
+	}
+    return retval;
+}
+
+UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_WriteValue *wvalue) {
+    if(!wvalue->value.hasValue || !wvalue->value.value.data)
+        return UA_STATUSCODE_BADNODATA; // TODO: is this the right return code?
+    if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE) {
+        const UA_Node *orig = UA_NodeStore_get(server->nodestore, &wvalue->nodeId);
+        if(!orig)
+            return UA_STATUSCODE_BADNODEIDUNKNOWN;
+        if(orig->nodeClass & (UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLE) &&
+           ((const UA_VariableNode*)orig)->valueSource == UA_VALUESOURCE_DATASOURCE) {
+            UA_StatusCode retval = Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)orig, wvalue);
+            UA_NodeStore_release(orig);
+            return retval;
+        }
+        UA_NodeStore_release(orig);
+    }
+    return UA_Server_editNode(server, session, &wvalue->nodeId,
+                              (UA_EditNodeCallback)MoveAttributeIntoNode, wvalue);
+}
+
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
                    UA_WriteResponse *response) {
                    UA_WriteResponse *response) {
     UA_assert(server != UA_NULL && session != UA_NULL && request != UA_NULL && response != UA_NULL);
     UA_assert(server != UA_NULL && session != UA_NULL && request != UA_NULL && response != UA_NULL);
 
 
-    if(request->nodesToWriteSize <= 0){
+    if(request->nodesToWriteSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
         return;
     }
     }
@@ -666,13 +674,8 @@ void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest
     }
     }
 
 
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
-#ifdef NO_ALLOCA
     UA_Boolean isExternal[request->nodesToWriteSize];
     UA_Boolean isExternal[request->nodesToWriteSize];
     UA_UInt32 indices[request->nodesToWriteSize];
     UA_UInt32 indices[request->nodesToWriteSize];
-#else
-    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToWriteSize);
-    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToWriteSize);
-#endif /*NO_ALLOCA */
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
     for(size_t j = 0; j < server->externalNamespacesSize; j++) {
     for(size_t j = 0; j < server->externalNamespacesSize; j++) {
         UA_UInt32 indexSize = 0;
         UA_UInt32 indexSize = 0;
@@ -697,6 +700,6 @@ void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
 #endif
 #endif
-            response->results[i] = writeValue(server, &request->nodesToWrite[i]);
+		  response->results[i] = Service_Write_single(server, session, &request->nodesToWrite[i]);
     }
     }
 }
 }

+ 14 - 11
src/server/ua_services_call.c

@@ -5,8 +5,9 @@
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 #include "ua_nodes.h"
 #include "ua_nodes.h"
 
 
-static const UA_VariableNode *getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
-                                                       UA_String withBrowseName) {
+static const UA_VariableNode
+*getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
+                          UA_String withBrowseName) {
     const UA_Node *refTarget;
     const UA_Node *refTarget;
     UA_NodeId hasProperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
     UA_NodeId hasProperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
     
     
@@ -27,7 +28,8 @@ static const UA_VariableNode *getArgumentsVariableNode(UA_Server *server, const
     return UA_NULL;
     return UA_NULL;
 }
 }
 
 
-static UA_StatusCode statisfySignature(UA_Variant *var, UA_Argument arg) {
+static UA_StatusCode
+statisfySignature(UA_Variant *var, UA_Argument arg) {
     if(!UA_NodeId_equal(&var->type->typeId, &arg.dataType) )
     if(!UA_NodeId_equal(&var->type->typeId, &arg.dataType) )
         return UA_STATUSCODE_BADINVALIDARGUMENT;
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     
     
@@ -72,7 +74,8 @@ static UA_StatusCode statisfySignature(UA_Variant *var, UA_Argument arg) {
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static UA_StatusCode argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefinition) {
+static UA_StatusCode
+argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefinition) {
     if(argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_ARGUMENT] &&
     if(argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_ARGUMENT] &&
         argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
         argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -104,17 +107,16 @@ static UA_StatusCode argConformsToDefinition(UA_CallMethodRequest *rs, const UA_
     return retval;
     return retval;
 }
 }
 
 
-static void callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request,
-                       UA_CallMethodResult *result) {
-    const UA_MethodNode *methodCalled = (const UA_MethodNode*) UA_NodeStore_get(server->nodestore,
-                                                                                &request->methodId);
+static void
+callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request,
+           UA_CallMethodResult *result) {
+    const UA_MethodNode *methodCalled = (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
     if(!methodCalled) {
     if(!methodCalled) {
         result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
         result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
         return;
         return;
     }
     }
     
     
-    const UA_ObjectNode *withObject = (const UA_ObjectNode *) UA_NodeStore_get(server->nodestore,
-                                                                               &request->objectId);
+    const UA_ObjectNode *withObject = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, &request->objectId);
     if(!withObject) {
     if(!withObject) {
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         goto releaseMethodReturn;
         goto releaseMethodReturn;
@@ -203,7 +205,8 @@ void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *
         return;
         return;
     }
     }
 
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_CALLMETHODRESULT], request->methodsToCallSize);
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_CALLMETHODRESULT],
+                                     request->methodsToCallSize);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;

Diferenças do arquivo suprimidas por serem muito extensas
+ 771 - 224
src/server/ua_services_nodemanagement.c


+ 48 - 54
src/server/ua_services_view.c

@@ -4,12 +4,11 @@
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 #include "ua_util.h"
 #include "ua_util.h"
 
 
-static UA_StatusCode fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref,
-                                  UA_UInt32 mask, UA_ReferenceDescription *descr)
-{
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+static UA_StatusCode
+fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref,
+                         UA_UInt32 mask, UA_ReferenceDescription *descr) {
     UA_ReferenceDescription_init(descr);
     UA_ReferenceDescription_init(descr);
-    retval |= UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
+    UA_StatusCode retval = UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
     //TODO: ExpandedNodeId is mocked up
     //TODO: ExpandedNodeId is mocked up
     descr->nodeId.serverIndex = 0;
     descr->nodeId.serverIndex = 0;
     descr->nodeId.namespaceUri.length = -1;
     descr->nodeId.namespaceUri.length = -1;
@@ -43,10 +42,9 @@ static UA_StatusCode fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_Refe
 
 
 /* Tests if the node is relevant to the browse request and shall be returned. If
 /* Tests if the node is relevant to the browse request and shall be returned. If
    so, it is retrieved from the Nodestore. If not, null is returned. */
    so, it is retrieved from the Nodestore. If not, null is returned. */
-static const UA_Node *relevant_node(UA_Server *server, UA_NodeStore *ns, const UA_BrowseDescription *descr,
-                                    UA_Boolean return_all, UA_ReferenceNode *reference,
-                                    UA_NodeId *relevant, size_t relevant_count, UA_Boolean *isExternal)
-{
+static const UA_Node *
+isRelevantNode(UA_Server *server, const UA_BrowseDescription *descr, UA_Boolean return_all,
+               UA_ReferenceNode *reference, UA_NodeId *relevant, size_t relevant_count, UA_Boolean *isExternal) {
     if(reference->isInverse == UA_TRUE && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD)
     if(reference->isInverse == UA_TRUE && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD)
         return UA_NULL;
         return UA_NULL;
     else if(reference->isInverse == UA_FALSE && descr->browseDirection == UA_BROWSEDIRECTION_INVERSE)
     else if(reference->isInverse == UA_FALSE && descr->browseDirection == UA_BROWSEDIRECTION_INVERSE)
@@ -72,8 +70,8 @@ is_relevant: ;
 			break;
 			break;
 		}
 		}
 	}
 	}
-	if(*isExternal == UA_FALSE){
-		node = UA_NodeStore_get(ns, &reference->targetId.nodeId);
+	if(*isExternal == UA_FALSE) {
+		node = UA_NodeStore_get(server->nodestore, &reference->targetId.nodeId);
 	} else {
 	} else {
 		/*	prepare a read request in the external nodestore	*/
 		/*	prepare a read request in the external nodestore	*/
 		UA_ExternalNodeStore *ens = &server->externalNamespaces[nsIndex].externalNodeStore;
 		UA_ExternalNodeStore *ens = &server->externalNamespaces[nsIndex].externalNodeStore;
@@ -102,24 +100,18 @@ is_relevant: ;
 		/*	create and fill a dummy nodeStructure	*/
 		/*	create and fill a dummy nodeStructure	*/
 		UA_Node *tempNode = (UA_Node*) UA_ObjectNode_new();
 		UA_Node *tempNode = (UA_Node*) UA_ObjectNode_new();
 		UA_NodeId_copy(&(reference->targetId.nodeId), &(tempNode->nodeId));
 		UA_NodeId_copy(&(reference->targetId.nodeId), &(tempNode->nodeId));
-		if(readNodesResults[0].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[0].status == UA_STATUSCODE_GOOD)
 			UA_NodeClass_copy((UA_NodeClass*)readNodesResults[0].value.data, &(tempNode->nodeClass));
 			UA_NodeClass_copy((UA_NodeClass*)readNodesResults[0].value.data, &(tempNode->nodeClass));
-		}
-		if(readNodesResults[1].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[1].status == UA_STATUSCODE_GOOD)
 			UA_QualifiedName_copy((UA_QualifiedName*)readNodesResults[1].value.data, &(tempNode->browseName));
 			UA_QualifiedName_copy((UA_QualifiedName*)readNodesResults[1].value.data, &(tempNode->browseName));
-		}
-		if(readNodesResults[2].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[2].status == UA_STATUSCODE_GOOD)
 			UA_LocalizedText_copy((UA_LocalizedText*)readNodesResults[2].value.data, &(tempNode->displayName));
 			UA_LocalizedText_copy((UA_LocalizedText*)readNodesResults[2].value.data, &(tempNode->displayName));
-		}
-		if(readNodesResults[3].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[3].status == UA_STATUSCODE_GOOD)
 			UA_LocalizedText_copy((UA_LocalizedText*)readNodesResults[3].value.data, &(tempNode->description));
 			UA_LocalizedText_copy((UA_LocalizedText*)readNodesResults[3].value.data, &(tempNode->description));
-		}
-		if(readNodesResults[4].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[4].status == UA_STATUSCODE_GOOD)
 			UA_UInt32_copy((UA_UInt32*)readNodesResults[4].value.data, &(tempNode->writeMask));
 			UA_UInt32_copy((UA_UInt32*)readNodesResults[4].value.data, &(tempNode->writeMask));
-		}
-		if(readNodesResults[5].status == UA_STATUSCODE_GOOD){
+		if(readNodesResults[5].status == UA_STATUSCODE_GOOD)
 			UA_UInt32_copy((UA_UInt32*)readNodesResults[5].value.data, &(tempNode->userWriteMask));
 			UA_UInt32_copy((UA_UInt32*)readNodesResults[5].value.data, &(tempNode->userWriteMask));
-		}
 		UA_Array_delete(readValueIds, &UA_TYPES[UA_TYPES_READVALUEID], 6);
 		UA_Array_delete(readValueIds, &UA_TYPES[UA_TYPES_READVALUEID], 6);
 		UA_Array_delete(indices, &UA_TYPES[UA_TYPES_UINT32], 6);
 		UA_Array_delete(indices, &UA_TYPES[UA_TYPES_UINT32], 6);
 		UA_Array_delete(readNodesResults, &UA_TYPES[UA_TYPES_DATAVALUE], 6);
 		UA_Array_delete(readNodesResults, &UA_TYPES[UA_TYPES_DATAVALUE], 6);
@@ -127,7 +119,7 @@ is_relevant: ;
 		node = tempNode;
 		node = tempNode;
 	}
 	}
 #else
 #else
-    const UA_Node *node = UA_NodeStore_get(ns, &reference->targetId.nodeId);
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &reference->targetId.nodeId);
 #endif
 #endif
     if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
     if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
@@ -147,8 +139,8 @@ is_relevant: ;
  * the array and increase the size. Since the hierarchy is not cyclic, we can safely progress in the
  * the array and increase the size. Since the hierarchy is not cyclic, we can safely progress in the
  * array to process the newly found referencetype nodeids (emulated recursion).
  * array to process the newly found referencetype nodeids (emulated recursion).
  */
  */
-static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes,
-                                  size_t *reftypes_count) {
+static UA_StatusCode
+findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size_t *reftypes_count) {
     const UA_Node *node = UA_NodeStore_get(ns, root);
     const UA_Node *node = UA_NodeStore_get(ns, root);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNOMATCH;
         return UA_STATUSCODE_BADNOMATCH;
@@ -209,7 +201,7 @@ static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_No
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session){
+static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session) {
     session->availableContinuationPoints++;
     session->availableContinuationPoints++;
     UA_ByteString_deleteMembers(&cp->identifier);
     UA_ByteString_deleteMembers(&cp->identifier);
     UA_BrowseDescription_deleteMembers(&cp->browseDescription);
     UA_BrowseDescription_deleteMembers(&cp->browseDescription);
@@ -221,14 +213,15 @@ static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session){
  * Results for a single browsedescription. This is the inner loop for both Browse and BrowseNext
  * Results for a single browsedescription. This is the inner loop for both Browse and BrowseNext
  * @param session Session to save continuationpoints
  * @param session Session to save continuationpoints
  * @param ns The nodstore where the to-be-browsed node can be found
  * @param ns The nodstore where the to-be-browsed node can be found
- * @param cp If cp points to a continuationpoint, we continue from there.
+ * @param cp If cp is not null, we continue from here
  *           If cp is null, we can add a new continuation point if possible and necessary.
  *           If cp is null, we can add a new continuation point if possible and necessary.
  * @param descr If no cp is set, we take the browsedescription from there
  * @param descr If no cp is set, we take the browsedescription from there
  * @param maxrefs The maximum number of references the client has requested
  * @param maxrefs The maximum number of references the client has requested
  * @param result The entry in the request
  * @param result The entry in the request
  */
  */
-static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, struct ContinuationPointEntry *cp,
-                   const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) {
+void
+Service_Browse_single(UA_Server *server, UA_Session *session, struct ContinuationPointEntry *cp,
+                      const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) {
     UA_UInt32 continuationIndex = 0;
     UA_UInt32 continuationIndex = 0;
     size_t referencesCount = 0;
     size_t referencesCount = 0;
     UA_Int32 referencesIndex = 0;
     UA_Int32 referencesIndex = 0;
@@ -254,15 +247,17 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
     UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
     UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
     if(!all_refs) {
     if(!all_refs) {
         if(descr->includeSubtypes) {
         if(descr->includeSubtypes) {
-            result->statusCode = findsubtypes(ns, &descr->referenceTypeId, &relevant_refs, &relevant_refs_size);
+            result->statusCode = findSubTypes(server->nodestore, &descr->referenceTypeId,
+                                              &relevant_refs, &relevant_refs_size);
             if(result->statusCode != UA_STATUSCODE_GOOD)
             if(result->statusCode != UA_STATUSCODE_GOOD)
                 return;
                 return;
         } else {
         } else {
-            const UA_Node *rootRef = UA_NodeStore_get(ns, &descr->referenceTypeId);
+            const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &descr->referenceTypeId);
             if(!rootRef) {
             if(!rootRef) {
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 return;
                 return;
-            } else if(rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
+            }
+            if(rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
                 UA_NodeStore_release(rootRef);
                 UA_NodeStore_release(rootRef);
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 return;
                 return;
@@ -274,7 +269,7 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
     }
     }
 
 
     /* get the node */
     /* get the node */
-    const UA_Node *node = UA_NodeStore_get(ns, &descr->nodeId);
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &descr->nodeId);
     if(!node) {
     if(!node) {
         result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         if(!all_refs && descr->includeSubtypes)
         if(!all_refs && descr->includeSubtypes)
@@ -306,34 +301,32 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
     UA_Boolean isExternal = UA_FALSE;
     UA_Boolean isExternal = UA_FALSE;
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
     	isExternal = UA_FALSE;
     	isExternal = UA_FALSE;
-    	const UA_Node *current = relevant_node(server, ns, descr, all_refs, &node->references[referencesIndex],
-                                               relevant_refs, relevant_refs_size, &isExternal);
+    	const UA_Node *current = isRelevantNode(server, descr, all_refs, &node->references[referencesIndex],
+                                                relevant_refs, relevant_refs_size, &isExternal);
         if(!current)
         if(!current)
             continue;
             continue;
         if(skipped < continuationIndex) {
         if(skipped < continuationIndex) {
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
-        	if(isExternal == UA_TRUE){
+        	if(isExternal == UA_TRUE)
         		/*	relevant_node returns a node malloced with UA_ObjectNode_new if it is external (there is no UA_Node_new function)	*/
         		/*	relevant_node returns a node malloced with UA_ObjectNode_new if it is external (there is no UA_Node_new function)	*/
         		UA_ObjectNode_delete((UA_ObjectNode*)current);
         		UA_ObjectNode_delete((UA_ObjectNode*)current);
-        	} else {
+        	else
         		UA_NodeStore_release(current);
         		UA_NodeStore_release(current);
-        	}
 #else
 #else
         	UA_NodeStore_release(current);
         	UA_NodeStore_release(current);
 #endif
 #endif
             skipped++;
             skipped++;
             continue;
             continue;
         }
         }
-        UA_StatusCode retval = fillrefdescr(ns, current, &node->references[referencesIndex], descr->resultMask,
-                                            &result->references[referencesCount]);
+        UA_StatusCode retval = fillReferenceDescription(server->nodestore, current, &node->references[referencesIndex],
+                                                        descr->resultMask, &result->references[referencesCount]);
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
-        if(isExternal == UA_TRUE){
+        if(isExternal == UA_TRUE)
         	UA_ObjectNode_delete((UA_ObjectNode*)current);
         	UA_ObjectNode_delete((UA_ObjectNode*)current);
-        } else {
+        else
         	UA_NodeStore_release(current);
         	UA_NodeStore_release(current);
-        }
 #else
 #else
-        	UA_NodeStore_release(current);
+        UA_NodeStore_release(current);
 #endif
 #endif
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
             UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], referencesCount);
             UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], referencesCount);
@@ -370,7 +363,8 @@ static void browse(UA_Server *server, UA_Session *session, UA_NodeStore *ns, str
         }
         }
     } else if(maxrefs != 0 && referencesCount >= maxrefs) {
     } else if(maxrefs != 0 && referencesCount >= maxrefs) {
         /* create a cp */
         /* create a cp */
-        if(session->availableContinuationPoints <= 0 || !(cp = UA_malloc(sizeof(struct ContinuationPointEntry)))) {
+        if(session->availableContinuationPoints <= 0 ||
+           !(cp = UA_malloc(sizeof(struct ContinuationPointEntry)))) {
             result->statusCode = UA_STATUSCODE_BADNOCONTINUATIONPOINTS;
             result->statusCode = UA_STATUSCODE_BADNOCONTINUATIONPOINTS;
             return;
             return;
         }
         }
@@ -440,8 +434,8 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
 #endif
 #endif
-            browse(server, session, server->nodestore, UA_NULL, &request->nodesToBrowse[i],
-                   request->requestedMaxReferencesPerNode, &response->results[i]);
+            Service_Browse_single(server, session, UA_NULL, &request->nodesToBrowse[i],
+                                  request->requestedMaxReferencesPerNode, &response->results[i]);
     }
     }
 }
 }
 
 
@@ -464,7 +458,7 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
            struct ContinuationPointEntry *cp;
            struct ContinuationPointEntry *cp;
            LIST_FOREACH(cp, &session->continuationPoints, pointers) {
            LIST_FOREACH(cp, &session->continuationPoints, pointers) {
                if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
                if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
-                   browse(server, session, server->nodestore, cp, UA_NULL, 0, &response->results[i]);
+                   Service_Browse_single(server, session, cp, UA_NULL, 0, &response->results[i]);
                    break;
                    break;
                }
                }
            }
            }
@@ -500,8 +494,7 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
 static UA_StatusCode
 static UA_StatusCode
 walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_RelativePath *path,
 walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_RelativePath *path,
                UA_Int32 pathindex, UA_BrowsePathTarget **targets, UA_Int32 *targets_size,
                UA_Int32 pathindex, UA_BrowsePathTarget **targets, UA_Int32 *targets_size,
-               UA_Int32 *target_count)
-{
+               UA_Int32 *target_count) {
     const UA_RelativePathElement *elem = &path->elements[pathindex];
     const UA_RelativePathElement *elem = &path->elements[pathindex];
     if(elem->targetName.name.length == -1)
     if(elem->targetName.name.length == -1)
         return UA_STATUSCODE_BADBROWSENAMEINVALID;
         return UA_STATUSCODE_BADBROWSENAMEINVALID;
@@ -515,7 +508,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
     else if(!elem->includeSubtypes)
     else if(!elem->includeSubtypes)
         reftypes = (UA_NodeId*)(uintptr_t)&elem->referenceTypeId; // ptr magic due to const cast
         reftypes = (UA_NodeId*)(uintptr_t)&elem->referenceTypeId; // ptr magic due to const cast
     else {
     else {
-        retval = findsubtypes(server->nodestore, &elem->referenceTypeId, &reftypes, &reftypes_count);
+        retval = findSubTypes(server->nodestore, &elem->referenceTypeId, &reftypes, &reftypes_count);
         if(retval != UA_STATUSCODE_GOOD)
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
             return retval;
     }
     }
@@ -577,8 +570,9 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
     return retval;
     return retval;
 }
 }
 
 
-static void translateBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path,
-                                UA_BrowsePathResult *result) {
+static void
+translateBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path,
+                    UA_BrowsePathResult *result) {
     if(path->relativePath.elementsSize <= 0) {
     if(path->relativePath.elementsSize <= 0) {
         result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
         result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
         return;
         return;

+ 136 - 320
src/ua_types.c

@@ -9,43 +9,38 @@
 #include <strsafe.h>
 #include <strsafe.h>
 #endif
 #endif
 
 
-/*****************/
 /* Helper Macros */
 /* Helper Macros */
-/*****************/
-
-#define UA_TYPE_DEFAULT(TYPE)            \
-    UA_TYPE_NEW_DEFAULT(TYPE)            \
-    UA_TYPE_DELETE_DEFAULT(TYPE)
-
-#define UA_TYPE_NEW_DEFAULT(TYPE)                              \
+#define UA_TYPE_DEFAULT(TYPE)                                  \
     TYPE * TYPE##_new() {                                      \
     TYPE * TYPE##_new() {                                      \
         TYPE *p = UA_malloc(sizeof(TYPE));                     \
         TYPE *p = UA_malloc(sizeof(TYPE));                     \
         if(p) TYPE##_init(p);                                  \
         if(p) TYPE##_init(p);                                  \
         return p;                                              \
         return p;                                              \
+    }                                                          \
+    void TYPE##_delete(TYPE *p) {                              \
+        TYPE##_deleteMembers(p);                               \
+        UA_free(p);                                            \
     }
     }
 
 
-#define UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
-    void TYPE##_deleteMembers(TYPE *p) {    \
-    }
-
-#define UA_TYPE_DELETE_DEFAULT(TYPE) \
-    void TYPE##_delete(TYPE *p) {    \
-        TYPE##_deleteMembers(p);     \
-        UA_free(p);                  \
-    }
+/* static variables */
+UA_EXPORT const UA_String UA_STRING_NULL = {.length = -1, .data = (UA_Byte*)0 };
+UA_EXPORT const UA_ByteString UA_BYTESTRING_NULL = {.length = -1, .data = (UA_Byte*)0 };
+UA_EXPORT const UA_NodeId UA_NODEID_NULL = {0, UA_NODEIDTYPE_NUMERIC, {0}};
+UA_EXPORT const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {
+    .nodeId = { .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0 },
+    .namespaceUri = {.length = -1, .data = (UA_Byte*)0}, .serverIndex = 0 };
 
 
 /***************************/
 /***************************/
 /* Random Number Generator */
 /* Random Number Generator */
 /***************************/
 /***************************/
 
 
-static UA_THREAD_LOCAL pcg32_random_t rng = PCG32_INITIALIZER;
+static UA_THREAD_LOCAL pcg32_random_t UA_rng = PCG32_INITIALIZER;
 
 
 UA_EXPORT void UA_random_seed(UA_UInt64 seed) {
 UA_EXPORT void UA_random_seed(UA_UInt64 seed) {
-    pcg32_srandom_r(&rng, seed, UA_DateTime_now());
+    pcg32_srandom_r(&UA_rng, seed, UA_DateTime_now());
 }
 }
 
 
 UA_EXPORT UA_UInt32 UA_random(void) {
 UA_EXPORT UA_UInt32 UA_random(void) {
-    return (UA_UInt32)pcg32_random_r(&rng);
+    return (UA_UInt32)pcg32_random_r(&UA_rng);
 }
 }
 
 
 /*****************/
 /*****************/
@@ -86,8 +81,7 @@ UA_TYPE_DEFAULT(UA_Float)
 UA_TYPE_DEFAULT(UA_Double)
 UA_TYPE_DEFAULT(UA_Double)
 
 
 /* String */
 /* String */
-UA_TYPE_NEW_DEFAULT(UA_String)
-UA_TYPE_DELETE_DEFAULT(UA_String)
+UA_TYPE_DEFAULT(UA_String)
 
 
 void UA_String_init(UA_String *p) {
 void UA_String_init(UA_String *p) {
     p->length = -1;
     p->length = -1;
@@ -255,16 +249,16 @@ UA_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) {
 
 
 UA_Guid UA_Guid_random(UA_UInt32 *seed) {
 UA_Guid UA_Guid_random(UA_UInt32 *seed) {
     UA_Guid result;
     UA_Guid result;
-    result.data1 = (UA_UInt32)pcg32_random_r(&rng);
-    UA_UInt32 r = (UA_UInt32)pcg32_random_r(&rng);
+    result.data1 = (UA_UInt32)pcg32_random_r(&UA_rng);
+    UA_UInt32 r = (UA_UInt32)pcg32_random_r(&UA_rng);
     result.data2 = (UA_UInt16) r;
     result.data2 = (UA_UInt16) r;
     result.data3 = (UA_UInt16) (r >> 16);
     result.data3 = (UA_UInt16) (r >> 16);
-    r = (UA_UInt32)pcg32_random_r(&rng);
+    r = (UA_UInt32)pcg32_random_r(&UA_rng);
     result.data4[0] = (UA_Byte)r;
     result.data4[0] = (UA_Byte)r;
     result.data4[1] = (UA_Byte)(r >> 4);
     result.data4[1] = (UA_Byte)(r >> 4);
     result.data4[2] = (UA_Byte)(r >> 8);
     result.data4[2] = (UA_Byte)(r >> 8);
     result.data4[3] = (UA_Byte)(r >> 12);
     result.data4[3] = (UA_Byte)(r >> 12);
-    r = (UA_UInt32)pcg32_random_r(&rng);
+    r = (UA_UInt32)pcg32_random_r(&UA_rng);
     result.data4[4] = (UA_Byte)r;
     result.data4[4] = (UA_Byte)r;
     result.data4[5] = (UA_Byte)(r >> 4);
     result.data4[5] = (UA_Byte)(r >> 4);
     result.data4[6] = (UA_Byte)(r >> 8);
     result.data4[6] = (UA_Byte)(r >> 8);
@@ -291,8 +285,7 @@ UA_StatusCode UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length) {
 /* XmlElement */
 /* XmlElement */
 
 
 /* NodeId */
 /* NodeId */
-UA_TYPE_NEW_DEFAULT(UA_NodeId)
-UA_TYPE_DELETE_DEFAULT(UA_NodeId)
+UA_TYPE_DEFAULT(UA_NodeId)
 
 
 void UA_NodeId_init(UA_NodeId *p) {
 void UA_NodeId_init(UA_NodeId *p) {
     p->identifierType = UA_NODEIDTYPE_NUMERIC;
     p->identifierType = UA_NODEIDTYPE_NUMERIC;
@@ -391,65 +384,8 @@ UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
     return UA_TRUE;
     return UA_TRUE;
 }
 }
 
 
-UA_NodeId UA_NodeId_fromInteger(UA_UInt16 nsIndex, UA_Int32 identifier) {
-    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_NUMERIC,
-                         .identifier.numeric = identifier };
-}
-
-UA_NodeId UA_NodeId_fromCharString(UA_UInt16 nsIndex, char identifier[]) {
-    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_STRING,
-                         .identifier.string = UA_STRING(identifier) };
-}
-
-UA_NodeId UA_NodeId_fromCharStringCopy(UA_UInt16 nsIndex, char const identifier[]) {
-    return (UA_NodeId) {.namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_STRING,
-                        .identifier.string = UA_STRING_ALLOC(identifier) };
-}
-
-UA_NodeId UA_NodeId_fromString(UA_UInt16 nsIndex, UA_String identifier) {
-    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_STRING,
-                         .identifier.string = identifier };
-}
-
-UA_NodeId UA_NodeId_fromStringCopy(UA_UInt16 nsIndex, UA_String identifier) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_STRING;
-    UA_String_copy(&identifier, &id.identifier.string);
-    return id;
-}
-
-UA_NodeId UA_NodeId_fromGuid(UA_UInt16 nsIndex, UA_Guid identifier) {
-    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_GUID,
-                         .identifier.guid = identifier };
-}
-
-UA_NodeId UA_NodeId_fromCharByteString(UA_UInt16 nsIndex, char identifier[]) {
-    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_BYTESTRING,
-                         .identifier.byteString = UA_STRING(identifier) };
-}
-
-UA_NodeId UA_NodeId_fromCharByteStringCopy(UA_UInt16 nsIndex, char const identifier[]) {
-    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_BYTESTRING,
-                         .identifier.byteString = UA_STRING_ALLOC(identifier) };
-}
-
-UA_NodeId UA_NodeId_fromByteString(UA_UInt16 nsIndex, UA_ByteString identifier) {
-    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_BYTESTRING,
-                         .identifier.byteString = identifier };
-}
-
-UA_NodeId UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteString identifier) {
-    UA_NodeId id;
-    id.namespaceIndex = nsIndex;
-    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
-    UA_ByteString_copy(&identifier, &id.identifier.byteString);
-    return id;
-}
-
 /* ExpandedNodeId */
 /* ExpandedNodeId */
-UA_TYPE_NEW_DEFAULT(UA_ExpandedNodeId)
-UA_TYPE_DELETE_DEFAULT(UA_ExpandedNodeId)
+UA_TYPE_DEFAULT(UA_ExpandedNodeId)
 
 
 void UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p) {
 void UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p) {
     UA_NodeId_deleteMembers(&p->nodeId);
     UA_NodeId_deleteMembers(&p->nodeId);
@@ -473,15 +409,10 @@ UA_StatusCode UA_ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNo
     return retval;
     return retval;
 }
 }
 
 
-UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p) {
-    return UA_NodeId_isNull(&p->nodeId);
-}
-
 /* StatusCode */
 /* StatusCode */
 
 
 /* QualifiedName */
 /* QualifiedName */
-UA_TYPE_NEW_DEFAULT(UA_QualifiedName)
-UA_TYPE_DELETE_DEFAULT(UA_QualifiedName)
+UA_TYPE_DEFAULT(UA_QualifiedName)
 
 
 void UA_QualifiedName_deleteMembers(UA_QualifiedName *p) {
 void UA_QualifiedName_deleteMembers(UA_QualifiedName *p) {
     UA_String_deleteMembers(&p->name);
     UA_String_deleteMembers(&p->name);
@@ -503,8 +434,7 @@ UA_StatusCode UA_QualifiedName_copy(UA_QualifiedName const *src, UA_QualifiedNam
 }
 }
 
 
 /* LocalizedText */
 /* LocalizedText */
-UA_TYPE_NEW_DEFAULT(UA_LocalizedText)
-UA_TYPE_DELETE_DEFAULT(UA_LocalizedText)
+UA_TYPE_DEFAULT(UA_LocalizedText)
 
 
 void UA_LocalizedText_deleteMembers(UA_LocalizedText *p) {
 void UA_LocalizedText_deleteMembers(UA_LocalizedText *p) {
     UA_String_deleteMembers(&p->locale);
     UA_String_deleteMembers(&p->locale);
@@ -527,8 +457,7 @@ UA_StatusCode UA_LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedTex
 }
 }
 
 
 /* ExtensionObject */
 /* ExtensionObject */
-UA_TYPE_NEW_DEFAULT(UA_ExtensionObject)
-UA_TYPE_DELETE_DEFAULT(UA_ExtensionObject)
+UA_TYPE_DEFAULT(UA_ExtensionObject)
 
 
 void UA_ExtensionObject_deleteMembers(UA_ExtensionObject *p) {
 void UA_ExtensionObject_deleteMembers(UA_ExtensionObject *p) {
     UA_NodeId_deleteMembers(&p->typeId);
     UA_NodeId_deleteMembers(&p->typeId);
@@ -553,8 +482,7 @@ UA_StatusCode UA_ExtensionObject_copy(UA_ExtensionObject const *src, UA_Extensio
 }
 }
 
 
 /* DataValue */
 /* DataValue */
-UA_TYPE_NEW_DEFAULT(UA_DataValue)
-UA_TYPE_DELETE_DEFAULT(UA_DataValue)
+UA_TYPE_DEFAULT(UA_DataValue)
 
 
 void UA_DataValue_deleteMembers(UA_DataValue *p) {
 void UA_DataValue_deleteMembers(UA_DataValue *p) {
     UA_Variant_deleteMembers(&p->value);
     UA_Variant_deleteMembers(&p->value);
@@ -577,8 +505,7 @@ UA_StatusCode UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst) {
 }
 }
 
 
 /* Variant */
 /* Variant */
-UA_TYPE_NEW_DEFAULT(UA_Variant)
-UA_TYPE_DELETE_DEFAULT(UA_Variant)
+UA_TYPE_DEFAULT(UA_Variant)
 
 
 void UA_Variant_init(UA_Variant *p) {
 void UA_Variant_init(UA_Variant *p) {
     p->storageType = UA_VARIANT_DATA;
     p->storageType = UA_VARIANT_DATA;
@@ -846,8 +773,7 @@ UA_StatusCode UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32
 }
 }
 
 
 /* DiagnosticInfo */
 /* DiagnosticInfo */
-UA_TYPE_NEW_DEFAULT(UA_DiagnosticInfo)
-UA_TYPE_DELETE_DEFAULT(UA_DiagnosticInfo)
+UA_TYPE_DEFAULT(UA_DiagnosticInfo)
 
 
 void UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
 void UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
     UA_String_deleteMembers(&p->additionalInfo);
     UA_String_deleteMembers(&p->additionalInfo);
@@ -889,87 +815,68 @@ UA_StatusCode UA_DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_Diagnostic
 /*******************/
 /*******************/
 
 
 void UA_init(void *p, const UA_DataType *dataType) {
 void UA_init(void *p, const UA_DataType *dataType) {
-    /* Do not check if the index is a builtin-type here. Builtins will be called
-       with their very own _init functions normally. In the off case, that the
-       generic function is called with the index of a builtin, their layout
-       contains a single member of the builtin type, that will be inited in the
-       for loop. */
+    switch(dataType->typeIndex) {
+    case UA_TYPES_BOOLEAN:
+    case UA_TYPES_SBYTE:
+    case UA_TYPES_BYTE:
+        *(UA_Byte*)p = 0;
+        return;
+    case UA_TYPES_INT16:
+    case UA_TYPES_UINT16:
+        *(UA_Int16*)p = 0;
+        return;
+    case UA_TYPES_INT32:
+    case UA_TYPES_UINT32:
+    case UA_TYPES_STATUSCODE:
+    case UA_TYPES_FLOAT:
+        *(UA_Int32*)p = 0;
+        return;
+    case UA_TYPES_INT64:
+    case UA_TYPES_UINT64:
+    case UA_TYPES_DOUBLE:
+    case UA_TYPES_DATETIME:
+        *(UA_Int64*)p = 0;
+        return;
+    case UA_TYPES_GUID:
+        UA_Guid_init((UA_Guid*)p);
+        return;
+    case UA_TYPES_NODEID:
+        UA_NodeId_init((UA_NodeId*)p);
+        return;
+    case UA_TYPES_EXTENSIONOBJECT:
+        UA_ExtensionObject_init((UA_ExtensionObject*)p);
+        return;
+    case UA_TYPES_DATAVALUE:
+        UA_DataValue_init((UA_DataValue*)p);
+        return;
+    case UA_TYPES_VARIANT:
+        UA_Variant_init((UA_Variant*)p);
+        return;
+    case UA_TYPES_DIAGNOSTICINFO:
+        UA_DiagnosticInfo_init((UA_DiagnosticInfo*)p);
+        return;
+    }
 
 
     uintptr_t ptr = (uintptr_t)p;
     uintptr_t ptr = (uintptr_t)p;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
-    for(size_t i=0;i<membersSize; i++) {
+    for(size_t i = 0; i < membersSize; i++) {
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataTypeMember *member = &dataType->members[i];
-        if(member->isArray) {
-            /* Padding contains bit-magic to split into padding before and after
-               the length integer */
+        if(!member->isArray) {
+            const UA_DataType *memberType;
+            if(member->namespaceZero)
+                memberType = &UA_TYPES[member->memberTypeIndex];
+            else
+                memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
+            ptr += member->padding;
+            UA_init((void*)ptr, memberType);
+            ptr += memberType->memSize;
+        } else {
             ptr += (member->padding >> 3);
             ptr += (member->padding >> 3);
             *((UA_Int32*)ptr) = -1;
             *((UA_Int32*)ptr) = -1;
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             *((void**)ptr) = UA_NULL;
             *((void**)ptr) = UA_NULL;
             ptr += sizeof(void*);
             ptr += sizeof(void*);
-            continue;
-        }
-
-        ptr += member->padding;
-        if(!member->namespaceZero) {
-            // pointer arithmetic
-            const UA_DataType *memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
-            UA_init((void*)ptr, memberType);
-            ptr += memberType->memSize;
-            continue;
-        }
-
-        switch(member->memberTypeIndex) {
-        case UA_TYPES_BOOLEAN:
-        case UA_TYPES_SBYTE:
-        case UA_TYPES_BYTE:
-            *(UA_Byte*)ptr = 0;
-            break;
-        case UA_TYPES_INT16:
-        case UA_TYPES_UINT16:
-            *(UA_Int16*)ptr = 0;
-            break;
-        case UA_TYPES_INT32:
-        case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-        case UA_TYPES_FLOAT:
-            *(UA_Int32*)ptr = 0;
-            break;
-        case UA_TYPES_INT64:
-        case UA_TYPES_UINT64:
-        case UA_TYPES_DOUBLE:
-        case UA_TYPES_DATETIME:
-            *(UA_Int64*)ptr = 0;
-            break;
-        case UA_TYPES_GUID:
-            UA_Guid_init((UA_Guid*)ptr);
-            break;
-        case UA_TYPES_NODEID:
-            UA_NodeId_init((UA_NodeId*)ptr);
-            break;
-        case UA_TYPES_EXPANDEDNODEID:
-            UA_ExpandedNodeId_init((UA_ExpandedNodeId*)ptr);
-            break;
-        case UA_TYPES_LOCALIZEDTEXT:
-            UA_LocalizedText_init((UA_LocalizedText*)ptr);
-            break;
-        case UA_TYPES_EXTENSIONOBJECT:
-            UA_ExtensionObject_init((UA_ExtensionObject*)ptr);
-            break;
-        case UA_TYPES_DATAVALUE:
-            UA_DataValue_init((UA_DataValue*)ptr);
-            break;
-        case UA_TYPES_VARIANT:
-            UA_Variant_init((UA_Variant*)ptr);
-            break;
-        case UA_TYPES_DIAGNOSTICINFO:
-            UA_DiagnosticInfo_init((UA_DiagnosticInfo*)ptr);
-            break;
-        default:
-            // QualifiedName, LocalizedText and strings are treated as structures, also
-            UA_init((void*)ptr, &UA_TYPES[member->memberTypeIndex]);
         }
         }
-        ptr += UA_TYPES[member->memberTypeIndex].memSize;
     }
     }
 }
 }
 
 
@@ -985,20 +892,39 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *dataType) {
         memcpy(dst, src, dataType->memSize);
         memcpy(dst, src, dataType->memSize);
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
     }
     }
+    switch(dataType->typeIndex) {
+    case UA_TYPES_NODEID:
+        return UA_NodeId_copy((const UA_NodeId*)src, (UA_NodeId*)dst);
+    case UA_TYPES_EXTENSIONOBJECT:
+        return UA_ExtensionObject_copy((const UA_ExtensionObject*)src, (UA_ExtensionObject*)dst);
+    case UA_TYPES_DATAVALUE:
+        return UA_DataValue_copy((const UA_DataValue*)src, (UA_DataValue*)dst);
+    case UA_TYPES_VARIANT:
+        return UA_Variant_copy((const UA_Variant*)src, (UA_Variant*)dst);
+    case UA_TYPES_DIAGNOSTICINFO:
+        return UA_DiagnosticInfo_copy((const UA_DiagnosticInfo*)src, (UA_DiagnosticInfo*)dst);
+    }
+
     UA_init(dst, dataType);
     UA_init(dst, dataType);
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     uintptr_t ptrs = (uintptr_t)src;
     uintptr_t ptrs = (uintptr_t)src;
     uintptr_t ptrd = (uintptr_t)dst;
     uintptr_t ptrd = (uintptr_t)dst;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
-    for(size_t i=0;i<membersSize; i++) {
+    size_t i;
+    for(i = 0; i < membersSize && retval == UA_STATUSCODE_GOOD; i++) {
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataType *memberType;
         const UA_DataType *memberType;
         if(member->namespaceZero)
         if(member->namespaceZero)
             memberType = &UA_TYPES[member->memberTypeIndex];
             memberType = &UA_TYPES[member->memberTypeIndex];
         else
         else
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
-
-        if(member->isArray) {
+        if(!member->isArray) {
+            ptrs += member->padding;
+            ptrd += member->padding;
+            retval = UA_copy((const void*)ptrs, (void*)ptrd, memberType);
+            ptrs += memberType->memSize;
+            ptrd += memberType->memSize;
+        } else {
             ptrs += (member->padding >> 3);
             ptrs += (member->padding >> 3);
             ptrd += (member->padding >> 3);
             ptrd += (member->padding >> 3);
             UA_Int32 *dstNoElements = (UA_Int32*)ptrd;
             UA_Int32 *dstNoElements = (UA_Int32*)ptrd;
@@ -1006,174 +932,66 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *dataType) {
             ptrs += sizeof(UA_Int32) + (member->padding & 0x07);
             ptrs += sizeof(UA_Int32) + (member->padding & 0x07);
             ptrd += sizeof(UA_Int32) + (member->padding & 0x07);
             ptrd += sizeof(UA_Int32) + (member->padding & 0x07);
             retval = UA_Array_copy(*(void* const*)ptrs, (void**)ptrd, memberType, elements);
             retval = UA_Array_copy(*(void* const*)ptrs, (void**)ptrd, memberType, elements);
-            if(retval != UA_STATUSCODE_GOOD) {
-                UA_deleteMembers(dst, dataType);
-                UA_init(dst, dataType);
-                return retval;
-            }
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
             *dstNoElements = elements;
             *dstNoElements = elements;
             ptrs += sizeof(void*);
             ptrs += sizeof(void*);
             ptrd += sizeof(void*);
             ptrd += sizeof(void*);
-            continue;
-        }
-
-        ptrs += member->padding;
-        ptrd += member->padding;
-        if(!member->namespaceZero) {
-            retval = UA_copy((const void*)ptrs, (void*)ptrd, memberType);
-            if(retval != UA_STATUSCODE_GOOD) {
-                UA_deleteMembers(dst, dataType);
-                UA_init(dst, dataType);
-                return retval;
-            }
-            ptrs += memberType->memSize;
-            ptrd += memberType->memSize;
-            continue;
-        }
-
-        switch(member->memberTypeIndex) {
-        case UA_TYPES_BOOLEAN:
-        case UA_TYPES_SBYTE:
-        case UA_TYPES_BYTE:
-            *((UA_Byte*)ptrd) = *((const UA_Byte*)ptrs);
-            break;
-        case UA_TYPES_INT16:
-        case UA_TYPES_UINT16:
-            *((UA_Int16*)ptrd) = *((const UA_Byte*)ptrs);
-            break;
-        case UA_TYPES_INT32:
-        case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-        case UA_TYPES_FLOAT:
-            *((UA_Int32*)ptrd) = *((const UA_Int32*)ptrs);
-            break;
-        case UA_TYPES_INT64:
-        case UA_TYPES_UINT64:
-        case UA_TYPES_DOUBLE:
-        case UA_TYPES_DATETIME:
-            *((UA_Int64*)ptrd) = *((const UA_Int64*)ptrs);
-            break;
-        case UA_TYPES_GUID:
-            *((UA_Guid*)ptrd) = *((const UA_Guid*)ptrs);
-            break;
-        case UA_TYPES_NODEID:
-            retval |= UA_NodeId_copy((const UA_NodeId*)ptrs, (UA_NodeId*)ptrd);
-            break;
-        case UA_TYPES_EXPANDEDNODEID:
-            retval |= UA_ExpandedNodeId_copy((const UA_ExpandedNodeId*)ptrs, (UA_ExpandedNodeId*)ptrd);
-            break;
-        case UA_TYPES_LOCALIZEDTEXT:
-            retval |= UA_LocalizedText_copy((const UA_LocalizedText*)ptrs, (UA_LocalizedText*)ptrd);
-            break;
-        case UA_TYPES_EXTENSIONOBJECT:
-            retval |= UA_ExtensionObject_copy((const UA_ExtensionObject*)ptrs, (UA_ExtensionObject*)ptrd);
-            break;
-        case UA_TYPES_DATAVALUE:
-            retval |= UA_DataValue_copy((const UA_DataValue*)ptrs, (UA_DataValue*)ptrd);
-            break;
-        case UA_TYPES_VARIANT:
-            retval |= UA_Variant_copy((const UA_Variant*)ptrs, (UA_Variant*)ptrd);
-            break;
-        case UA_TYPES_DIAGNOSTICINFO:
-            retval |= UA_DiagnosticInfo_copy((const UA_DiagnosticInfo*)ptrs, (UA_DiagnosticInfo*)ptrd);
-            break;
-        default:
-            // QualifiedName, LocalizedText and strings are treated as structures, also
-            retval |= UA_copy((const void *)ptrs, (void*)ptrd, memberType);
         }
         }
-        ptrs += memberType->memSize;
-        ptrd += memberType->memSize;
-    }
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_deleteMembers(dst, dataType);
-        UA_init(dst, dataType);
     }
     }
+    if(retval != UA_STATUSCODE_GOOD)
+        UA_deleteMembersUntil(dst, dataType, i);
     return retval;
     return retval;
 }
 }
 
 
 void UA_deleteMembers(void *p, const UA_DataType *dataType) {
 void UA_deleteMembers(void *p, const UA_DataType *dataType) {
-    UA_deleteMembersUntil(p, dataType, -1);
+    UA_deleteMembersUntil(p, dataType, UA_UINT16_MIN); // lastMember is bigger than the possible member count
 }
 }
 
 
-void UA_deleteMembersUntil(void *p, const UA_DataType *dataType, UA_Int32 lastMember) {
-    uintptr_t ptr = (uintptr_t)p;
+void UA_deleteMembersUntil(void *p, const UA_DataType *dataType, size_t lastMember) {
     if(dataType->fixedSize)
     if(dataType->fixedSize)
         return;
         return;
-    UA_Byte membersSize = dataType->membersSize;
-    for(size_t i=0;i<membersSize; i++) {
-        if(lastMember > -1 && (UA_Int32)i > lastMember){
-            return;
-        }
+    switch(dataType->typeIndex) {
+    case UA_TYPES_NODEID:
+        UA_NodeId_deleteMembers((UA_NodeId*)p);
+        return;
+    case UA_TYPES_EXTENSIONOBJECT:
+        UA_ExtensionObject_deleteMembers((UA_ExtensionObject*)p);
+        return;
+    case UA_TYPES_DATAVALUE:
+        UA_DataValue_deleteMembers((UA_DataValue*)p);
+        return;
+    case UA_TYPES_VARIANT:
+        UA_Variant_deleteMembers((UA_Variant*)p);
+        return;
+    case UA_TYPES_DIAGNOSTICINFO:
+        UA_DiagnosticInfo_deleteMembers((UA_DiagnosticInfo*)p);
+        return;
+    }
+
+    uintptr_t ptr = (uintptr_t)p;
+    size_t until = dataType->membersSize;
+    if(lastMember < until)
+        until = lastMember;
+    for(size_t i = 0; i < until; i++) {
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataTypeMember *member = &dataType->members[i];
         const UA_DataType *memberType;
         const UA_DataType *memberType;
         if(member->namespaceZero)
         if(member->namespaceZero)
             memberType = &UA_TYPES[member->memberTypeIndex];
             memberType = &UA_TYPES[member->memberTypeIndex];
         else
         else
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
-
-        if(member->isArray) {
+        if(!member->isArray) {
+            ptr += member->padding;
+            UA_deleteMembers((void*)ptr, memberType);
+            ptr += memberType->memSize;
+        } else {
             ptr += (member->padding >> 3);
             ptr += (member->padding >> 3);
             UA_Int32 elements = *((UA_Int32*)ptr);
             UA_Int32 elements = *((UA_Int32*)ptr);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             UA_Array_delete(*(void**)ptr, memberType, elements);
             UA_Array_delete(*(void**)ptr, memberType, elements);
             *(void**)ptr = UA_NULL;
             *(void**)ptr = UA_NULL;
             ptr += sizeof(void*);
             ptr += sizeof(void*);
-            continue;
-        }
-
-        ptr += member->padding;
-        if(!member->namespaceZero) {
-            UA_deleteMembers((void*)ptr, memberType);
-            ptr += memberType->memSize;
-            continue;
         }
         }
-
-        switch(member->memberTypeIndex) {
-        case UA_TYPES_BOOLEAN:
-        case UA_TYPES_SBYTE:
-        case UA_TYPES_BYTE:
-        case UA_TYPES_INT16:
-        case UA_TYPES_UINT16:
-        case UA_TYPES_INT32:
-        case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-        case UA_TYPES_FLOAT:
-        case UA_TYPES_INT64:
-        case UA_TYPES_UINT64:
-        case UA_TYPES_DOUBLE:
-        case UA_TYPES_DATETIME:
-        case UA_TYPES_GUID:
-            break;
-        case UA_TYPES_NODEID:
-            UA_NodeId_deleteMembers((UA_NodeId*)ptr);
-            break;
-        case UA_TYPES_EXPANDEDNODEID:
-            UA_ExpandedNodeId_deleteMembers((UA_ExpandedNodeId*)ptr);
-            break;
-        case UA_TYPES_LOCALIZEDTEXT:
-            UA_LocalizedText_deleteMembers((UA_LocalizedText*)ptr);
-            break;
-        case UA_TYPES_EXTENSIONOBJECT:
-            UA_ExtensionObject_deleteMembers((UA_ExtensionObject*)ptr);
-            break;
-        case UA_TYPES_DATAVALUE:
-            UA_DataValue_deleteMembers((UA_DataValue*)ptr);
-            break;
-        case UA_TYPES_VARIANT:
-            UA_Variant_deleteMembers((UA_Variant*)ptr);
-            break;
-        case UA_TYPES_DIAGNOSTICINFO:
-            UA_DiagnosticInfo_deleteMembers((UA_DiagnosticInfo*)ptr);
-            break;
-        default:
-            // QualifiedName, LocalizedText and strings are treated as structures, also
-            if(lastMember > -1){
-                UA_deleteMembersUntil((void*)ptr, memberType, lastMember-i);
-            }
-            else
-                UA_deleteMembers((void*)ptr, memberType);
-        }
-        ptr += memberType->memSize;
     }
     }
 }
 }
 
 
@@ -1227,10 +1045,8 @@ UA_StatusCode UA_Array_copy(const void *src, void **dst, const UA_DataType *data
         ptrs += dataType->memSize;
         ptrs += dataType->memSize;
         ptrd += dataType->memSize;
         ptrd += dataType->memSize;
     }
     }
-
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         UA_Array_delete(*dst, dataType, elements);
         UA_Array_delete(*dst, dataType, elements);
-
     return retval;
     return retval;
 }
 }
 
 

+ 142 - 200
src/ua_types_encoding_binary.c

@@ -930,7 +930,47 @@ UA_StatusCode UA_DiagnosticInfo_decodeBinary(UA_ByteString const *src, size_t *U
 
 
 UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_ByteString *dst,
 UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_ByteString *dst,
                               size_t *UA_RESTRICT offset) {
                               size_t *UA_RESTRICT offset) {
-    uintptr_t ptr = (uintptr_t) src;
+    /* builtin types */
+    switch (dataType->typeIndex) {
+    case UA_TYPES_BOOLEAN:
+    case UA_TYPES_SBYTE:
+    case UA_TYPES_BYTE:
+        return UA_Byte_encodeBinary((const UA_Byte*)src, dst, offset);
+    case UA_TYPES_INT16:
+    case UA_TYPES_UINT16:
+        return UA_UInt16_encodeBinary((const UA_UInt16*)src, dst, offset);
+    case UA_TYPES_INT32:
+    case UA_TYPES_UINT32:
+    case UA_TYPES_STATUSCODE:
+        return UA_UInt32_encodeBinary((const UA_UInt32*)src, dst, offset);
+    case UA_TYPES_INT64:
+    case UA_TYPES_UINT64:
+    case UA_TYPES_DATETIME:
+        return UA_UInt64_encodeBinary((const UA_UInt64*)src, dst, offset);
+    case UA_TYPES_FLOAT:
+        return UA_Float_encodeBinary((const UA_Float*)src, dst, offset);
+    case UA_TYPES_DOUBLE:
+        return UA_Double_encodeBinary((const UA_Double*)src, dst, offset);
+    case UA_TYPES_GUID:
+        return UA_Guid_encodeBinary((const UA_Guid*)src, dst, offset);
+    case UA_TYPES_NODEID:
+        return UA_NodeId_encodeBinary((const UA_NodeId*)src, dst, offset);
+    case UA_TYPES_EXPANDEDNODEID:
+        return UA_ExpandedNodeId_encodeBinary((const UA_ExpandedNodeId*)src, dst, offset);
+    case UA_TYPES_LOCALIZEDTEXT:
+        return UA_LocalizedText_encodeBinary((const UA_LocalizedText*)src, dst, offset);
+    case UA_TYPES_EXTENSIONOBJECT:
+        return UA_ExtensionObject_encodeBinary((const UA_ExtensionObject*)src, dst, offset);
+    case UA_TYPES_DATAVALUE:
+        return UA_DataValue_encodeBinary((const UA_DataValue*)src, dst, offset);
+    case UA_TYPES_VARIANT:
+        return UA_Variant_encodeBinary((const UA_Variant*)src, dst, offset);
+    case UA_TYPES_DIAGNOSTICINFO:
+        return UA_DiagnosticInfo_encodeBinary((const UA_DiagnosticInfo*)src, dst, offset);
+    }
+
+    /* structured type */
+    uintptr_t ptr = (uintptr_t)src;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
     for(size_t i = 0; i < membersSize && retval == UA_STATUSCODE_GOOD; i++) {
     for(size_t i = 0; i < membersSize && retval == UA_STATUSCODE_GOOD; i++) {
@@ -940,84 +980,63 @@ UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_B
             memberType = &UA_TYPES[member->memberTypeIndex];
             memberType = &UA_TYPES[member->memberTypeIndex];
         else
         else
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
-        if(member->isArray) {
+        if(!member->isArray) {
+            ptr += member->padding;
+            retval = UA_encodeBinary((const void*) ptr, memberType, dst, offset);
+            ptr += memberType->memSize;
+        } else {
             ptr += (member->padding >> 3);
             ptr += (member->padding >> 3);
             const UA_Int32 noElements = *((const UA_Int32*) ptr);
             const UA_Int32 noElements = *((const UA_Int32*) ptr);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             retval = UA_Array_encodeBinary(*(void * const *) ptr, noElements, memberType, dst, offset);
             retval = UA_Array_encodeBinary(*(void * const *) ptr, noElements, memberType, dst, offset);
             ptr += sizeof(void*);
             ptr += sizeof(void*);
-            continue;
-        }
-
-        ptr += member->padding;
-        if(!member->namespaceZero) {
-            UA_encodeBinary((const void*) ptr, memberType, dst, offset);
-            ptr += memberType->memSize;
-            continue;
         }
         }
-
-        switch (member->memberTypeIndex) {
-        case UA_TYPES_BOOLEAN:
-        case UA_TYPES_SBYTE:
-        case UA_TYPES_BYTE:
-            retval = UA_Byte_encodeBinary((const UA_Byte*) ptr, dst, offset);
-            break;
-        case UA_TYPES_INT16:
-        case UA_TYPES_UINT16:
-            retval = UA_UInt16_encodeBinary((const UA_UInt16*) ptr, dst, offset);
-            break;
-        case UA_TYPES_INT32:
-        case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-            retval = UA_UInt32_encodeBinary((const UA_UInt32*) ptr, dst, offset);
-            break;
-        case UA_TYPES_INT64:
-        case UA_TYPES_UINT64:
-        case UA_TYPES_DATETIME:
-            retval = UA_UInt64_encodeBinary((const UA_UInt64*) ptr, dst, offset);
-            break;
-        case UA_TYPES_FLOAT:
-            retval = UA_Float_encodeBinary((const UA_Float*) ptr, dst, offset);
-            break;
-        case UA_TYPES_DOUBLE:
-            retval = UA_Double_encodeBinary((const UA_Double*) ptr, dst, offset);
-            break;
-        case UA_TYPES_GUID:
-            retval = UA_Guid_encodeBinary((const UA_Guid*) ptr, dst, offset);
-            break;
-        case UA_TYPES_NODEID:
-            retval = UA_NodeId_encodeBinary((const UA_NodeId*) ptr, dst, offset);
-            break;
-        case UA_TYPES_EXPANDEDNODEID:
-            retval = UA_ExpandedNodeId_encodeBinary((const UA_ExpandedNodeId*) ptr, dst, offset);
-            break;
-        case UA_TYPES_LOCALIZEDTEXT:
-            retval = UA_LocalizedText_encodeBinary((const UA_LocalizedText*) ptr, dst, offset);
-            break;
-        case UA_TYPES_EXTENSIONOBJECT:
-            retval = UA_ExtensionObject_encodeBinary((const UA_ExtensionObject*) ptr, dst, offset);
-            break;
-        case UA_TYPES_DATAVALUE:
-            retval = UA_DataValue_encodeBinary((const UA_DataValue*) ptr, dst, offset);
-            break;
-        case UA_TYPES_VARIANT:
-            retval = UA_Variant_encodeBinary((const UA_Variant*) ptr, dst, offset);
-            break;
-        case UA_TYPES_DIAGNOSTICINFO:
-            retval = UA_DiagnosticInfo_encodeBinary((const UA_DiagnosticInfo*) ptr, dst, offset);
-            break;
-        default:
-            // also handles UA_TYPES_QUALIFIEDNAME, UA_TYPES_STRING, UA_TYPES_BYTESTRING,
-            // UA_TYPES_XMLELEMENT
-            retval = UA_encodeBinary((const void*) ptr, memberType, dst, offset);
-        }
-        ptr += memberType->memSize;
     }
     }
     return retval;
     return retval;
 }
 }
 
 
 UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset,
 UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset,
                               void *dst, const UA_DataType *dataType) {
                               void *dst, const UA_DataType *dataType) {
+    /* builtin types */
+    switch (dataType->typeIndex) {
+    case UA_TYPES_BOOLEAN:
+    case UA_TYPES_SBYTE:
+    case UA_TYPES_BYTE:
+        return UA_Byte_decodeBinary(src, offset, (UA_Byte*)dst);
+    case UA_TYPES_INT16:
+    case UA_TYPES_UINT16:
+        return UA_Int16_decodeBinary(src, offset, (UA_Int16*)dst);
+    case UA_TYPES_INT32:
+    case UA_TYPES_UINT32:
+    case UA_TYPES_STATUSCODE:
+        return UA_UInt32_decodeBinary(src, offset, (UA_UInt32*)dst);
+    case UA_TYPES_INT64:
+    case UA_TYPES_UINT64:
+    case UA_TYPES_DATETIME:
+        return UA_UInt64_decodeBinary(src, offset, (UA_UInt64*)dst);
+    case UA_TYPES_FLOAT:
+        return UA_Float_decodeBinary(src, offset, (UA_Float*)dst);
+    case UA_TYPES_DOUBLE:
+        return UA_Double_decodeBinary(src, offset, (UA_Double*)dst);
+    case UA_TYPES_GUID:
+        return UA_Guid_decodeBinary(src, offset, (UA_Guid*)dst);
+    case UA_TYPES_NODEID:
+        return UA_NodeId_decodeBinary(src, offset, (UA_NodeId*)dst);
+    case UA_TYPES_EXPANDEDNODEID:
+        return UA_ExpandedNodeId_decodeBinary(src, offset, (UA_ExpandedNodeId*)dst);
+    case UA_TYPES_LOCALIZEDTEXT:
+        return UA_LocalizedText_decodeBinary(src, offset, (UA_LocalizedText*)dst);
+    case UA_TYPES_EXTENSIONOBJECT:
+        return UA_ExtensionObject_decodeBinary(src, offset, (UA_ExtensionObject*)dst);
+    case UA_TYPES_DATAVALUE:
+        return UA_DataValue_decodeBinary(src, offset, (UA_DataValue*)dst);
+    case UA_TYPES_VARIANT:
+        return UA_Variant_decodeBinary(src, offset, (UA_Variant*)dst);
+    case UA_TYPES_DIAGNOSTICINFO:
+        return UA_DiagnosticInfo_decodeBinary(src, offset, (UA_DiagnosticInfo*)dst);
+    }
+
+    /* structured types */
     uintptr_t ptr = (uintptr_t) dst;
     uintptr_t ptr = (uintptr_t) dst;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
@@ -1029,84 +1048,24 @@ UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offs
             memberType = &UA_TYPES[member->memberTypeIndex];
             memberType = &UA_TYPES[member->memberTypeIndex];
         else
         else
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
-        if(member->isArray) {
+        if(!member->isArray) {
+            ptr += member->padding;
+            retval = UA_decodeBinary(src, offset, (void*)ptr, memberType);
+            ptr += memberType->memSize;
+        } else {
             ptr += (member->padding >> 3);
             ptr += (member->padding >> 3);
             UA_Int32 *noElements = (UA_Int32*) ptr;
             UA_Int32 *noElements = (UA_Int32*) ptr;
             UA_Int32 tempNoElements = 0;
             UA_Int32 tempNoElements = 0;
-            retval |= UA_Int32_decodeBinary(src, offset, &tempNoElements);
-            if(retval)
-                continue;
+            retval = UA_Int32_decodeBinary(src, offset, &tempNoElements);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
-            retval = UA_Array_decodeBinary(src, offset, tempNoElements, (void**) ptr, memberType);
-            if(retval == UA_STATUSCODE_GOOD)
-                *noElements = tempNoElements;
+            retval = UA_Array_decodeBinary(src, offset, tempNoElements, (void**)ptr, memberType);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
+            *noElements = tempNoElements;
             ptr += sizeof(void*);
             ptr += sizeof(void*);
-            continue;
-        }
-
-        ptr += member->padding;
-        if(!member->namespaceZero) {
-            UA_decodeBinary(src, offset, (void*) ptr, memberType);
-            ptr += memberType->memSize;
-            continue;
         }
         }
-
-        switch (member->memberTypeIndex) {
-        case UA_TYPES_BOOLEAN:
-        case UA_TYPES_SBYTE:
-        case UA_TYPES_BYTE:
-            retval = UA_Byte_decodeBinary(src, offset, (UA_Byte*) ptr);
-            break;
-        case UA_TYPES_INT16:
-        case UA_TYPES_UINT16:
-            retval = UA_Int16_decodeBinary(src, offset, (UA_Int16*) ptr);
-            break;
-        case UA_TYPES_INT32:
-        case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-            retval = UA_UInt32_decodeBinary(src, offset, (UA_UInt32*) ptr);
-            break;
-        case UA_TYPES_INT64:
-        case UA_TYPES_UINT64:
-        case UA_TYPES_DATETIME:
-            retval = UA_UInt64_decodeBinary(src, offset, (UA_UInt64*) ptr);
-            break;
-        case UA_TYPES_FLOAT:
-            retval = UA_Float_decodeBinary(src, offset, (UA_Float*) ptr);
-            break;
-        case UA_TYPES_DOUBLE:
-            retval = UA_Double_decodeBinary(src, offset, (UA_Double*) ptr);
-            break;
-        case UA_TYPES_GUID:
-            retval = UA_Guid_decodeBinary(src, offset, (UA_Guid*) ptr);
-            break;
-        case UA_TYPES_NODEID:
-            retval = UA_NodeId_decodeBinary(src, offset, (UA_NodeId*) ptr);
-            break;
-        case UA_TYPES_EXPANDEDNODEID:
-            retval = UA_ExpandedNodeId_decodeBinary(src, offset, (UA_ExpandedNodeId*) ptr);
-            break;
-        case UA_TYPES_LOCALIZEDTEXT:
-            retval = UA_LocalizedText_decodeBinary(src, offset, (UA_LocalizedText*) ptr);
-            break;
-        case UA_TYPES_EXTENSIONOBJECT:
-            retval = UA_ExtensionObject_decodeBinary(src, offset, (UA_ExtensionObject*) ptr);
-            break;
-        case UA_TYPES_DATAVALUE:
-            retval = UA_DataValue_decodeBinary(src, offset, (UA_DataValue*) ptr);
-            break;
-        case UA_TYPES_VARIANT:
-            retval = UA_Variant_decodeBinary(src, offset, (UA_Variant*) ptr);
-            break;
-        case UA_TYPES_DIAGNOSTICINFO:
-            retval = UA_DiagnosticInfo_decodeBinary(src, offset, (UA_DiagnosticInfo*) ptr);
-            break;
-        default:
-            // also handles UA_TYPES_QUALIFIEDNAME, UA_TYPES_STRING, UA_TYPES_BYTESTRING,
-            // UA_TYPES_XMLELEMENT
-            retval = UA_decodeBinary(src, offset, (void*) ptr, memberType);
-        }
-        ptr += memberType->memSize;
     }
     }
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         UA_deleteMembersUntil(dst, dataType, i);
         UA_deleteMembersUntil(dst, dataType, i);
@@ -1271,6 +1230,44 @@ static size_t UA_DiagnosticInfo_calcSizeBinary(UA_DiagnosticInfo const *p) {
 }
 }
 
 
 size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType) {
 size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType) {
+    /* builtin types */
+    switch (dataType->typeIndex) {
+    case UA_TYPES_BOOLEAN:
+    case UA_TYPES_SBYTE:
+    case UA_TYPES_BYTE:
+        return 1;
+    case UA_TYPES_INT16:
+    case UA_TYPES_UINT16:
+        return 2;
+    case UA_TYPES_INT32:
+    case UA_TYPES_UINT32:
+    case UA_TYPES_STATUSCODE:
+    case UA_TYPES_FLOAT:
+        return 4;
+    case UA_TYPES_INT64:
+    case UA_TYPES_UINT64:
+    case UA_TYPES_DOUBLE:
+    case UA_TYPES_DATETIME:
+        return 8;
+    case UA_TYPES_GUID:
+        return 16;
+    case UA_TYPES_NODEID:
+        return UA_NodeId_calcSizeBinary((const UA_NodeId*)p);
+    case UA_TYPES_EXPANDEDNODEID:
+        return UA_ExpandedNodeId_calcSizeBinary((const UA_ExpandedNodeId*)p);
+    case UA_TYPES_LOCALIZEDTEXT:
+        return UA_LocalizedText_calcSizeBinary((const UA_LocalizedText*)p);
+    case UA_TYPES_EXTENSIONOBJECT:
+        return UA_ExtensionObject_calcSizeBinary((const UA_ExtensionObject*)p);
+    case UA_TYPES_DATAVALUE:
+        return UA_DataValue_calcSizeBinary((const UA_DataValue*)p);
+    case UA_TYPES_VARIANT:
+        return UA_Variant_calcSizeBinary((const UA_Variant*)p);
+    case UA_TYPES_DIAGNOSTICINFO:
+        return UA_DiagnosticInfo_calcSizeBinary((const UA_DiagnosticInfo*)p);
+    }
+
+    /* structured types */
     size_t size = 0;
     size_t size = 0;
     uintptr_t ptr = (uintptr_t) p;
     uintptr_t ptr = (uintptr_t) p;
     UA_Byte membersSize = dataType->membersSize;
     UA_Byte membersSize = dataType->membersSize;
@@ -1281,73 +1278,18 @@ size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType) {
             memberType = &UA_TYPES[member->memberTypeIndex];
             memberType = &UA_TYPES[member->memberTypeIndex];
         else
         else
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
             memberType = &dataType[member->memberTypeIndex - dataType->typeIndex];
-
-        if(member->isArray) {
+        if(!member->isArray) {
+            ptr += member->padding;
+            size += UA_calcSizeBinary((const void*)ptr, memberType);
+            ptr += memberType->memSize;
+        } else {
             ptr += (member->padding >> 3);
             ptr += (member->padding >> 3);
             const UA_Int32 elements = *((const UA_Int32*) ptr);
             const UA_Int32 elements = *((const UA_Int32*) ptr);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
-            size += UA_Array_calcSizeBinary(*(void * const *) ptr, elements, memberType);
+            size += UA_Array_calcSizeBinary(*(void * const *)ptr, elements, memberType);
             ptr += sizeof(void*);
             ptr += sizeof(void*);
             continue;
             continue;
         }
         }
-
-        ptr += member->padding;
-        if(!member->namespaceZero) {
-            size += UA_calcSizeBinary((const void*) ptr, memberType);
-            ptr += memberType->memSize;
-            continue;
-        }
-
-        switch (member->memberTypeIndex) {
-        case UA_TYPES_BOOLEAN:
-        case UA_TYPES_SBYTE:
-        case UA_TYPES_BYTE:
-            size += 1;
-            break;
-        case UA_TYPES_INT16:
-        case UA_TYPES_UINT16:
-            size += 2;
-            break;
-        case UA_TYPES_INT32:
-        case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-        case UA_TYPES_FLOAT:
-            size += 4;
-            break;
-        case UA_TYPES_INT64:
-        case UA_TYPES_UINT64:
-        case UA_TYPES_DOUBLE:
-        case UA_TYPES_DATETIME:
-            size += 8;
-            break;
-        case UA_TYPES_GUID:
-            size += 16;
-            break;
-        case UA_TYPES_NODEID:
-            size += UA_NodeId_calcSizeBinary((const UA_NodeId*) ptr);
-            break;
-        case UA_TYPES_EXPANDEDNODEID:
-            size += UA_ExpandedNodeId_calcSizeBinary((const UA_ExpandedNodeId*) ptr);
-            break;
-        case UA_TYPES_LOCALIZEDTEXT:
-            size += UA_LocalizedText_calcSizeBinary((const UA_LocalizedText*) ptr);
-            break;
-        case UA_TYPES_EXTENSIONOBJECT:
-            size += UA_ExtensionObject_calcSizeBinary((const UA_ExtensionObject*) ptr);
-            break;
-        case UA_TYPES_DATAVALUE:
-            size += UA_DataValue_calcSizeBinary((const UA_DataValue*) ptr);
-            break;
-        case UA_TYPES_VARIANT:
-            size += UA_Variant_calcSizeBinary((const UA_Variant*) ptr);
-            break;
-        case UA_TYPES_DIAGNOSTICINFO:
-            size += UA_DiagnosticInfo_calcSizeBinary((const UA_DiagnosticInfo*) ptr);
-            break;
-        default:
-            size += UA_calcSizeBinary((const void*) ptr, memberType);
-        }
-        ptr += memberType->memSize;
     }
     }
     return size;
     return size;
 }
 }

+ 4 - 2
tests/CMakeLists.txt

@@ -46,12 +46,14 @@ add_executable(check_services_attributes check_services_attributes.c $<TARGET_OB
 target_link_libraries(check_services_attributes ${LIBS})
 target_link_libraries(check_services_attributes ${LIBS})
 add_test(services_attributes ${CMAKE_CURRENT_BINARY_DIR}/check_services_attributes)
 add_test(services_attributes ${CMAKE_CURRENT_BINARY_DIR}/check_services_attributes)
 
 
+add_executable(check_services_nodemanagement check_services_nodemanagement.c $<TARGET_OBJECTS:open62541-object>)
+target_link_libraries(check_services_nodemanagement ${LIBS})
+add_test(services_nodemanagement ${CMAKE_CURRENT_BINARY_DIR}/check_services_nodemanagement)
+
 add_executable(check_nodestore check_nodestore.c $<TARGET_OBJECTS:open62541-object>)
 add_executable(check_nodestore check_nodestore.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_nodestore ${LIBS})
 target_link_libraries(check_nodestore ${LIBS})
 add_test(nodestore ${CMAKE_CURRENT_BINARY_DIR}/check_nodestore)
 add_test(nodestore ${CMAKE_CURRENT_BINARY_DIR}/check_nodestore)
 
 
-
-
 add_executable(check_session check_session.c $<TARGET_OBJECTS:open62541-object>)
 add_executable(check_session check_session.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_session ${LIBS})
 target_link_libraries(check_session ${LIBS})
 add_test(session ${CMAKE_CURRENT_BINARY_DIR}/check_session)
 add_test(session ${CMAKE_CURRENT_BINARY_DIR}/check_session)

Diferenças do arquivo suprimidas por serem muito extensas
+ 859 - 1015
tests/check_services_attributes.c


+ 60 - 0
tests/check_services_nodemanagement.c

@@ -0,0 +1,60 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "check.h"
+#include "server/ua_nodestore.h"
+#include "server/ua_services.h"
+#include "ua_client.h"
+#include "ua_nodeids.h"
+#include "ua_statuscodes.h"
+#include "ua_types.h"
+#include "ua_util.h"
+#include "server/ua_server_internal.h"
+
+#ifdef UA_MULTITHREADING
+#include <pthread.h>
+#include <urcu.h>
+#endif
+
+START_TEST(AddVariableNode) {
+    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+
+    /* add a variable node to the address space */
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
+    UA_Int32 myInteger = 42;
+    UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
+                                                  myIntegerName, UA_NODEID_NULL, attr, NULL);
+    ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
+    UA_Server_delete(server);
+} END_TEST
+
+static Suite * testSuite_services_nodemanagement(void) {
+	Suite *s = suite_create("services_nodemanagement");
+
+	TCase *tc_addnodes = tcase_create("addnodes");
+	tcase_add_test(tc_addnodes, AddVariableNode);
+
+	suite_add_tcase(s, tc_addnodes);
+	return s;
+}
+
+int main(void) {
+	int number_failed = 0;
+	Suite *s;
+	s = testSuite_services_nodemanagement();
+	SRunner *sr = srunner_create(s);
+	// srunner_set_fork_status(sr, CK_NOFORK);
+	srunner_run_all(sr, CK_NORMAL);
+	number_failed += srunner_ntests_failed(sr);
+	srunner_free(sr);
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}

+ 38 - 11
tools/generate_datatypes.py

@@ -53,9 +53,10 @@ minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "Applicati
                  "AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
                  "AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
                  "AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
                  "AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
                  "ViewNode", "ReferenceTypeNode", "BrowseResultMask", "ServerState", "ServerStatusDataType", "BuildInfo",
                  "ViewNode", "ReferenceTypeNode", "BrowseResultMask", "ServerState", "ServerStatusDataType", "BuildInfo",
-                 "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "VariableAttributes", "ObjectAttributes",
-                 "NodeAttributes","ReferenceTypeAttributes", "ViewAttributes", "ObjectTypeAttributes",
-                 "NodeAttributesMask","DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
+                 "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "NodeAttributes",
+                 "VariableAttributes", "ObjectAttributes", "ReferenceTypeAttributes", "ViewAttributes", "MethodAttributes",
+                 "ObjectTypeAttributes", "VariableTypeAttributes", "DataTypeAttributes", "NodeAttributesMask",
+                 "DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
                  "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
                  "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
                  "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse", 
                  "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse", 
                  "UserIdentityToken", "UserNameIdentityToken", "AnonymousIdentityToken", "ServiceFault",
                  "UserIdentityToken", "UserNameIdentityToken", "AnonymousIdentityToken", "ServiceFault",
@@ -124,28 +125,54 @@ class BuiltinType(object):
                 ".padding = offsetof(UA_String, data) - sizeof(UA_Int32), .isArray = UA_TRUE }}, " + \
                 ".padding = offsetof(UA_String, data) - sizeof(UA_Int32), .isArray = UA_TRUE }}, " + \
                 ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
                 ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
 
 
+        if self.name == "UA_ExpandedNodeId":
+            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
+                ".memSize = sizeof(UA_ExpandedNodeId), " + \
+                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".membersSize = 3, .members = {" + \
+                "\n\t{.memberTypeIndex = UA_TYPES_NODEID, .namespaceZero = UA_TRUE, " + \
+                (".memberName = \"nodeId\", " if typeintrospection else "") + \
+                ".padding = 0, .isArray = UA_FALSE }," + \
+                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
+                (".memberName = \"namespaceUri\", " if typeintrospection else "") + \
+                ".padding = offsetof(UA_ExpandedNodeId, namespaceUri) - sizeof(UA_NodeId), .isArray = UA_FALSE }," + \
+                "\n\t{.memberTypeIndex = UA_TYPES_UINT32, .namespaceZero = UA_TRUE, " + \
+                (".memberName = \"serverIndex\", " if typeintrospection else "") + \
+                ".padding = offsetof(UA_ExpandedNodeId, serverIndex) - offsetof(UA_ExpandedNodeId, namespaceUri) - sizeof(UA_String), .isArray = UA_FALSE }},\n" + \
+                ".typeIndex = UA_TYPES_EXPANDEDNODEID }"
+
         if self.name == "UA_QualifiedName":
         if self.name == "UA_QualifiedName":
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(UA_QualifiedName), " + \
                 ".memSize = sizeof(UA_QualifiedName), " + \
                 ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".membersSize = 2, .members = {" + \
                 ".membersSize = 2, .members = {" + \
                 "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
                 "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
-                (".memberName = (char*)0, " if typeintrospection else "") + \
+                (".memberName = \"namespaceIndex\", " if typeintrospection else "") + \
                 ".padding = 0, .isArray = UA_FALSE }," + \
                 ".padding = 0, .isArray = UA_FALSE }," + \
                 "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
                 "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
-                (".memberName = (char*)0, " if typeintrospection else "") + \
-                ".padding = offsetof(UA_QualifiedName, name) - sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
+                (".memberName = \"name\", " if typeintrospection else "") + \
+                ".padding = offsetof(UA_QualifiedName, name)-sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
                 ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
                 ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
-                
+
+        if self.name == "UA_LocalizedText":
+            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
+                ".memSize = sizeof(UA_LocalizedText), " + \
+                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".membersSize = 2, .members = {" + \
+                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
+                (".memberName = \"locale\", " if typeintrospection else "") + \
+                ".padding = 0, .isArray = UA_FALSE }," + \
+                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
+                (".memberName = \"text\", " if typeintrospection else "") + \
+                ".padding = offsetof(UA_LocalizedText, text)-sizeof(UA_String), .isArray = UA_FALSE }},\n" + \
+                ".typeIndex = UA_TYPES_LOCALIZEDTEXT }"
+
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), " + \
             ".memSize = sizeof(" + self.name + "), " + \
             ".namespaceZero = UA_TRUE, " + \
             ".namespaceZero = UA_TRUE, " + \
             ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
             ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
             ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
             ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
-            ", .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + "," + \
-            (".memberName = (char*)0, " if typeintrospection else "") + \
-            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, " + \
-            ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
+            ", .membersSize = 0, .typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
 
 
 class EnumerationType(object):
 class EnumerationType(object):
     def __init__(self, name, description = "", elements = OrderedDict()):
     def __init__(self, name, description = "", elements = OrderedDict()):

+ 44 - 34
tools/pyUANamespace/open62541_MacroHelper.py

@@ -80,48 +80,56 @@ class open62541_MacroHelper():
     #code.append("addOneWayReferenceWithSession(server, (UA_Session *) UA_NULL, &" + refid + ");")
     #code.append("addOneWayReferenceWithSession(server, (UA_Session *) UA_NULL, &" + refid + ");")
 
 
     if reference.isForward():
     if reference.isForward():
-      code.append("UA_Server_addMonodirectionalReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", UA_TRUE);")
+      code.append("UA_Server_addReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", UA_TRUE);")
     else:
     else:
-      code.append("UA_Server_addMonodirectionalReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", UA_FALSE);")
-
+      code.append("UA_Server_addReference(server, " + self.getCreateNodeIDMacro(sourcenode) + ", " + self.getCreateNodeIDMacro(reference.referenceType()) + ", " + self.getCreateExpandedNodeIDMacro(reference.target()) + ", UA_FALSE);")
     return code
     return code
                                
                                
   def getCreateNodeNoBootstrap(self, node, parentNode, parentReference):
   def getCreateNodeNoBootstrap(self, node, parentNode, parentReference):
     code = []
     code = []
     code.append("// Node: " + str(node) + ", " + str(node.browseName()))
     code.append("// Node: " + str(node) + ", " + str(node.browseName()))
+
     if node.nodeClass() == NODE_CLASS_OBJECT:
     if node.nodeClass() == NODE_CLASS_OBJECT:
-      code.append("UA_Server_addObjectNode(server, ")
+      nodetype = "Object"
     elif node.nodeClass() == NODE_CLASS_VARIABLE:
     elif node.nodeClass() == NODE_CLASS_VARIABLE:
-      code.append("UA_Server_addVariableNode(server,")
+      nodetype = "Variable"
     elif node.nodeClass() == NODE_CLASS_METHOD:
     elif node.nodeClass() == NODE_CLASS_METHOD:
-      code.append("#ifdef ENABLE_METHODCALL")
-      code.append("UA_Server_addMethodNode(server,")
+      nodetype = "Method"
     elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
     elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
-      code.append("UA_Server_addObjectTypeNode(server,")
+      nodetype = "ObjectType"
     elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
     elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
-      code.append("UA_Server_addReferenceTypeNode(server,")
+      nodetype = "ReferenceType"
     elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
     elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
-      code.append("UA_Server_addVariableTypeNode(server,")
+      nodetype = "VariableType"
     elif node.nodeClass() == NODE_CLASS_DATATYPE:
     elif node.nodeClass() == NODE_CLASS_DATATYPE:
-      code.append("UA_Server_addDataTypeNode(server,")
+      nodetype = "DataType"
     elif node.nodeClass() == NODE_CLASS_VIEW:
     elif node.nodeClass() == NODE_CLASS_VIEW:
-      code.append("UA_Server_addViewNode(server,")
-    elif node.nodeClass() == NODE_CLASS_METHODTYPE:
-      code.append("UA_Server_addMethodTypeNode(server,")
+      nodetype = "View"
     else:
     else:
-      return []
+      code.append("/* undefined nodeclass */")
+      return code;
+
+    code.append("UA_%sAttributes attr;" % nodetype)
+    code.append("UA_%sAttributes_init(&attr);" %  nodetype); 
+
+    code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\");")
+    code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\");")
     
     
-    code.append("       " + str(self.getCreateNodeIDMacro(node)) + ",") # NodeId
+    code.append("UA_NodeId nodeId = " + str(self.getCreateNodeIDMacro(node)) + ";")
+    if nodetype in ["Object", "Variable"]:
+      code.append("UA_NodeId typeDefinition = UA_NODEID_NULL;") # todo instantiation of object and variable types
+    code.append("UA_NodeId parentNodeId = " + str(self.getCreateNodeIDMacro(parentNode)) + ";")
+    code.append("UA_NodeId parentReferenceNodeId = " + str(self.getCreateNodeIDMacro(parentReference.referenceType())) + ";")
     extrNs = node.browseName().split(":")
     extrNs = node.browseName().split(":")
     if len(extrNs) > 1:
     if len(extrNs) > 1:
-      code.append("       UA_QUALIFIEDNAME(" +  str(extrNs[0]) + ", \"" + extrNs[1] + "\"),")  # browseName
+      code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(" +  str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
     else:
     else:
-      code.append("       UA_QUALIFIEDNAME(0, \"" + str(node.browseName()) + "\"),")  # browseName
-    code.append("       UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\"),")  # displayName
-    code.append("       UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\"),")  # description
-    code.append("       " + str(node.writeMask()) + ", " + str(node.userWriteMask()) + ",") # write/userWriteMask
-    code.append("       " + str(self.getCreateNodeIDMacro(parentNode)) + ",") # ParentNode
-    code.append("       " + str(self.getCreateNodeIDMacro(parentReference.referenceType())) + ",") # ReferenceTypeId
+      code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"" + str(node.browseName()) + "\");")
+
+    code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
+    if nodetype in ["Object", "Variable"]:
+      code.append("       , typeDefinition")
+    code.append("       , attr, NULL);")
       
       
     return code
     return code
     
     
@@ -130,27 +138,29 @@ class open62541_MacroHelper():
     code = []
     code = []
 
 
     code.append("// Node: " + str(node) + ", " + str(node.browseName()))
     code.append("// Node: " + str(node) + ", " + str(node.browseName()))
+    code.append("/* sorry, nodebootstrap needs to be updated */")
 
 
     if node.nodeClass() == NODE_CLASS_OBJECT:
     if node.nodeClass() == NODE_CLASS_OBJECT:
-      nodetype = "UA_ObjectNode"
+      nodetype = "Object"
     elif node.nodeClass() == NODE_CLASS_VARIABLE:
     elif node.nodeClass() == NODE_CLASS_VARIABLE:
-      nodetype = "UA_VariableNode"
+      nodetype = "Variable"
     elif node.nodeClass() == NODE_CLASS_METHOD:
     elif node.nodeClass() == NODE_CLASS_METHOD:
-      nodetype = "UA_MethodNode"
+      nodetype = "Method"
     elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
     elif node.nodeClass() == NODE_CLASS_OBJECTTYPE:
-      nodetype = "UA_ObjectTypeNode"
+      nodetype = "ObjectType"
     elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
     elif node.nodeClass() == NODE_CLASS_REFERENCETYPE:
-      nodetype = "UA_ReferenceTypeNode"
+      nodetype = "ReferenceType"
     elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
     elif node.nodeClass() == NODE_CLASS_VARIABLETYPE:
-      nodetype = "UA_VariableTypeNode"
+      nodetype = "VariableType"
     elif node.nodeClass() == NODE_CLASS_DATATYPE:
     elif node.nodeClass() == NODE_CLASS_DATATYPE:
-      nodetype = "UA_DataTypeNode"
+      nodetype = "DataType"
     elif node.nodeClass() == NODE_CLASS_VIEW:
     elif node.nodeClass() == NODE_CLASS_VIEW:
-      nodetype = "UA_ViewNode"
-    elif node.nodeClass() == NODE_CLASS_METHODTYPE:
-      nodetype = "UA_MethodTypeNode"
+      nodetype = "View"
     else:
     else:
-      nodetype = "UA_NodeTypeNotFoundorGeneric"
+      code.append("/* undefined nodeclass */")
+      return;
+
+    code.append("UA_%sAttributes attr;\nUA_%sAttributes_init(&attr);" % (nodetype, nodetype)); 
 
 
     code.append(nodetype + " *" + node.getCodePrintableID() + " = " + nodetype + "_new();")
     code.append(nodetype + " *" + node.getCodePrintableID() + " = " + nodetype + "_new();")
     if not "browsename" in self.supressGenerationOfAttribute:
     if not "browsename" in self.supressGenerationOfAttribute:

+ 3 - 3
tools/pyUANamespace/ua_node_types.py

@@ -667,10 +667,10 @@ class opcua_node_t:
     (parentNode, parentRef) = self.getFirstParentNode()
     (parentNode, parentRef) = self.getFirstParentNode()
     if not (parentNode in unPrintedNodes) and (parentNode != None) and (parentRef.referenceType() != None):
     if not (parentNode in unPrintedNodes) and (parentNode != None) and (parentRef.referenceType() != None):
       code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" + str(parentNode .__node_browseName__) + " using " + str(parentRef.referenceType().id()) + "/" + str(parentRef.referenceType().__node_browseName__))
       code.append("// Referencing node found and declared as parent: " + str(parentNode .id()) + "/" + str(parentNode .__node_browseName__) + " using " + str(parentRef.referenceType().id()) + "/" + str(parentRef.referenceType().__node_browseName__))
-      code = code + self.printOpen62541CCode_SubtypeEarly(bootstrapping = False)
+      #code = code + self.printOpen62541CCode_SubtypeEarly(bootstrapping = False)
       code = code + codegen.getCreateNodeNoBootstrap(self, parentNode, parentRef)
       code = code + codegen.getCreateNodeNoBootstrap(self, parentNode, parentRef)
-      code = code + self.printOpen62541CCode_Subtype(unPrintedReferences = unPrintedReferences, bootstrapping = False)
-      code.append("       UA_NULL);") # createdNodeId, wraps up the UA_Server_add<XYType>Node() call
+      #code = code + self.printOpen62541CCode_Subtype(unPrintedReferences = unPrintedReferences, bootstrapping = False)
+      #code.append("       UA_NULL);") # createdNodeId, wraps up the UA_Server_add<XYType>Node() call
       if self.nodeClass() == NODE_CLASS_METHOD:
       if self.nodeClass() == NODE_CLASS_METHOD:
         code.append("#endif //ENABLE_METHODCALL") # ifdef added by codegen when methods are detected
         code.append("#endif //ENABLE_METHODCALL") # ifdef added by codegen when methods are detected
       # Parent to child reference is added by the server, do not reprint that reference
       # Parent to child reference is added by the server, do not reprint that reference

+ 1 - 1
tools/travis_linux_script.sh

@@ -63,7 +63,7 @@ make
 cd .. && rm build -rf && mkdir -p build && cd build
 cd .. && rm build -rf && mkdir -p build && cd build
 echo "Debug build and unit tests (64 bit)"
 echo "Debug build and unit tests (64 bit)"
 cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEMO_NODESET=ON -DBUILD_UNIT_TESTS=ON -DBUILD_EXAMPLESERVER=ON -DENABLE_COVERAGE=ON ..
 cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEMO_NODESET=ON -DBUILD_UNIT_TESTS=ON -DBUILD_EXAMPLESERVER=ON -DENABLE_COVERAGE=ON ..
-make && make test
+make && make test ARGS="-V"
 echo "Run valgrind to see if the server leaks memory (just starting up and closing..)"
 echo "Run valgrind to see if the server leaks memory (just starting up and closing..)"
 if [[ ! ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "clang") ]]; then
 if [[ ! ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "clang") ]]; then
   (valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
   (valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);