Przeglądaj źródła

Merge branch 'master' into hardening_client

Conflicts:
	examples/networklayer_tcp.c
Stasik0 10 lat temu
rodzic
commit
56822bd591

+ 45 - 58
CMakeLists.txt

@@ -19,20 +19,23 @@ endif()
 
 # compiler flags
 if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
-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
-                -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wconversion -Wshadow 
-                -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -ffunction-sections -fdata-sections)
-    if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
-        add_definitions(-Wformat-nonliteral)
-        set (CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--gc-sections")
-        set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
-    else()
-        add_definitions(-Wno-gnu-statement-expression)
-    endif()
+    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
+                    -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wshadow -Wconversion
+                    -Winit-self -Wuninitialized -Wformat-security -Wformat-nonliteral)
+    # binary size reduction settings
+	add_definitions(-ffunction-sections -fdata-sections -fno-stack-protector -fno-unwind-tables
+                    -fno-asynchronous-unwind-tables -fno-math-errno -fmerge-all-constants -fno-ident)
+    set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--gc-sections")
+    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
+    set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
 	if(NOT WIN32)
-	    add_definitions(-fstack-protector -fPIC -fvisibility=hidden)
+	    add_definitions(-fvisibility=hidden -fPIC)
+        set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
 	endif()
+    if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
+        set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s") # strip binary
+    endif()
 endif()
 
 # build the main library
@@ -138,19 +141,25 @@ if(BUILD_DEMO_NODESET)
 	add_definitions(-DDEMO_NODESET)
 endif()
 
-if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
-	set(AMALGATED ON)
-    ## build amalgamated source files
-    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c
-                   PRE_BUILD
-                   COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.h ${exported_headers}
-                   COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
-                                  ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${exported_headers} ${internal_headers}
-                           ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources})
+option(ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c
+               PRE_BUILD
+               COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.h ${exported_headers}
+                                                                              ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h
+                                                                              ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h
+               COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
+                              ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
+                                                                              ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c
+                                                                              ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
+               DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${exported_headers} ${internal_headers}
+                       ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
+                       ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h
+                       ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
 
+add_custom_target(amalgamation ALL DEPENDS ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c)
+if(ENABLE_AMALGAMATION)
     add_library(open62541-object OBJECT ${PROJECT_BINARY_DIR}/open62541.c)
-    add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
+    include_directories(${PROJECT_BINARY_DIR})
 else()
     add_definitions(-DNOT_AMALGATED)
     add_library(open62541-object OBJECT ${lib_sources} ${internal_headers} ${exported_headers})
@@ -159,7 +168,7 @@ else()
     include_directories(${PROJECT_SOURCE_DIR}/src)
     include_directories(${PROJECT_BINARY_DIR}/src_generated)
 endif()
-
+add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
 
 # build language bindings for the library
 option(ENABLE_BINDING_LUA "Build Lua bindings" OFF)
@@ -181,10 +190,12 @@ endif()
 # build example server
 option(BUILD_EXAMPLESERVER "Build the example server" OFF)
 if(BUILD_EXAMPLESERVER)
-    add_executable(exampleServer examples/server.c $<TARGET_OBJECTS:open62541-object> examples/networklayer_tcp.c examples/logger_stdout.c)
-    add_executable(exampleServer_simple examples/server_simple.c $<TARGET_OBJECTS:open62541-object> examples/networklayer_tcp.c examples/logger_stdout.c)
-    target_include_directories(exampleServer PRIVATE ${PROJECT_BINARY_DIR})
-    target_include_directories(exampleServer_simple PRIVATE ${PROJECT_BINARY_DIR})
+    set(server_source $<TARGET_OBJECTS:open62541-object>)
+    if(NOT ENABLE_AMALGAMATION)
+        list(APPEND server_source examples/networklayer_tcp.c examples/logger_stdout.c)
+    endif()
+    add_executable(exampleServer examples/server.c ${server_source})
+    add_executable(exampleServer_simple examples/server_simple.c ${server_source})
     if(WIN32)
         target_link_libraries(exampleServer ws2_32)
         target_link_libraries(exampleServer_simple ws2_32)
@@ -196,10 +207,6 @@ if(BUILD_EXAMPLESERVER)
         target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
         target_link_libraries(exampleServer_simple urcu-cds urcu urcu-common pthread)
     endif()
-    if((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
-    	add_custom_command(TARGET exampleServer POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleServer>)
-		add_custom_command(TARGET exampleServer_simple POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleServer_simple>)
-	endif()
 endif()
 
 ## self-signed certificates
@@ -217,42 +224,22 @@ endif()
 # build example client
 option(BUILD_EXAMPLECLIENT "Build a test client" OFF)
 if(BUILD_EXAMPLECLIENT)
-	message(STATUS "Extensions: enabling client")
-	add_definitions( -DBENCHMARK=1 )
-	if(NOT AMALGATED)
-		add_executable(exampleClient_legacy $<TARGET_OBJECTS:open62541-object> examples/client_legacy.c)
-	endif()
-	add_executable(exampleClient $<TARGET_OBJECTS:open62541-object> examples/client.c examples/networklayer_tcp.c)
-    if(NOT AMALGATED)
-    	target_include_directories(exampleClient_legacy PRIVATE ${PROJECT_BINARY_DIR})
+	add_definitions(-DBENCHMARK)
+    set(client_source $<TARGET_OBJECTS:open62541-object>)
+    if(NOT ENABLE_AMALGAMATION)
+        list(APPEND client_source examples/networklayer_tcp.c examples/logger_stdout.c)
     endif()
-    target_include_directories(exampleClient PRIVATE ${PROJECT_BINARY_DIR})
+	add_executable(exampleClient examples/client.c ${client_source})
     if(WIN32)
-    	if(NOT AMALGATED)
-        	target_link_libraries(exampleClient_legacy ws2_32)
-        endif()
         target_link_libraries(exampleClient ws2_32)
     else()
-   		if(NOT AMALGATED)
-        	target_link_libraries(exampleClient_legacy rt)
-        endif()
         target_link_libraries(exampleClient rt)
     endif()
-    if ((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
-       if(NOT AMALGATED)
-       		add_custom_command(TARGET exampleClient_legacy POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient_legacy>)
-	   endif()
-	   add_custom_command(TARGET exampleClient POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient>)
-	endif()
     if(EXTENSION_STATELESS)
-        add_executable(statelessClient ${PROJECT_BINARY_DIR}/open62541.c examples/client_stateless.c)
-        target_include_directories(statelessClient PRIVATE ${PROJECT_BINARY_DIR})
+        add_executable(statelessClient examples/client_stateless.c ${client_source})
         if(ENABLE_MULTITHREADING)
             target_link_libraries(statelessClient urcu-cds urcu urcu-common pthread)
         endif()
-        if ((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
-    	add_custom_command(TARGET statelessClient POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:statelessClient>)
-		endif()
     endif()
 endif()
 

Plik diff jest za duży
+ 18 - 24
README.md


+ 1 - 1
examples/client.c

@@ -22,7 +22,7 @@ int main(int argc, char *argv[]) {
     UA_ReadRequest_init(&req);
     req.nodesToRead = UA_ReadValueId_new();
     req.nodesToReadSize = 1;
-    req.nodesToRead[0].nodeId = UA_NODEID_STATIC(1, 442); /* assume this node exists */
+    req.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */
     req.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
 
     UA_ReadResponse resp = UA_Client_read(client, &req);

+ 4 - 4
examples/client_legacy.c

@@ -64,7 +64,7 @@ static int sendOpenSecureChannel(UA_Int32 sock) {
 
 	UA_UInt32 secureChannelId = 0;
 	UA_String securityPolicy;
-	UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &securityPolicy);
+	securityPolicy = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
 
 	UA_String senderCert;
 	senderCert.data = UA_NULL;
@@ -147,8 +147,8 @@ static UA_Int32 sendCreateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32
 	rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
 	rq.requestHeader.authenticationToken.namespaceIndex = 10;
 	UA_String_copy(endpointUrl, &rq.endpointUrl);
-	UA_String_copycstring("mysession", &rq.sessionName);
-	UA_String_copycstring("abcd", &rq.clientCertificate);
+	rq.sessionName = UA_STRING("mysession");
+	rq.clientCertificate = UA_STRING("abcd");
 	UA_ByteString_newMembers(&rq.clientNonce, 1);
 	rq.clientNonce.data[0] = 0;
 	rq.requestedSessionTimeout = 1200000;
@@ -501,7 +501,7 @@ int main(int argc, char *argv[]) {
 
     //Connect to remote server
 	UA_String endpoint;
-	UA_String_copycstring("none",&endpoint);
+	endpoint = UA_STRING("none");
 	ConnectionInfo connectionInfo;
 
 

+ 2 - 3
examples/client_stateless.c

@@ -1,5 +1,5 @@
 /*
-	C ECHO client example using sockets
+ * C ECHO client example using sockets
  */
 #include <stdio.h>	//printf
 #include <string.h>	//strlen
@@ -8,10 +8,9 @@
 #include <unistd.h> // for close
 #include <stdlib.h> // pulls in declaration of malloc, free
 
-#include "ua_transport_generated.h"
 #include "ua_util.h"
 #include "ua_types_encoding_binary.h"
-
+#include "ua_transport_generated.h"
 
 int main(int argc , char *argv[])
 {

+ 42 - 27
examples/networklayer_tcp.c

@@ -3,39 +3,41 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
 
-#include <stdlib.h> // malloc, free
+#ifdef NOT_AMALGATED
+# define _XOPEN_SOURCE 500 //some users need this for some reason
+# define __USE_BSD
+# include <stdlib.h> // malloc, free
+# include <stdio.h>
+# include <string.h> // memset
+#endif
+
 #ifdef _WIN32
-#include <malloc.h>
-#include <winsock2.h>
-#include <sys/types.h>
-#include <windows.h>
-#include <ws2tcpip.h>
-#define CLOSESOCKET(S) closesocket(S)
+# include <malloc.h>
+# include <winsock2.h>
+# include <sys/types.h>
+# include <windows.h>
+# include <ws2tcpip.h>
+# define CLOSESOCKET(S) closesocket(S)
 #else
-#include <sys/select.h> 
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/socketvar.h>
-#include <sys/ioctl.h>
-#include <netdb.h> //gethostbyname for the client
-#define __USE_BSD
-#include <unistd.h> // read, write, close, usleep
-#define Sleep(x) usleep((x)*1000)
-#include <arpa/inet.h>
-#define CLOSESOCKET(S) close(S)
+# include <sys/select.h> 
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <sys/ioctl.h>
+# include <netdb.h> //gethostbyname for the client
+# include <unistd.h> // read, write, close
+# include <arpa/inet.h>
+# define CLOSESOCKET(S) close(S)
 #endif
 
-#include <stdio.h>
-#include <errno.h> // errno, EINTR
-#include <fcntl.h> // fcntl
-#include <string.h> // memset
-
 #include "networklayer_tcp.h" // UA_MULTITHREADING is defined in here
-
 #ifdef UA_MULTITHREADING
-#include <urcu/uatomic.h>
+# include <urcu/uatomic.h>
 #endif
 
+/* with a space so amalgamation does not remove the includes */
+# include <errno.h> // errno, EINTR
+# include <fcntl.h> // fcntl
+
 struct ServerNetworklayer_TCP;
 
 /* Forwarded to the server as a (UA_Connection) and used for callbacks back into
@@ -566,13 +568,26 @@ static UA_StatusCode ClientNetworkLayerTCP_send(ClientNetworkLayerTCP *handle, U
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode ClientNetworkLayerTCP_awaitResponse(ClientNetworkLayerTCP *handle,
-                                                         UA_ByteString *response, UA_UInt32 timeout) {
+static UA_StatusCode ClientNetworkLayerTCP_awaitResponse(ClientNetworkLayerTCP *handle, UA_ByteString *response,
+                                                         UA_UInt32 timeout) {
+    //FD_ZERO(&handle->read_fds);
+    //FD_SET(handle->sockfd, &handle->read_fds);//tcp socket
     struct timeval tmptv = {0, timeout};
+    /*int ret = select(handle->sockfd+1, &handle->read_fds, NULL, NULL, &tmptv);
+    if(ret <= -1)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    if(ret == 0)
+        return UA_STATUSCODE_BADTIMEOUT;*/
+
     setsockopt(handle->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv,sizeof(struct timeval));
+
     int ret = recv(handle->sockfd, (char*)response->data, response->length, 0);
+
+    if(ret <= -1)
+        return UA_STATUSCODE_BADINTERNALERROR;
     if(ret == 0)
         return UA_STATUSCODE_BADSERVERNOTCONNECTED;
+
     response->length = ret;
     return UA_STATUSCODE_GOOD;
 }

+ 4 - 4
examples/networklayer_tcp.h

@@ -11,10 +11,10 @@ extern "C" {
 #endif
 
 #ifdef NOT_AMALGATED
-    #include "ua_server.h"
-	#include "ua_client.h"
+#include "ua_server.h"
+#include "ua_client.h"
 #else
-    #include "open62541.h"
+#include "open62541.h"
 #endif
 
 /** @brief Create the TCP networklayer and listen to the specified port */
@@ -25,4 +25,4 @@ UA_ClientNetworkLayer ClientNetworkLayerTCP_new(UA_ConnectionConfig conf);
 } // extern "C"
 #endif
 
-#endif /* NETWORKLAYERTCP_H_ */
+#endif /* NETWORKLAYERTCP_H_ */

+ 27 - 23
examples/networklayer_udp.c

@@ -3,33 +3,37 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
 
+#define _XOPEN_SOURCE 500 //some users need this for some reason
+#define __USE_BSD
 #include <stdlib.h> // malloc, free
-#ifdef _WIN32
-#include <malloc.h>
-#include <winsock2.h>
-#include <sys/types.h>
-#include <windows.h>
-#include <ws2tcpip.h>
-#define CLOSESOCKET(S) closesocket(S)
-#else
-#include <strings.h> //bzero
-#include <sys/select.h> 
-#include <netinet/in.h>
-#include <sys/socketvar.h>
-#include <sys/ioctl.h>
-#include <unistd.h> // read, write, close
-#include <arpa/inet.h>
-#define CLOSESOCKET(S) close(S)
-#endif
-
 #include <stdio.h>
-#include <errno.h> // errno, EINTR
-#include <fcntl.h> // fcntl
+#include <string.h> // memset
+#include "networklayer_udp.h"
+#ifdef UA_MULTITHREADING
+# include <urcu/uatomic.h>
+#endif
 
-#include "networklayer_udp.h" // UA_MULTITHREADING is defined in here
+/* with a space so amalgamation does not remove the includes */
+# include <errno.h> // errno, EINTR
+# include <fcntl.h> // fcntl
 
-#ifdef UA_MULTITHREADING
-#include <urcu/uatomic.h>
+#ifdef _WIN32
+# include <malloc.h>
+# include <winsock2.h>
+# include <sys/types.h>
+# include <windows.h>
+# include <ws2tcpip.h>
+# define CLOSESOCKET(S) closesocket(S)
+#else
+# include <strings.h> //bzero
+# include <sys/select.h> 
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <sys/socketvar.h>
+# include <sys/ioctl.h>
+# include <unistd.h> // read, write, close
+# include <arpa/inet.h>
+# define CLOSESOCKET(S) close(S)
 #endif
 
 #define MAXBACKLOG 100

+ 3 - 3
examples/networklayer_udp.h

@@ -11,9 +11,9 @@ extern "C" {
 #endif
 
 #ifdef NOT_AMALGATED
-    #include "ua_server.h"
+# include "ua_server.h"
 #else
-    #include "open62541.h"
+# include "open62541.h"
 #endif
 
 /** @brief Create the UDP networklayer and listen to the specified port */
@@ -23,4 +23,4 @@ UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UIn
 } // extern "C"
 #endif
 
-#endif /* NETWORKLAYERUDP_H_ */
+#endif /* NETWORKLAYERUDP_H_ */

+ 24 - 29
examples/server.c

@@ -2,25 +2,24 @@
  * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
-#ifdef NOT_AMALGATED
-    #include "ua_types.h"
-    #include "ua_server.h"
-#else
-    #include "open62541.h"
-#endif
 
-#include <time.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdlib.h> 
-#include <signal.h>
 #define __USE_XOPEN2K
 #ifdef UA_MULTITHREADING
-#include <pthread.h>
+# include <pthread.h>
 #endif
 
-// provided by the user, implementations available in the /examples folder
-#include "logger_stdout.h"
-#include "networklayer_tcp.h"
+#ifdef NOT_AMALGATED
+# include <time.h>
+# include "ua_types.h"
+# include "ua_server.h"
+# include "logger_stdout.h"
+# include "networklayer_tcp.h"
+#else
+# include "open62541.h"
+#endif
 
 /****************************/
 /* Server-related variables */
@@ -181,11 +180,10 @@ int main(int argc, char** argv) {
 		.read = readTimeData,
 		.release = releaseTimeData,
 		.write = NULL};
-	UA_QualifiedName dateName;
-	UA_QUALIFIEDNAME_ASSIGN(dateName, "current time");
+	const UA_QualifiedName dateName = UA_QUALIFIEDNAME(0, "current time");
 	UA_Server_addDataSourceVariableNode(server, dateDataSource, dateName, UA_NODEID_NULL,
-                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
 	if(!(temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))){
 		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Linux specific] Can not open temperature file, no temperature node will be added");
@@ -196,11 +194,10 @@ int main(int argc, char** argv) {
 			.read = readTemperature,
 			.release = releaseTemperature,
 			.write = NULL};
-		UA_QualifiedName ledName;
-		UA_QUALIFIEDNAME_ASSIGN(ledName, "cpu temperature");
+		const UA_QualifiedName ledName = UA_QUALIFIEDNAME(0, "cpu temperature");
 		UA_Server_addDataSourceVariableNode(server, temperatureDataSource, ledName, UA_NODEID_NULL, 
-                                            UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                            UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+                                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 	}
 
 	if (	!(triggerFile = fopen("/sys/class/leds/led0/trigger", "w"))
@@ -223,21 +220,19 @@ int main(int argc, char** argv) {
 		.read = readLedStatus,
 		.release = releaseLedStatus,
 		.write = writeLedStatus};
-	UA_QualifiedName statusName;
-	UA_QUALIFIEDNAME_ASSIGN(statusName, "status LED");
+	const UA_QualifiedName statusName = UA_QUALIFIEDNAME(0, "status LED");
 	UA_Server_addDataSourceVariableNode(server, ledStatusDataSource, statusName, UA_NODEID_NULL,
-                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
 	// 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]);
-    UA_QualifiedName myIntegerName;
-    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_STATIC(1, 442);
-    UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
-    UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
+    const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(0, "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, myIntegerVariant, myIntegerName,
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
 

+ 25 - 15
examples/server_simple.c

@@ -72,28 +72,38 @@ int main(int argc, char** argv) {
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    UA_QualifiedName myIntegerName;
-    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
-    UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
-    UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
+    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_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
     
 #ifdef BENCHMARK
-    UA_UInt32 nodeCount = 500;
-    char str[15];
+    UA_UInt32 nodeCount = 50;
+    char str[32];
     for(UA_UInt32 i = 0;i<nodeCount;i++) {
-        UA_Int32 *data = UA_Int32_new();
-        *data = 42;
+        /* scalar */
+        void *data = UA_new(&UA_TYPES[i]);
         UA_Variant *variant = UA_Variant_new();
-        UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT32]);
-        UA_QualifiedName *nodeName = UA_QualifiedName_new();
+        UA_Variant_setScalar(variant, data, &UA_TYPES[i]);
         sprintf(str,"%d",i);
-        UA_QualifiedName_copycstring(str, nodeName);
-        UA_Server_addVariableNode(server, variant, *nodeName, UA_NODEID_NULL,
-                                  UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                  UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+        UA_QualifiedName nodeName = UA_QUALIFIEDNAME(1, str);
+        UA_NodeId id = UA_NODEID_NUMERIC(1, 100 + i);
+        UA_Server_addVariableNode(server, variant, nodeName, id,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+
+        /* array */
+        data = UA_Array_new(&UA_TYPES[i], 10);
+        variant = UA_Variant_new();
+        UA_Variant_setArray(variant, data, 10, &UA_TYPES[i]);
+        sprintf(str,"array of %d",i);
+        nodeName = UA_QUALIFIEDNAME(1, str);
+        id = UA_NODEID_NUMERIC(1, 200 + i);
+        UA_Server_addVariableNode(server, variant, nodeName, id,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
     }
 #endif
 

+ 79 - 35
include/ua_types.h

@@ -321,8 +321,11 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_DiagnosticInfo)
 
 /* String */
 /** Copy a (zero terminated) char-array into a UA_String. Memory for the string data is
-    allocated. */
-UA_StatusCode UA_EXPORT UA_String_copycstring(char const *src, UA_String *dst);
+    allocated. If the memory cannot be allocated, a null-string is returned. */
+UA_String UA_EXPORT UA_String_fromChars(char const *src);
+#define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
+#define UA_STRING(CHARS) (const UA_String) {sizeof(CHARS)-1, (UA_Byte*)CHARS }
+#define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
 
 /** 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, ...);
@@ -330,11 +333,6 @@ UA_StatusCode UA_EXPORT UA_String_copyprintf(char const *fmt, UA_String *dst, ..
 /** Compares two strings */
 UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
 
-#define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
-#define UA_STRING_ASSIGN(VARIABLE, STRING) do { \
-        VARIABLE.length = sizeof(STRING)-1;     \
-        VARIABLE.data   = (UA_Byte *)STRING; } while(0)
-
 /* DateTime */
 /** Returns the current time */
 UA_DateTime UA_EXPORT UA_DateTime_now(void);
@@ -375,35 +373,57 @@ UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 /** Is the nodeid a null-nodeid? */
 UA_Boolean UA_EXPORT UA_NodeId_isNull(const UA_NodeId *p);
 
-#define UA_NODEID_ASSIGN(VARIABLE, NAMESPACE, NUMERICID) do {                 \
-        VARIABLE.namespaceIndex = NAMESPACE;                                  \
-        VARIABLE.identifierType = CPP_ONLY(UA_NodeId::)UA_NODEIDTYPE_NUMERIC; \
-        VARIABLE.identifier.numeric = NUMERICID; } while(0);
+#define UA_NODEID_NUMERIC(NS_INDEX, NUMERICID) (UA_NodeId) {           \
+        .namespaceIndex = NS_INDEX,                                    \
+        .identifierType = UA_NODEIDTYPE_NUMERIC,                       \
+        .identifier.numeric = NUMERICID }
+
+#define UA_NODEID_STRING(NS_INDEX, CHARS) (const UA_NodeId) {          \
+        .namespaceIndex = NS_INDEX,                                    \
+        .identifierType = UA_NODEIDTYPE_STRING,                        \
+        .identifier.string = UA_STRING(CHARS) }
+    
+#define UA_NODEID_STRING_ALLOC(NS_INDEX, CHARS) (const UA_NodeId) {    \
+        .namespaceIndex = NS_INDEX,                                    \
+        .identifierType = UA_NODEIDTYPE_STRING,                        \
+        .identifier.string = UA_STRING_ALLOC(CHARS) }
+
+#define UA_NODEID_GUID(NS_INDEX, GUID) (UA_NodeId) {                   \
+        .namespaceIndex = NS_INDEX,                                    \
+        .identifierType = UA_NODEIDTYPE_GUID,                          \
+        .identifier.guid = GUID }
 
-#define UA_NODEID_STATIC(NAMESPACE, NUMERICID) (UA_NodeId) {              \
-    .namespaceIndex = NAMESPACE, .identifierType = UA_NODEIDTYPE_NUMERIC, \
-    .identifier.numeric = NUMERICID }
+#define UA_NODEID_BYTESTRING(NS_INDEX, CHARS) (const UA_NodeId) {      \
+        .namespaceIndex = NS_INDEX,                                    \
+        .identifierType = UA_NODEIDTYPE_BYTESTRING,                    \
+        .identifier.byteString = UA_STRING(CHARS) }
 
-#define UA_NODEID_NULL UA_NODEID_STATIC(0,0)
+#define UA_NODEID_BYTESTRING_ALLOC(NS_INDEX, CHARS) (const UA_NodeId) {\
+        .namespaceIndex = NS_INDEX,                                    \
+        .identifierType = UA_NODEIDTYPE_BYTESTRING,                    \
+        .identifier.byteString = UA_STRING_ALLOC(CHARS) }
+
+#define UA_NODEID_NULL UA_NODEID_NUMERIC(0,0)
 
 /* ExpandedNodeId */
 UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
 
-#define UA_EXPANDEDNODEID_STATIC(NAMESPACE, NUMERICID) (UA_ExpandedNodeId) {             \
-        .nodeId = {.namespaceIndex = NAMESPACE, .identifierType = UA_NODEIDTYPE_NUMERIC, \
-                   .identifier.numeric = NUMERICID },                                    \
+#define UA_EXPANDEDNODEID_NUMERIC(NS_INDEX, NUMERICID) (UA_ExpandedNodeId) {            \
+        .nodeId = {.namespaceIndex = NS_INDEX, .identifierType = UA_NODEIDTYPE_NUMERIC, \
+                   .identifier.numeric = NUMERICID },                                   \
         .serverIndex = 0, .namespaceUri = {.data = (UA_Byte*)0, .length = -1} }
     
 /* QualifiedName */
-UA_StatusCode UA_EXPORT UA_QualifiedName_copycstring(char const *src, UA_QualifiedName *dst);
-#define UA_QUALIFIEDNAME_ASSIGN(VARIABLE, STRING) do {          \
-        VARIABLE.namespaceIndex = 0;                            \
-        UA_STRING_ASSIGN(VARIABLE.name, STRING); } while(0)
+#define UA_QUALIFIEDNAME(NS_INDEX, CHARS) (const UA_QualifiedName) {    \
+        .namespaceIndex = NS_INDEX, .name = UA_STRING(CHARS) }
+#define UA_QUALIFIEDNAME_ALLOC(NS_INDEX, CHARS) (UA_QualifiedName) {    \
+        .namespaceIndex = NS_INDEX, .name = UA_STRING_ALLOC(CHARS) }
 
 /* LocalizedText */
-/** Copy a (zero-terminated) char-array into the UA_LocalizedText. Memory for the string is
-    allocated. The locale is set to "en" by default. */
-UA_StatusCode UA_EXPORT UA_LocalizedText_copycstring(char const *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) }
 
 /* Variant */
 
@@ -415,12 +435,6 @@ UA_StatusCode UA_EXPORT UA_LocalizedText_copycstring(char const *src, UA_Localiz
  *                      data can be NULL if arrayLength == 0
  */
 
-/**
- * Copy the variant, but use only a subset of the (multidimensional) array. Returns an error code if
- * the variant is no array or if the indicated range does not fit.
- */
-UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, UA_NumericRange range);
-
 /**
  * Set the variant to a scalar value that already resides in memory. The value takes on the
  * lifecycle of the variant and is deleted with it.
@@ -452,8 +466,8 @@ UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, c
  * @param type The datatype of the array
  * @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 noElements, const UA_DataType *type);
+UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElements,
+                                            const UA_DataType *type);
 
 /**
  * Set the variant to an array that is copied from an existing array.
@@ -464,8 +478,38 @@ UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array,
  * @param type The datatype of the array
  * @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 noElements, const UA_DataType *type);
+UA_StatusCode UA_EXPORT UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32 noElements,
+                                                const UA_DataType *type);
+
+/**
+ * Copy the variant, but use only a subset of the (multidimensional) array. Returns an error code if
+ * the variant is no array or if the indicated range does not fit.
+ */
+UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, UA_NumericRange range);
+
+/**
+ * Insert a range of data into an existing variant of the dimensionality. This overwrites data in
+ * the variant. The inserted data is managed by the variant (members are deleted with it).
+ *
+ * @param v The variant
+ * @param data The data array. Obviously the type must match the variant and the length the range.
+ * @param range The range of where the new data is inserted
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *data, const UA_NumericRange range);
+
+/**
+ * Copies the variant and inserts data from the range. The inserted data is managed by the variant
+ * (members are deleted with it).
+ *
+ * @param src The source variant
+ * @param dst The target variant
+ * @param data The data array. Obviously the type must match the variant and the length the range.
+ * @param range The range of where the new data is inserted
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Variant_setCopyRange(const UA_Variant *src, UA_Variant *dst, void *data,
+                                                const UA_NumericRange range);
 
 /****************************/
 /* Structured Type Handling */

+ 8 - 8
src/client/ua_client.c

@@ -128,10 +128,10 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
 
 	UA_AsymmetricAlgorithmSecurityHeader asymHeader;
 	UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader);
-	UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &asymHeader.securityPolicyUri);
+	asymHeader.securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
 
     /* id of opensecurechannelrequest */
-	UA_NodeId requestType = UA_NODEID_STATIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
+	UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
 
 	UA_OpenSecureChannelRequest opnSecRq;
 	UA_OpenSecureChannelRequest_init(&opnSecRq);
@@ -194,7 +194,7 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
 	UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
 	UA_NodeId_decodeBinary(&reply, &offset, &requestType);
 
-	if(!UA_NodeId_equal(&requestType, &UA_NODEID_STATIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
+	if(!UA_NodeId_equal(&requestType, &UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
                                                         UA_ENCODINGOFFSET_BINARY))) {
         UA_ByteString_deleteMembers(&reply);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
@@ -243,7 +243,7 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     seqHeader.sequenceNumber = ++client->sequenceNumber;
     seqHeader.requestId = ++client->requestId;
 
-	UA_NodeId requestId = UA_NODEID_STATIC(0, requestType->typeId.identifier.numeric +
+	UA_NodeId requestId = UA_NODEID_NUMERIC(0, requestType->typeId.identifier.numeric +
                                            UA_ENCODINGOFFSET_BINARY);
 
 	msgHeader.messageHeader.messageSize =
@@ -301,7 +301,7 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     UA_NodeId responseId;
 	retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId);
 
-	if(!UA_NodeId_equal(&responseId, &UA_NODEID_STATIC(0, responseType->typeId.identifier.numeric +
+	if(!UA_NodeId_equal(&responseId, &UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
                                                        UA_ENCODINGOFFSET_BINARY))) {
         UA_ByteString_deleteMembers(&reply);
         UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
@@ -411,13 +411,13 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
 UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectionConfig conf,
                                 UA_ClientNetworkLayer networkLayer, char *endpointUrl)
 {
-    UA_StatusCode retval = UA_String_copycstring(endpointUrl, &client->endpointUrl);
-    if(retval != UA_STATUSCODE_GOOD)
+    client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
+    if(client->endpointUrl.length < 0)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
     client->networkLayer = networkLayer;
     client->connection.localConf = conf;
-    retval = networkLayer.connect(client->endpointUrl, client->networkLayer.nlHandle);
+    UA_StatusCode retval = networkLayer.connect(client->endpointUrl, client->networkLayer.nlHandle);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 

+ 20 - 12
src/server/ua_nodes.c

@@ -100,8 +100,8 @@ UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectType
 void UA_VariableNode_init(UA_VariableNode *p) {
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_VARIABLE;
-    p->variableType = UA_VARIABLENODETYPE_VARIANT;
-    UA_Variant_init(&p->variable.variant);
+    p->valueSource = UA_VALUESOURCE_VARIANT;
+    UA_Variant_init(&p->value.variant);
     p->valueRank = -2; // scalar or array of any dimension
     p->accessLevel = 0;
     p->userAccessLevel = 0;
@@ -118,8 +118,8 @@ UA_VariableNode * UA_VariableNode_new(void) {
 
 void UA_VariableNode_deleteMembers(UA_VariableNode *p) {
     UA_Node_deleteMembers((UA_Node*)p);
-    if(p->variableType == UA_VARIABLENODETYPE_VARIANT)
-        UA_Variant_deleteMembers(&p->variable.variant);
+    if(p->valueSource == UA_VALUESOURCE_VARIANT)
+        UA_Variant_deleteMembers(&p->value.variant);
 }
 
 void UA_VariableNode_delete(UA_VariableNode *p) {
@@ -130,11 +130,12 @@ void UA_VariableNode_delete(UA_VariableNode *p) {
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
     UA_VariableNode_init(dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    dst->variableType = src->variableType;
-    if(src->variableType == UA_VARIABLENODETYPE_VARIANT)
-        retval = UA_Variant_copy(&src->variable.variant, &dst->variable.variant);
+    dst->valueRank = src->valueRank;
+    dst->valueSource = src->valueSource;
+    if(src->valueSource == UA_VALUESOURCE_VARIANT)
+        retval = UA_Variant_copy(&src->value.variant, &dst->value.variant);
     else
-        dst->variable.dataSource = src->variable.dataSource;
+        dst->value.dataSource = src->value.dataSource;
     if(retval) {
         UA_VariableNode_deleteMembers(dst);
         return retval;
@@ -150,8 +151,9 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
 void UA_VariableTypeNode_init(UA_VariableTypeNode *p) {
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_VARIABLETYPE;
-    UA_Variant_init(&p->value);
-    p->valueRank = 0;
+    p->valueSource = UA_VALUESOURCE_VARIANT;
+    UA_Variant_init(&p->value.variant);
+    p->valueRank = -2; // scalar or array of any dimension
     p->isAbstract = UA_FALSE;
 }
 
@@ -164,7 +166,8 @@ UA_VariableTypeNode * UA_VariableTypeNode_new(void) {
 
 void UA_VariableTypeNode_deleteMembers(UA_VariableTypeNode *p) {
     UA_Node_deleteMembers((UA_Node*)p);
-    UA_Variant_deleteMembers(&p->value);
+    if(p->valueSource == UA_VALUESOURCE_VARIANT)
+        UA_Variant_deleteMembers(&p->value.variant);
 }
 
 void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
@@ -175,7 +178,12 @@ void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
 UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) {
     UA_VariableTypeNode_init(dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    retval |= UA_Variant_copy(&src->value, &dst->value);
+    dst->valueRank = src->valueRank;
+    dst->valueSource = src->valueSource;
+    if(src->valueSource == UA_VALUESOURCE_VARIANT)
+        UA_Variant_copy(&src->value.variant, &dst->value.variant);
+    else
+        dst->value.dataSource = src->value.dataSource;
     if(retval) {
         UA_VariableTypeNode_deleteMembers(dst);
         return retval;

+ 15 - 7
src/server/ua_nodes.h

@@ -32,6 +32,11 @@ typedef struct {
 } UA_ObjectTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 
+typedef enum {
+    UA_VALUESOURCE_VARIANT,
+    UA_VALUESOURCE_DATASOURCE
+} UA_ValueSource;
+
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
@@ -39,14 +44,12 @@ typedef struct {
                              n = -1: the value is a scalar.
                              n = -2: the value can be a scalar or an array with any number of dimensions.
                              n = -3:  the value can be a scalar or a one dimensional array. */
-    enum {
-        UA_VARIABLENODETYPE_VARIANT,
-        UA_VARIABLENODETYPE_DATASOURCE
-    } variableType;
+    UA_ValueSource valueSource;
     union {
         UA_Variant variant;
         UA_DataSource dataSource;
-    } variable;
+    } value;
+    /* <--- similar to variabletypenodes up to there--->*/
     UA_Byte accessLevel;
     UA_Byte userAccessLevel;
     UA_Double minimumSamplingInterval;
@@ -58,9 +61,14 @@ UA_StatusCode UA_VariableNode_copyWithoutRefsAndVariable(const UA_VariableNode *
 
 typedef struct {
     UA_STANDARD_NODEMEMBERS
-    UA_Boolean isAbstract;
     UA_Int32 valueRank;
-    UA_Variant value;
+    UA_ValueSource valueSource;
+    union {
+        UA_Variant variant;
+        UA_DataSource dataSource;
+    } value;
+    /* <--- similar to variablenodes up to there--->*/
+    UA_Boolean isAbstract;
 } UA_VariableTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)
 

+ 2 - 2
src/server/ua_securechannel_manager.c

@@ -75,8 +75,8 @@ UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager           *cm
         cm->maxChannelLifetime : request->requestedLifetime;
 
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
-    UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None",
-                          (UA_String *)&entry->channel.serverAsymAlgSettings.securityPolicyUri);
+    entry->channel.serverAsymAlgSettings.securityPolicyUri =
+        UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
     LIST_INSERT_HEAD(&cm->channels, entry, pointers);
 
     response->serverProtocolVersion = 0;

+ 179 - 186
src/server/ua_server.c

@@ -37,14 +37,18 @@ void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkL
     server->nlsSize++;
 
     if(networkLayer.discoveryUrl){
-		UA_String* newUrls = UA_realloc(server->description.discoveryUrls, sizeof(UA_String)*(server->description.discoveryUrlsSize+1)); //TODO: rework this pattern into *_array_insert
+        if(server->description.discoveryUrlsSize < 0)
+            server->description.discoveryUrlsSize = 0;
+		UA_String* newUrls = UA_realloc(server->description.discoveryUrls,
+                                        sizeof(UA_String)*(server->description.discoveryUrlsSize));
 		if(!newUrls) {
 			UA_LOG_ERROR(server->logger, UA_LOGGERCATEGORY_SERVER, "Adding discoveryUrl");
 			return;
 		}
 		server->description.discoveryUrls = newUrls;
-		UA_String_copy(networkLayer.discoveryUrl, &server->description.discoveryUrls[0]);
-		server->description.discoveryUrlsSize++;
+		UA_String_copy(networkLayer.discoveryUrl,
+                       &server->description.discoveryUrls[server->description.discoveryUrlsSize]);
+        server->description.discoveryUrlsSize++;
     }
 }
 
@@ -94,13 +98,13 @@ static UA_StatusCode readStatus(const void *handle, UA_Boolean sourceTimeStamp,
     status->startTime   = ((const UA_Server*)handle)->startTime;
     status->currentTime = UA_DateTime_now();
     status->state       = UA_SERVERSTATE_RUNNING;
-    UA_String_copycstring("http://www.open62541.org", &status->buildInfo.productUri);
-    UA_String_copycstring("open62541", &status->buildInfo.manufacturerName);
-    UA_String_copycstring("open62541 OPC UA Server", &status->buildInfo.productName);
+    status->buildInfo.productUri = UA_STRING_ALLOC("http://www.open62541.org");
+    status->buildInfo.manufacturerName = UA_STRING_ALLOC("open62541");
+    status->buildInfo.productName = UA_STRING_ALLOC("open62541 OPC UA Server");
 #define STRINGIFY(x) #x //some magic
 #define TOSTRING(x) STRINGIFY(x) //some magic
-    UA_String_copycstring(TOSTRING(OPEN62541_VERSION_MAJOR) "." TOSTRING(OPEN62541_VERSION_MINOR) "." TOSTRING(OPEN62541_VERSION_PATCH), &status->buildInfo.softwareVersion);
-    UA_String_copycstring("0", &status->buildInfo.buildNumber);
+    status->buildInfo.softwareVersion = UA_STRING_ALLOC(TOSTRING(OPEN62541_VERSION_MAJOR) "." TOSTRING(OPEN62541_VERSION_MINOR) "." TOSTRING(OPEN62541_VERSION_PATCH));
+    status->buildInfo.buildNumber = UA_STRING_ALLOC("0");
     status->buildInfo.buildDate = ((const UA_Server*)handle)->buildDate;
     status->secondsTillShutdown = 0;
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
@@ -143,9 +147,9 @@ static void releaseCurrentTime(const void *handle, UA_DataValue *value) {
 }
 
 static void copyNames(UA_Node *node, char *name) {
-    UA_QualifiedName_copycstring(name, &node->browseName);
-    UA_LocalizedText_copycstring(name, &node->displayName);
-    UA_LocalizedText_copycstring(name, &node->description);
+    node->browseName = UA_QUALIFIEDNAME_ALLOC(0, name);
+    node->displayName = UA_LOCALIZEDTEXT_ALLOC("", name);
+    node->description = UA_LOCALIZEDTEXT_ALLOC("", name);
 }
 
 static void addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid, UA_Int32 parent) {
@@ -153,8 +157,8 @@ static void addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid,
     copyNames((UA_Node*)datatype, name);
     datatype->nodeId.identifier.numeric = datatypeid;
     UA_Server_addNode(server, (UA_Node*)datatype,
-                      &UA_EXPANDEDNODEID_STATIC(0, parent),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 }
 
 static UA_VariableTypeNode* createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid, UA_Int32 parent, UA_Boolean abstract) {
@@ -162,8 +166,7 @@ static UA_VariableTypeNode* createVariableTypeNode(UA_Server *server, char* name
     copyNames((UA_Node*)variabletype, name);
     variabletype->nodeId.identifier.numeric = variabletypeid;
     variabletype->isAbstract = abstract;
-    variabletype->value.type = &UA_TYPES[UA_TYPES_VARIANT];
-
+    variabletype->value.variant.type = &UA_TYPES[UA_TYPES_VARIANT];
     return variabletype;
 }
 
@@ -171,16 +174,16 @@ static void addVariableTypeNode_organized(UA_Server *server, char* name, UA_UInt
 	UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
 
     UA_Server_addNode(server, (UA_Node*)variabletype,
-                      &UA_EXPANDEDNODEID_STATIC(0, parent),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 }
 
 static void addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletypeid, UA_Int32 parent, UA_Boolean abstract) {
 	UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
 
     UA_Server_addNode(server, (UA_Node*)variabletype,
-                      &UA_EXPANDEDNODEID_STATIC(0, parent),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 }
 
 UA_Server * UA_Server_new(void) {
@@ -211,11 +214,11 @@ UA_Server * UA_Server_new(void) {
 #define APPLICATION_URI "urn:unconfigured:open62541:open62541Server"
     // mockup application description
     UA_ApplicationDescription_init(&server->description);
-    UA_String_copycstring(PRODUCT_URI, &server->description.productUri);
-    UA_String_copycstring(APPLICATION_URI, &server->description.applicationUri);
+    server->description.productUri = UA_STRING_ALLOC(PRODUCT_URI);
+    server->description.applicationUri = UA_STRING_ALLOC(APPLICATION_URI);
     server->description.discoveryUrlsSize = 0;
 
-    UA_LocalizedText_copycstring("Unconfigured open62541 application", &server->description.applicationName);
+    server->description.applicationName = UA_LOCALIZEDTEXT_ALLOC("", "Unconfigured open62541 application");
     server->description.applicationType = UA_APPLICATIONTYPE_SERVER;
     server->externalNamespacesSize = 0;
     server->externalNamespaces = UA_NULL;
@@ -223,15 +226,15 @@ UA_Server * UA_Server_new(void) {
     UA_EndpointDescription *endpoint = UA_EndpointDescription_new(); // todo: check return code
     if(endpoint) {
         endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
-        UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &endpoint->securityPolicyUri);
-        UA_String_copycstring("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary", &endpoint->transportProfileUri);
+        endpoint->securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
+        endpoint->transportProfileUri = UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
         endpoint->userIdentityTokens = UA_malloc(sizeof(UA_UserTokenPolicy));
         if(!endpoint->userIdentityTokens) {
             UA_EndpointDescription_delete(endpoint);
         } else {
             UA_UserTokenPolicy_init(endpoint->userIdentityTokens);
             endpoint->userIdentityTokens->tokenType = UA_USERTOKENTYPE_ANONYMOUS;
-            UA_String_copycstring("my-anonymous-policy", &endpoint->userIdentityTokens->policyId); // defined per server
+            endpoint->userIdentityTokens->policyId = UA_STRING_ALLOC("my-anonymous-policy"); // defined per server
 
             /* UA_String_copy(endpointUrl, &endpoint->endpointUrl); */
             /* /\* The standard says "the HostName specified in the Server Certificate is the */
@@ -275,7 +278,7 @@ UA_Server * UA_Server_new(void) {
 
     UA_ReferenceTypeNode *hassubtype = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hassubtype, "HasSubtype");
-    UA_LocalizedText_copycstring("HasSupertype", &hassubtype->inverseName);
+    hassubtype->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "HasSupertype");
     hassubtype->nodeId.identifier.numeric = UA_NS0ID_HASSUBTYPE;
     hassubtype->isAbstract = UA_FALSE;
     hassubtype->symmetric  = UA_FALSE;
@@ -288,8 +291,8 @@ UA_Server * UA_Server_new(void) {
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hierarchicalreferences,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_REFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)nonhierarchicalreferences, "NonHierarchicalReferences");
@@ -297,8 +300,8 @@ UA_Server * UA_Server_new(void) {
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)nonhierarchicalreferences,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_REFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haschild, "HasChild");
@@ -306,78 +309,78 @@ UA_Server * UA_Server_new(void) {
     haschild->isAbstract = UA_TRUE;
     haschild->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)haschild,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)organizes, "Organizes");
-    UA_LocalizedText_copycstring("OrganizedBy", &organizes->inverseName);
+    organizes->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "OrganizedBy");
     organizes->nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     organizes->isAbstract = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)organizes,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haseventsource, "HasEventSource");
-    UA_LocalizedText_copycstring("EventSourceOf", &haseventsource->inverseName);
+    haseventsource->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "EventSourceOf");
     haseventsource->nodeId.identifier.numeric = UA_NS0ID_HASEVENTSOURCE;
     haseventsource->isAbstract = UA_FALSE;
     haseventsource->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)haseventsource,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasmodellingrule, "HasModellingRule");
-    UA_LocalizedText_copycstring("ModellingRuleOf", &hasmodellingrule->inverseName);
+    hasmodellingrule->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "ModellingRuleOf");
     hasmodellingrule->nodeId.identifier.numeric = UA_NS0ID_HASMODELLINGRULE;
     hasmodellingrule->isAbstract = UA_FALSE;
     hasmodellingrule->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasmodellingrule,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasencoding, "HasEncoding");
-    UA_LocalizedText_copycstring("EncodingOf", &hasencoding->inverseName);
+    hasencoding->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "EncodingOf");
     hasencoding->nodeId.identifier.numeric = UA_NS0ID_HASENCODING;
     hasencoding->isAbstract = UA_FALSE;
     hasencoding->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasencoding,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasdescription, "HasDescription");
-    UA_LocalizedText_copycstring("DescriptionOf", &hasdescription->inverseName);
+    hasdescription->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "DescriptionOf");
     hasdescription->nodeId.identifier.numeric = UA_NS0ID_HASDESCRIPTION;
     hasdescription->isAbstract = UA_FALSE;
     hasdescription->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasdescription,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hastypedefinition, "HasTypeDefinition");
-    UA_LocalizedText_copycstring("TypeDefinitionOf", &hastypedefinition->inverseName);
+    hastypedefinition->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "TypeDefinitionOf");
     hastypedefinition->nodeId.identifier.numeric = UA_NS0ID_HASTYPEDEFINITION;
     hastypedefinition->isAbstract = UA_FALSE;
     hastypedefinition->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hastypedefinition,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)generatesevent, "GeneratesEvent");
-    UA_LocalizedText_copycstring("GeneratedBy", &generatesevent->inverseName);
+    generatesevent->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "GeneratedBy");
     generatesevent->nodeId.identifier.numeric = UA_NS0ID_GENERATESEVENT;
     generatesevent->isAbstract = UA_FALSE;
     generatesevent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)generatesevent,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)aggregates, "Aggregates");
@@ -386,112 +389,112 @@ UA_Server * UA_Server_new(void) {
     aggregates->isAbstract = UA_TRUE;
     aggregates->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)aggregates,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASCHILD),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCHILD),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     // complete bootstrap of hassubtype
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_HASCHILD), UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE),
-                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasproperty, "HasProperty");
-    UA_LocalizedText_copycstring("PropertyOf", &hasproperty->inverseName);
+    hasproperty->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "PropertyOf");
     hasproperty->nodeId.identifier.numeric = UA_NS0ID_HASPROPERTY;
     hasproperty->isAbstract = UA_FALSE;
     hasproperty->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasproperty,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_AGGREGATES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hascomponent, "HasComponent");
-    UA_LocalizedText_copycstring("ComponentOf", &hascomponent->inverseName);
+    hascomponent->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "ComponentOf");
     hascomponent->nodeId.identifier.numeric = UA_NS0ID_HASCOMPONENT;
     hascomponent->isAbstract = UA_FALSE;
     hascomponent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hascomponent,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_AGGREGATES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasnotifier, "HasNotifier");
-    UA_LocalizedText_copycstring("NotifierOf", &hasnotifier->inverseName);
+    hasnotifier->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "NotifierOf");
     hasnotifier->nodeId.identifier.numeric = UA_NS0ID_HASNOTIFIER;
     hasnotifier->isAbstract = UA_FALSE;
     hasnotifier->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasnotifier,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASEVENTSOURCE),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasorderedcomponent, "HasOrderedComponent");
-    UA_LocalizedText_copycstring("OrderedComponentOf", &hasorderedcomponent->inverseName);
+    hasorderedcomponent->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "OrderedComponentOf");
     hasorderedcomponent->nodeId.identifier.numeric = UA_NS0ID_HASORDEREDCOMPONENT;
     hasorderedcomponent->isAbstract = UA_FALSE;
     hasorderedcomponent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasorderedcomponent,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasmodelparent, "HasModelParent");
-    UA_LocalizedText_copycstring("ModelParentOf", &hasmodelparent->inverseName);
+    hasmodelparent->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "ModelParentOf");
     hasmodelparent->nodeId.identifier.numeric = UA_NS0ID_HASMODELPARENT;
     hasmodelparent->isAbstract = UA_FALSE;
     hasmodelparent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasmodelparent,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)fromstate, "FromState");
-    UA_LocalizedText_copycstring("ToTransition", &fromstate->inverseName);
+    fromstate->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "ToTransition");
     fromstate->nodeId.identifier.numeric = UA_NS0ID_FROMSTATE;
     fromstate->isAbstract = UA_FALSE;
     fromstate->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)fromstate,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)tostate, "ToState");
-    UA_LocalizedText_copycstring("FromTransition", &tostate->inverseName);
+    tostate->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "FromTransition");
     tostate->nodeId.identifier.numeric = UA_NS0ID_TOSTATE;
     tostate->isAbstract = UA_FALSE;
     tostate->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)tostate,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hascause, "HasCause");
-    UA_LocalizedText_copycstring("MayBeCausedBy", &hascause->inverseName);
+    hascause->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "MayBeCausedBy");
     hascause->nodeId.identifier.numeric = UA_NS0ID_HASCAUSE;
     hascause->isAbstract = UA_FALSE;
     hascause->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hascause,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
     
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haseffect, "HasEffect");
-    UA_LocalizedText_copycstring("MayBeEffectedBy", &haseffect->inverseName);
+    haseffect->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "MayBeEffectedBy");
     haseffect->nodeId.identifier.numeric = UA_NS0ID_HASEFFECT;
     haseffect->isAbstract = UA_FALSE;
     haseffect->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)haseffect,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hashistoricalconfiguration, "HasHistoricalConfiguration");
-    UA_LocalizedText_copycstring("HistoricalConfigurationOf", &hashistoricalconfiguration->inverseName);
+    hashistoricalconfiguration->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "HistoricalConfigurationOf");
     hashistoricalconfiguration->nodeId.identifier.numeric = UA_NS0ID_HASHISTORICALCONFIGURATION;
     hashistoricalconfiguration->isAbstract = UA_FALSE;
     hashistoricalconfiguration->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hashistoricalconfiguration,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_AGGREGATES),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     /**********************/
     /* Basic Object Types */
@@ -511,8 +514,8 @@ UA_Server * UA_Server_new(void) {
     folderType->nodeId.identifier.numeric = UA_NS0ID_FOLDERTYPE;
     copyNames((UA_Node*)folderType, "FolderType");
     UA_NodeStore_insert(server->nodestore, (UA_Node*)folderType, UA_NULL);
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE),
- 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+ 		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
     /*****************/
     /* Basic Folders */
@@ -522,35 +525,35 @@ UA_Server * UA_Server_new(void) {
     copyNames((UA_Node*)root, "Root");
     root->nodeId.identifier.numeric = UA_NS0ID_ROOTFOLDER;
     UA_NodeStore_insert(server->nodestore, (UA_Node*)root, UA_NULL);
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_ROOTFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
- 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+ 		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *objects = UA_ObjectNode_new();
     copyNames((UA_Node*)objects, "Objects");
     objects->nodeId.identifier.numeric = UA_NS0ID_OBJECTSFOLDER;
     UA_Server_addNode(server, (UA_Node*)objects,
- 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
- 		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
- 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+ 		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+ 		   &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+ 		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *types = UA_ObjectNode_new();
     copyNames((UA_Node*)types, "Types");
     types->nodeId.identifier.numeric = UA_NS0ID_TYPESFOLDER;
     UA_Server_addNode(server, (UA_Node*)types,
- 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
- 		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_TYPESFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
- 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+ 		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+ 		   &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+ 		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *views = UA_ObjectNode_new();
     copyNames((UA_Node*)views, "Views");
     views->nodeId.identifier.numeric = UA_NS0ID_VIEWSFOLDER;
     UA_Server_addNode(server, (UA_Node*)views,
- 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
- 		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+ 		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+ 		   &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
     /**********************/
     /* Further Data Types */
@@ -560,10 +563,10 @@ UA_Server * UA_Server_new(void) {
     copyNames((UA_Node*)datatypes, "DataTypes");
     datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
     UA_Server_addNode(server, (UA_Node*)datatypes,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_TYPESFOLDER),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_DATATYPESFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_DATATYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
     addDataTypeNode(server, "BaseDataType", UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER);
     addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, UA_NS0ID_BASEDATATYPE);
@@ -600,10 +603,10 @@ UA_Server * UA_Server_new(void) {
    copyNames((UA_Node*)variabletypes, "VariableTypes");
    variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
    UA_Server_addNode(server, (UA_Node*)variabletypes,
-                     &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_TYPESFOLDER),
-                     &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_VARIABLETYPESFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+                     &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                     &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
    addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE, UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
    addVariableTypeNode_subtype(server, "PropertyType", UA_NS0ID_PROPERTYTYPE, UA_NS0ID_BASEVARIABLETYPE, UA_FALSE);
 
@@ -615,107 +618,97 @@ UA_Server * UA_Server_new(void) {
    copyNames((UA_Node*)servernode, "Server");
    servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
    UA_Server_addNode(server, (UA_Node*)servernode,
-		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
    UA_VariableNode *namespaceArray = UA_VariableNode_new();
    copyNames((UA_Node*)namespaceArray, "NamespaceArray");
    namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
-   namespaceArray->variableType = UA_VARIABLENODETYPE_VARIANT;
-   namespaceArray->variable.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
-   namespaceArray->variable.variant.arrayLength = 2;
-   namespaceArray->variable.variant.type = &UA_TYPES[UA_TYPES_STRING];
+   namespaceArray->value.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
+   namespaceArray->value.variant.arrayLength = 2;
+   namespaceArray->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
    // Fixme: Insert the external namespaces
-   UA_String_copycstring("http://opcfoundation.org/UA/",
-		   &((UA_String *)(namespaceArray->variable.variant.data))[0]);
-   UA_String_copycstring(APPLICATION_URI,
-		   &((UA_String *)(namespaceArray->variable.variant.data))[1]);
+   ((UA_String *)namespaceArray->value.variant.data)[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
+   ((UA_String *)namespaceArray->value.variant.data)[1] = UA_STRING_ALLOC(APPLICATION_URI);
    namespaceArray->valueRank = 1;
    namespaceArray->minimumSamplingInterval = 1.0;
    namespaceArray->historizing = UA_FALSE;
    UA_Server_addNode(server, (UA_Node*)namespaceArray,
-		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
-   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
-                UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_PROPERTYTYPE));
+		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
+                UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
    UA_VariableNode *serverArray = UA_VariableNode_new();
    copyNames((UA_Node*)serverArray, "ServerArray");
    serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
-   serverArray->variableType = UA_VARIABLENODETYPE_VARIANT;
-   serverArray->variable.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
-   serverArray->variable.variant.arrayLength = 1;
-   serverArray->variable.variant.type = &UA_TYPES[UA_TYPES_STRING];
-   UA_String_copycstring(APPLICATION_URI,
- 		   &((UA_String *)(serverArray->variable.variant.data))[0]);
+   serverArray->value.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+   serverArray->value.variant.arrayLength = 1;
+   serverArray->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+   *(UA_String *)serverArray->value.variant.data = UA_STRING_ALLOC(APPLICATION_URI);
    serverArray->valueRank = 1;
    serverArray->minimumSamplingInterval = 1.0;
    serverArray->historizing = UA_FALSE;
    UA_Server_addNode(server, (UA_Node*)serverArray,
- 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
- 		   &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
-   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERARRAY),
-                UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_PROPERTYTYPE));
+ 		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+ 		   &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY),
+                UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
    UA_ObjectNode *servercapablities = UA_ObjectNode_new();
    copyNames((UA_Node*)servercapablities, "ServerCapabilities");
    servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
    UA_Server_addNode(server, (UA_Node*)servercapablities,
-		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
 
    UA_VariableNode *localeIdArray = UA_VariableNode_new();
    copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
    localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
-   localeIdArray->variableType = UA_VARIABLENODETYPE_VARIANT;
-   localeIdArray->variable.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
-   localeIdArray->variable.variant.arrayLength = 2;
-   localeIdArray->variable.variant.type = &UA_TYPES[UA_TYPES_STRING];
-   UA_String_copycstring("en",
-		   &((UA_String *)(localeIdArray->variable.variant.data))[0]);
-   UA_String_copycstring("de",
-		   &((UA_String *)(localeIdArray->variable.variant.data))[1]);
+   localeIdArray->value.variant.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
+   localeIdArray->value.variant.arrayLength = 2;
+   localeIdArray->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+   *(UA_String *)localeIdArray->value.variant.data = UA_STRING_ALLOC("en");
    localeIdArray->valueRank = 1;
    localeIdArray->minimumSamplingInterval = 1.0;
    localeIdArray->historizing = UA_FALSE;
    UA_Server_addNode(server, (UA_Node*)localeIdArray,
-		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
-   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_PROPERTYTYPE));
+		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
    UA_VariableNode *serverstatus = UA_VariableNode_new();
    copyNames((UA_Node*)serverstatus, "ServerStatus");
-   serverstatus->nodeId = UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
-   serverstatus->variableType = UA_VARIABLENODETYPE_DATASOURCE;
-   serverstatus->variable.dataSource = (UA_DataSource) {.handle = server, .read = readStatus,
+   serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
+   serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
+   serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus,
 	   .release = releaseStatus, .write = UA_NULL};
-   UA_Server_addNode(server, (UA_Node*)serverstatus, &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+   UA_Server_addNode(server, (UA_Node*)serverstatus, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
 
    UA_VariableNode *state = UA_VariableNode_new();
    UA_ServerState *stateEnum = UA_ServerState_new();
    *stateEnum = UA_SERVERSTATE_RUNNING;
    copyNames((UA_Node*)state, "State");
    state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
-   state->variableType = UA_VARIABLENODETYPE_VARIANT;
-   state->variable.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
-   state->variable.variant.arrayLength = -1;
-   state->variable.variant.data = stateEnum; // points into the other object.
+   state->value.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
+   state->value.variant.arrayLength = -1;
+   state->value.variant.data = stateEnum; // points into the other object.
    UA_NodeStore_insert(server->nodestore, (UA_Node*)state, UA_NULL);
-   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
-		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
+   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
 
    UA_VariableNode *currenttime = UA_VariableNode_new();
    copyNames((UA_Node*)currenttime, "CurrentTime");
-   currenttime->nodeId = UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
-   currenttime->variableType = UA_VARIABLENODETYPE_DATASOURCE;
-   currenttime->variable.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
+   currenttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+   currenttime->valueSource = UA_VALUESOURCE_DATASOURCE;
+   currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
 	   .release = releaseCurrentTime, .write = UA_NULL};
-   UA_Server_addNode(server, (UA_Node*)currenttime, &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+   UA_Server_addNode(server, (UA_Node*)currenttime, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
 
 #ifdef DEMO_NODESET
    /**************/
@@ -725,32 +718,32 @@ UA_Server * UA_Server_new(void) {
 #define DEMOID 990
    UA_ObjectNode *demo = UA_ObjectNode_new();
    copyNames((UA_Node*)demo, "Demo");
-   demo->nodeId = UA_NODEID_STATIC(1, DEMOID);
+   demo->nodeId = UA_NODEID_NUMERIC(1, DEMOID);
    UA_Server_addNode(server, (UA_Node*)demo,
-		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-   ADDREFERENCE(UA_NODEID_STATIC(1, DEMOID), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+		   &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
 #define SCALARID 991
    UA_ObjectNode *scalar = UA_ObjectNode_new();
    copyNames((UA_Node*)scalar, "Scalar");
-   scalar->nodeId = UA_NODEID_STATIC(1, SCALARID);
+   scalar->nodeId = UA_NODEID_NUMERIC(1, SCALARID);
    UA_Server_addNode(server, (UA_Node*)scalar,
-		   &UA_EXPANDEDNODEID_STATIC(1, DEMOID),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-   ADDREFERENCE(UA_NODEID_STATIC(1, SCALARID), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+		   &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
 #define ARRAYID 992
    UA_ObjectNode *array = UA_ObjectNode_new();
    copyNames((UA_Node*)array, "Arrays");
-   array->nodeId = UA_NODEID_STATIC(1, ARRAYID);
+   array->nodeId = UA_NODEID_NUMERIC(1, ARRAYID);
    UA_Server_addNode(server, (UA_Node*)array,
-		   &UA_EXPANDEDNODEID_STATIC(1, DEMOID),
-		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-   ADDREFERENCE(UA_NODEID_STATIC(1, ARRAYID), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+		   &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID),
+		   &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
    UA_UInt32 id = 1000; //running id in namespace 1
    for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
@@ -764,14 +757,14 @@ UA_Server * UA_Server_new(void) {
 	    char name[15];
 	    sprintf(name, "%02d", type);
 	    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, name);
-	    UA_Server_addVariableNode(server, variant, myIntegerName, UA_NODEID_STATIC(1, ++id),
-	                              UA_NODEID_STATIC(1, SCALARID), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+	    UA_Server_addVariableNode(server, variant, myIntegerName, UA_NODEID_NUMERIC(1, ++id),
+	                              UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
         //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, arrayvar, myIntegerName, UA_NODEID_STATIC(1, ++id),
-                                  UA_NODEID_STATIC(1, ARRAYID), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+        UA_Server_addVariableNode(server, arrayvar, myIntegerName, UA_NODEID_NUMERIC(1, ++id),
+                                  UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
    }
 #endif
 

+ 10 - 8
src/server/ua_server_addressspace.c

@@ -6,7 +6,7 @@ UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_Qualifi
                           UA_NodeId nodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId)
 {
     UA_VariableNode *node = UA_VariableNode_new();
-    node->variable.variant = *value; // copy content
+    node->value.variant = *value; // copy content
     UA_NodeId_copy(&nodeId, &node->nodeId);
     UA_QualifiedName_copy(&browseName, &node->browseName);
     UA_String_copy(&browseName.name, &node->displayName.text);
@@ -15,13 +15,14 @@ UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_Qualifi
     UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
     UA_AddNodesResult res =
         UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
-    ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                 UA_EXPANDEDNODEID_STATIC(0, value->type->typeId.identifier.numeric));
+    ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
     if(res.statusCode != UA_STATUSCODE_GOOD) {
-        UA_Variant_init(&node->variable.variant);
+        UA_Variant_init(&node->value.variant);
         UA_VariableNode_delete(node);
     } else
         UA_free(value);
+    UA_AddNodesResult_deleteMembers(&res);
     return res.statusCode;
 }
 
@@ -31,8 +32,8 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
                                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId)
 {
     UA_VariableNode *node = UA_VariableNode_new();
-    node->variableType = UA_VARIABLENODETYPE_DATASOURCE;
-    node->variable.dataSource = dataSource;
+    node->valueSource = UA_VALUESOURCE_DATASOURCE;
+    node->value.dataSource = dataSource;
     UA_NodeId_copy(&nodeId, &node->nodeId);
     UA_QualifiedName_copy(&browseName, &node->browseName);
     UA_String_copy(&browseName.name, &node->displayName.text);
@@ -41,10 +42,11 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
     UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
     UA_AddNodesResult res =
         UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
-    ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+    ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
     if(res.statusCode != UA_STATUSCODE_GOOD)
         UA_VariableNode_delete(node);
+    UA_AddNodesResult_deleteMembers(&res);
     return res.statusCode;
 }
 

+ 2 - 2
src/server/ua_server_binary.c

@@ -100,8 +100,8 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     respHeader.messageHeader.messageSize = 0;
     respHeader.secureChannelId = p.securityToken.channelId;
 
-    UA_NodeId responseType = UA_NODEID_STATIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE);
-    responseType.identifier.numeric += UA_ENCODINGOFFSET_BINARY;
+    UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
+                                               UA_ENCODINGOFFSET_BINARY);
 
     respHeader.messageHeader.messageSize =
         UA_SecureConversationMessageHeader_calcSizeBinary(&respHeader)

+ 114 - 132
src/server/ua_services_attribute.c

@@ -195,19 +195,18 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
             UA_Boolean hasRange = UA_FALSE;
             UA_NumericRange range;
             if(id->indexRange.length > 0) {
-                hasRange = UA_TRUE;
                 retval = parse_numericrange(id->indexRange, &range);
                 if(retval != UA_STATUSCODE_GOOD)
                     break;
+                hasRange = UA_TRUE;
             }
 
             const UA_VariableNode *vn = (const UA_VariableNode*)node;
-
-            if(vn->variableType == UA_VARIABLENODETYPE_VARIANT) {
+            if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
                 if(hasRange)
-                    retval |= UA_Variant_copyRange(&vn->variable.variant, &v->value, range);
+                    retval |= UA_Variant_copyRange(&vn->value.variant, &v->value, range);
                 else
-                    retval |= UA_Variant_copy(&vn->variable.variant, &v->value);
+                    retval |= UA_Variant_copy(&vn->value.variant, &v->value);
                 if(retval == UA_STATUSCODE_GOOD) {
                     v->hasValue = UA_TRUE;
                     handleSourceTimestamps(timestamps, v);
@@ -217,11 +216,11 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
                 UA_DataValue_init(&val);
                 UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
                                               timestamps == UA_TIMESTAMPSTORETURN_BOTH);
-                retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, sourceTimeStamp, &val);
+                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, sourceTimeStamp, &val);
                 if(retval == UA_STATUSCODE_GOOD) {
                     retval |= UA_DataValue_copy(&val, v); // todo: selection of indexranges
                 }
-                vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+                vn->value.dataSource.release(vn->value.dataSource.handle, &val);
             }
 
             if(hasRange)
@@ -229,31 +228,24 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
         }
         break;
 
-    case UA_ATTRIBUTEID_DATATYPE:
+    case UA_ATTRIBUTEID_DATATYPE: {
 		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-		v->hasValue = UA_TRUE;
-		if(node->nodeClass == UA_NODECLASS_VARIABLETYPE){
-			retval |= UA_Variant_setScalarCopy(&v->value,
-											  &((const UA_VariableTypeNode *)node)->value.type->typeId,
-											  &UA_TYPES[UA_TYPES_NODEID]);
-		} else {
-			const UA_VariableNode *vn = (const UA_VariableNode*)node;
-			if(vn->variableType == UA_VARIABLENODETYPE_VARIANT)
-				retval |= UA_Variant_setScalarCopy(&v->value, &vn->variable.variant.type->typeId,
-												  &UA_TYPES[UA_TYPES_NODEID]);
-			else {
-				UA_DataValue val;
-				UA_DataValue_init(&val);
-				retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, UA_FALSE, &val);
-				if(retval != UA_STATUSCODE_GOOD)
-					break;
-				retval |= UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId,
-												  &UA_TYPES[UA_TYPES_NODEID]);
-				vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
-				if(retval != UA_STATUSCODE_GOOD)
-					break;
-			}
-		}
+        const UA_VariableNode *vn = (const UA_VariableNode*)node;
+        if(vn->valueSource == UA_VALUESOURCE_VARIANT)
+            retval = UA_Variant_setScalarCopy(&v->value, &vn->value.variant.type->typeId,
+                                              &UA_TYPES[UA_TYPES_NODEID]);
+        else {
+            UA_DataValue val;
+            UA_DataValue_init(&val);
+            retval = vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, &val);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
+            retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
+            vn->value.dataSource.release(vn->value.dataSource.handle, &val);
+        }
+        if(retval == UA_STATUSCODE_GOOD)
+            v->hasValue = UA_TRUE;
+        }
         break;
 
     case UA_ATTRIBUTEID_VALUERANK:
@@ -266,21 +258,17 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         {
-        	//TODO: handle indexRange
-            if(node->nodeClass == UA_NODECLASS_VARIABLETYPE)
-                break;
-                
             const UA_VariableNode *vn = (const UA_VariableNode *)node;
-            if(vn->variableType == UA_VARIABLENODETYPE_VARIANT) {
-                retval = UA_Variant_setArrayCopy(&v->value, vn->variable.variant.arrayDimensions,
-                                                 vn->variable.variant.arrayDimensionsSize,
+            if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
+                retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.arrayDimensions,
+                                                 vn->value.variant.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->variable.dataSource.read(vn->variable.dataSource.handle, UA_FALSE, &val);
+                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, &val);
                 if(retval != UA_STATUSCODE_GOOD)
                     break;
                 if(!val.hasValue)
@@ -288,7 +276,7 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
                 else
                     retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions,
                                                      val.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
-                vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+                vn->value.dataSource.release(vn->value.dataSource.handle, &val);
             }
         }
         break;
@@ -440,6 +428,10 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 static 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;
+
     // we might repeat writing, e.g. when the node got replaced mid-work
     UA_Boolean done = UA_FALSE;
     while(!done) {
@@ -462,104 +454,95 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
         case UA_ATTRIBUTEID_EVENTNOTIFIER:
             retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
             break;
-        case UA_ATTRIBUTEID_VALUE:
-            if(node->nodeClass == UA_NODECLASS_VARIABLE) {
-                const UA_VariableNode *vn = (const UA_VariableNode*)node;
-                if(vn->variableType == UA_VARIABLENODETYPE_DATASOURCE) {
-                    if(!vn->variable.dataSource.write) {
-                        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-                        break;
-                    }
-                    retval = vn->variable.dataSource.write(vn->variable.dataSource.handle, &wvalue->value.value);
-                    done = UA_TRUE;
-                    break;
-                }
-
-                // array sizes are not compared
+        case UA_ATTRIBUTEID_VALUE: {
+            if(node->nodeClass != UA_NODECLASS_VARIABLE &&
+               node->nodeClass != UA_NODECLASS_VARIABLETYPE) {
+                retval = UA_STATUSCODE_BADTYPEMISMATCH;
+                break;
+            }
 
-                if(!wvalue->value.hasValue) {
-                    retval = UA_STATUSCODE_BADTYPEMISMATCH;
+            /* 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;
-                }
-
-                if(!UA_NodeId_equal(&vn->variable.variant.type->typeId, &wvalue->value.value.type->typeId)) {
-                    if(vn->variable.variant.type->namespaceZero && wvalue->value.value.type->namespaceZero &&
-                       vn->variable.variant.type->typeIndex == wvalue->value.value.type->typeIndex)
-                        // an enum was sent as an int32, or an opaque type as a bytestring
-                        wvalue->value.value.type = vn->variable.variant.type;
-                    else if(vn->variable.variant.type == &UA_TYPES[UA_TYPES_BYTE] &&
-                            (!vn->variable.variant.data || vn->variable.variant.arrayLength > -1) /* isArray */ &&
-                            wvalue->value.value.type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
-                            wvalue->value.value.data && wvalue->value.value.arrayLength == -1 /* isScalar */) {
-                        // 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;
-                        break;
-                    }
-                }
+                hasRange = UA_TRUE;
+            }
 
-                UA_VariableNode *newVn = UA_VariableNode_new();
-                if(!newVn) {
-                    retval = UA_STATUSCODE_BADOUTOFMEMORY;
-                    break;
-                }
-                retval = UA_VariableNode_copy(vn, newVn);
-                if(retval != UA_STATUSCODE_GOOD) {
-                    UA_VariableNode_delete(newVn);
-                    break;
-                }
-                retval = UA_Variant_copy(&wvalue->value.value, &newVn->variable.variant);
-                if(retval != UA_STATUSCODE_GOOD) {
-                    UA_VariableNode_delete(newVn);
-                    break;
-                }
-                if(UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVn,
-                                        UA_NULL) == UA_STATUSCODE_GOOD)
-                    done = UA_TRUE;
-                else
-                    UA_VariableNode_delete(newVn);
-            } else if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
-                const UA_VariableTypeNode *vtn = (const UA_VariableTypeNode*)node;
-                if(!wvalue->value.hasValue) {
+            /* 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;
                     break;
                 }
-                if(!UA_NodeId_equal(&vtn->value.type->typeId, &wvalue->value.value.type->typeId)) {
-                    if(!vtn->value.type->namespaceZero || wvalue->value.value.type->namespaceZero ||
-                       vtn->value.type->typeIndex != wvalue->value.value.type->typeIndex) {
-                        retval = UA_STATUSCODE_BADTYPEMISMATCH;
-                        break;
-                    }
-                    wvalue->value.value.type = vtn->value.type;
-                }
-
-                UA_VariableTypeNode *newVtn = UA_VariableTypeNode_new();
-                if(!newVtn) {
-                    retval = UA_STATUSCODE_BADOUTOFMEMORY;
-                    break;
-                }
-                retval = UA_VariableTypeNode_copy(vtn, newVtn);
-                if(retval != UA_STATUSCODE_GOOD) {
-                    UA_VariableTypeNode_delete(newVtn);
-                    break;
-                }
-                retval = UA_Variant_copy(&wvalue->value.value, &newVtn->value);
-                if(retval != UA_STATUSCODE_GOOD) {
-                    UA_VariableTypeNode_delete(newVtn);
+                // todo: writing ranges
+                retval = vn->value.dataSource.write(vn->value.dataSource.handle, &wvalue->value.value);
+                done = UA_TRUE;
+                break;
+            }
+            const UA_Variant *oldV = &vn->value.variant;
+
+            /* 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] &&
+                        (!oldV->data || vn->value.variant.arrayLength > -1) /* isArray */ &&
+                        wvalue->value.value.type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
+                        wvalue->value.value.data && wvalue->value.value.arrayLength == -1 /* isScalar */) {
+                    /* 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;
                     break;
                 }
-                if(UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVtn,
-                                        UA_NULL) == UA_STATUSCODE_GOOD)
-                    done = UA_TRUE;
-                else
-                    UA_VariableTypeNode_delete(newVtn);
-            } else {
-                retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+            }
+
+            /* 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;
+                break;
+            }
+            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_setRange(&newVn->value.variant, wvalue->value.value.data, range);
+            else {
+                UA_Variant_deleteMembers(&newVn->value.variant);
+                retval = UA_Variant_copy(&wvalue->value.value, &newVn->value.variant);
+            }
+            if(retval != UA_STATUSCODE_GOOD ||
+               UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVn,
+                                    UA_NULL) != UA_STATUSCODE_GOOD)
+                goto clean_up;
+            if(hasRange)
+                UA_free(range.dimensions);
+            done = UA_TRUE;
+            break;
+
+            clean_up:
+            if(node->nodeClass == UA_NODECLASS_VARIABLE)
+                UA_VariableNode_delete(newVn);
+            else
+                UA_VariableTypeNode_delete((UA_VariableTypeNode*)newVn);
+            if(hasRange)
+                UA_free(range.dimensions);
             }
             break;
         case UA_ATTRIBUTEID_DATATYPE:
@@ -578,10 +561,9 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
             break;
         }
 
+        UA_NodeStore_release(node);
         if(retval != UA_STATUSCODE_GOOD)
             break;
-
-        UA_NodeStore_release(node);
     }
 
     return retval;

+ 1 - 1
src/server/ua_services_nodemanagement.c

@@ -66,7 +66,7 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     /* } */
 
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
-        vnode->variable.variant = attr.value;
+        vnode->value.variant = attr.value;
         UA_Variant_init(&attr.value);
     }
 

+ 165 - 107
src/ua_types.c

@@ -81,12 +81,13 @@ UA_TYPE_DEFAULT(UA_Double)
 
 /* String */
 UA_TYPE_NEW_DEFAULT(UA_String)
+UA_TYPE_DELETE_DEFAULT(UA_String)
+
 void UA_String_init(UA_String *p) {
     p->length = -1;
     p->data   = UA_NULL;
 }
 
-UA_TYPE_DELETE_DEFAULT(UA_String)
 void UA_String_deleteMembers(UA_String *p) {
     UA_free(p->data);
     p->data = UA_NULL;
@@ -103,21 +104,22 @@ UA_StatusCode UA_String_copy(UA_String const *src, UA_String *dst) {
     return UA_STATUSCODE_GOOD;
 }
 
-/* The c-string needs to be null-terminated. the string cannot be smaller than zero. */
-UA_StatusCode UA_String_copycstring(char const *src, UA_String *dst) {
-    UA_String_init(dst);
-    size_t length = (UA_UInt32) strlen(src);
+UA_String UA_String_fromChars(char const *src) {
+    UA_String str;
+    size_t length = sizeof(src)-1;
     if(length == 0) {
-        dst->length = 0;
-        dst->data = UA_NULL;
-        return UA_STATUSCODE_GOOD;
+        str.length = 0;
+        str.data = UA_NULL;
+        return str;
     }
-    dst->data = UA_malloc(length);
-    if(!dst->data)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    UA_memcpy(dst->data, src, length);
-    dst->length = length;
-    return UA_STATUSCODE_GOOD;
+    str.data = UA_malloc(length);
+    if(!str.data) {
+        str.length = -1;
+        return str;
+    }
+    UA_memcpy(str.data, src, length);
+    str.length = length;
+    return str;
 }
 
 #define UA_STRING_COPYPRINTF_BUFSIZE 1024
@@ -229,6 +231,7 @@ UA_StatusCode UA_DateTime_toString(UA_DateTime atime, UA_String *timeString) {
 }
 
 /* Guid */
+UA_TYPE_NEW_DEFAULT(UA_Guid)
 UA_TYPE_DELETEMEMBERS_NOACTION(UA_Guid)
 UA_TYPE_DELETE_DEFAULT(UA_Guid)
 
@@ -264,7 +267,6 @@ void UA_Guid_init(UA_Guid *p) {
     memset(p->data4, 0, sizeof(UA_Byte)*8);
 }
 
-UA_TYPE_NEW_DEFAULT(UA_Guid)
 UA_StatusCode UA_Guid_copy(UA_Guid const *src, UA_Guid *dst) {
     UA_memcpy((void *)dst, (const void *)src, sizeof(UA_Guid));
     return UA_STATUSCODE_GOOD;
@@ -289,13 +291,15 @@ UA_StatusCode UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length) {
 /* XmlElement */
 
 /* NodeId */
+UA_TYPE_NEW_DEFAULT(UA_NodeId)
+UA_TYPE_DELETE_DEFAULT(UA_NodeId)
+
 void UA_NodeId_init(UA_NodeId *p) {
     p->identifierType = UA_NODEIDTYPE_NUMERIC;
     p->namespaceIndex = 0;
     memset(&p->identifier, 0, sizeof(p->identifier));
 }
 
-UA_TYPE_NEW_DEFAULT(UA_NodeId)
 UA_StatusCode UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     switch(src->identifierType) {
@@ -329,7 +333,6 @@ static UA_Boolean UA_NodeId_isBasicType(UA_NodeId const *id) {
         id ->identifier.numeric <= 25;
 }
 
-UA_TYPE_DELETE_DEFAULT(UA_NodeId)
 void UA_NodeId_deleteMembers(UA_NodeId *p) {
     switch(p->identifierType) {
     case UA_NODEIDTYPE_STRING:
@@ -394,7 +397,9 @@ UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
 }
 
 /* ExpandedNodeId */
+UA_TYPE_NEW_DEFAULT(UA_ExpandedNodeId)
 UA_TYPE_DELETE_DEFAULT(UA_ExpandedNodeId)
+
 void UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p) {
     UA_NodeId_deleteMembers(&p->nodeId);
     UA_String_deleteMembers(&p->namespaceUri);
@@ -406,7 +411,6 @@ void UA_ExpandedNodeId_init(UA_ExpandedNodeId *p) {
     p->serverIndex = 0;
 }
 
-UA_TYPE_NEW_DEFAULT(UA_ExpandedNodeId)
 UA_StatusCode UA_ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNodeId *dst) {
     UA_StatusCode retval = UA_NodeId_copy(&src->nodeId, &dst->nodeId);
     retval |= UA_String_copy(&src->namespaceUri, &dst->namespaceUri);
@@ -425,7 +429,9 @@ UA_Boolean UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p) {
 /* StatusCode */
 
 /* QualifiedName */
+UA_TYPE_NEW_DEFAULT(UA_QualifiedName)
 UA_TYPE_DELETE_DEFAULT(UA_QualifiedName)
+
 void UA_QualifiedName_deleteMembers(UA_QualifiedName *p) {
     UA_String_deleteMembers(&p->name);
 }
@@ -435,7 +441,6 @@ void UA_QualifiedName_init(UA_QualifiedName *p) {
     p->namespaceIndex = 0;
 }
 
-UA_TYPE_NEW_DEFAULT(UA_QualifiedName)
 UA_StatusCode UA_QualifiedName_copy(UA_QualifiedName const *src, UA_QualifiedName *dst) {
     UA_StatusCode retval = UA_String_copy(&src->name, &dst->name);
     dst->namespaceIndex = src->namespaceIndex;
@@ -444,16 +449,12 @@ UA_StatusCode UA_QualifiedName_copy(UA_QualifiedName const *src, UA_QualifiedNam
         UA_QualifiedName_init(dst);
     }
     return retval;
-
-}
-
-UA_StatusCode UA_QualifiedName_copycstring(char const *src, UA_QualifiedName *dst) {
-    dst->namespaceIndex = 0;
-    return UA_String_copycstring(src, &dst->name);
 }
 
 /* LocalizedText */
+UA_TYPE_NEW_DEFAULT(UA_LocalizedText)
 UA_TYPE_DELETE_DEFAULT(UA_LocalizedText)
+
 void UA_LocalizedText_deleteMembers(UA_LocalizedText *p) {
     UA_String_deleteMembers(&p->locale);
     UA_String_deleteMembers(&p->text);
@@ -464,17 +465,6 @@ void UA_LocalizedText_init(UA_LocalizedText *p) {
     UA_String_init(&p->text);
 }
 
-UA_TYPE_NEW_DEFAULT(UA_LocalizedText)
-UA_StatusCode UA_LocalizedText_copycstring(char const *src, UA_LocalizedText *dst) {
-    UA_StatusCode retval = UA_String_copycstring("", &dst->locale);
-    retval |= UA_String_copycstring(src, &dst->text);
-    if(retval) {
-        UA_LocalizedText_deleteMembers(dst);
-        UA_LocalizedText_init(dst);
-    }
-    return retval;
-}
-
 UA_StatusCode UA_LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst) {
     UA_StatusCode retval = UA_String_copy(&src->locale, &dst->locale);
     retval |= UA_String_copy(&src->text, &dst->text);
@@ -486,7 +476,9 @@ UA_StatusCode UA_LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedTex
 }
 
 /* ExtensionObject */
+UA_TYPE_NEW_DEFAULT(UA_ExtensionObject)
 UA_TYPE_DELETE_DEFAULT(UA_ExtensionObject)
+
 void UA_ExtensionObject_deleteMembers(UA_ExtensionObject *p) {
     UA_NodeId_deleteMembers(&p->typeId);
     UA_ByteString_deleteMembers(&p->body);
@@ -498,7 +490,6 @@ void UA_ExtensionObject_init(UA_ExtensionObject *p) {
     UA_ByteString_init(&p->body);
 }
 
-UA_TYPE_NEW_DEFAULT(UA_ExtensionObject)
 UA_StatusCode UA_ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst) {
     UA_StatusCode retval = UA_ByteString_copy(&src->body, &dst->body);
     retval |= UA_NodeId_copy(&src->typeId, &dst->typeId);
@@ -511,7 +502,9 @@ UA_StatusCode UA_ExtensionObject_copy(UA_ExtensionObject const *src, UA_Extensio
 }
 
 /* DataValue */
+UA_TYPE_NEW_DEFAULT(UA_DataValue)
 UA_TYPE_DELETE_DEFAULT(UA_DataValue)
+
 void UA_DataValue_deleteMembers(UA_DataValue *p) {
     UA_Variant_deleteMembers(&p->value);
 }
@@ -526,7 +519,6 @@ void UA_DataValue_init(UA_DataValue *p) {
     UA_Variant_init(&p->value);
 }
 
-UA_TYPE_NEW_DEFAULT(UA_DataValue)
 UA_StatusCode UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst) {
     UA_DataValue_init(dst);
     *((UA_Byte*)dst) = *((const UA_Byte*)src); // the bitfield
@@ -545,6 +537,8 @@ UA_StatusCode UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst) {
 
 /* Variant */
 UA_TYPE_NEW_DEFAULT(UA_Variant)
+UA_TYPE_DELETE_DEFAULT(UA_Variant)
+
 void UA_Variant_init(UA_Variant *p) {
     p->storageType = UA_VARIANT_DATA;
     p->arrayLength = -1;
@@ -554,20 +548,19 @@ void UA_Variant_init(UA_Variant *p) {
     p->type = &UA_TYPES[UA_TYPES_BOOLEAN];
 }
 
-UA_TYPE_DELETE_DEFAULT(UA_Variant)
 void UA_Variant_deleteMembers(UA_Variant *p) {
-    if(p->storageType == UA_VARIANT_DATA) {
-        if(p->data) {
-            if(p->arrayLength == -1)
-                p->arrayLength = 1;
-            UA_Array_delete(p->data, p->type, p->arrayLength);
-            p->data = UA_NULL;
-            p->arrayLength = -1;
-        }
-        if(p->arrayDimensions) {
-            UA_free(p->arrayDimensions);
-            p->arrayDimensions = UA_NULL;
-        }
+    if(p->storageType != UA_VARIANT_DATA)
+        return;
+    if(p->data) {
+        if(p->arrayLength == -1)
+            p->arrayLength = 1;
+        UA_Array_delete(p->data, p->type, p->arrayLength);
+        p->data = UA_NULL;
+        p->arrayLength = -1;
+    }
+    if(p->arrayDimensions) {
+        UA_free(p->arrayDimensions);
+        p->arrayDimensions = UA_NULL;
     }
 }
 
@@ -596,26 +589,32 @@ UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
         }
         dst->arrayDimensionsSize = src->arrayDimensionsSize;
     }
-
     return retval;
 }
 
-UA_StatusCode UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range) {
-    UA_Variant_init(dst);
-    // test the integrity of the variant dimensions
+/**
+ * Tests if a range is compatible with a variant. If yes, the following values are set:
+ * - total: how many elements are indicated by the range
+ * - block_size: how big is each contiguous block of elements in the variant denoted by the range
+ * - block_distance: how many elements are between the blocks (beginning to beginning)
+ * - first_elem: where does the first block begin
+ */
+static UA_StatusCode testRangeWithVariant(const UA_Variant *v, const UA_NumericRange range, size_t *total,
+                                          size_t *block_size, size_t *block_distance, size_t *first_elem) {
+    /* Test the integrity of the source variant dimensions */
     UA_Int32 dims_count = 1;
-    const UA_Int32 *dims = &src->arrayLength; // default: the array has only one dimension
-    if(src->arrayDimensionsSize > 0) {
-        dims_count = src->arrayDimensionsSize;
-        dims = src->arrayDimensions;
+    const UA_Int32 *dims = &v->arrayLength; // default: the array has only one dimension
+    if(v->arrayDimensionsSize > 0) {
+        dims_count = v->arrayDimensionsSize;
+        dims = v->arrayDimensions;
         UA_Int32 elements = 1;
         for(UA_Int32 i = 0; i < dims_count; i++)
             elements *= dims[i];
-        if(elements != src->arrayLength)
+        if(elements != v->arrayLength)
             return UA_STATUSCODE_BADINTERNALERROR;
     }
 
-    // test the integrity of the range and count objects
+    /* Test the integrity of the range */
     size_t count = 1;
     if(range.dimensionsSize != dims_count)
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -627,67 +626,125 @@ UA_StatusCode UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const
         count *= (range.dimensions[i].max - range.dimensions[i].min) + 1;
     }
 
-    dst->data = UA_malloc(src->type->memSize * count);
-    if(!dst->data)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    
-    // copy a subset of the tensor with as few calls as possible.
-    // shift from copying single elements to contiguous blocks
-    size_t elem_size = src->type->memSize;
-    uintptr_t nextsrc = (uintptr_t)src->data; // the start ptr of the next copy operation
-    size_t contiguous_elems = src->arrayLength; // the length of the copy operation
-    ptrdiff_t jump_length = elem_size * dims[0]; // how far to jump until the next contiguous copy
-    size_t copy_count = count; // how often to copy
-
-    size_t running_dimssize = 1; // how big is a contiguous block for the dimensions k_max to k
+    /* Compute the block size and the position of the first element */
+    size_t bs = 0;
+    size_t bd = 0;
+    size_t fe = 0;
+    size_t running_dimssize = 1; // elements per block of dimensions k to k_max
     UA_Boolean found_contiguous = UA_FALSE;
     for(UA_Int32 k = dims_count - 1; k >= 0; k--) {
-        if(!found_contiguous) {
-            if(range.dimensions[k].min != 0 || range.dimensions[k].max + 1 != (UA_UInt32)dims[k]) {
-                found_contiguous = UA_TRUE;
-                contiguous_elems = (range.dimensions[k].max - range.dimensions[k].min + 1) * running_dimssize;
-                jump_length = ((dims[k] * running_dimssize) - contiguous_elems) * elem_size;
-                copy_count /= range.dimensions[k].max - range.dimensions[k].min + 1;
-            } else
-                copy_count /= dims[k];
+        if(!found_contiguous && (range.dimensions[k].min != 0 ||
+                                 range.dimensions[k].max + 1 != (UA_UInt32)dims[k])) {
+            found_contiguous = UA_TRUE;
+            bs = (range.dimensions[k].max - range.dimensions[k].min + 1) * running_dimssize;
+            bd = dims[k] * running_dimssize;
         } 
-        nextsrc += running_dimssize * range.dimensions[k].min * elem_size;
+        fe += running_dimssize * range.dimensions[k].min;
         running_dimssize *= dims[k];
     }
+    *total = count;
+    *block_size = bs;
+    *block_distance = bd;
+    *first_elem = fe;
+    return UA_STATUSCODE_GOOD;
+}
 
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+UA_StatusCode UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range) {
+    size_t count, block_size, block_distance, first_elem;
+    UA_StatusCode retval = testRangeWithVariant(src, range, &count, &block_size, &block_distance, &first_elem);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    UA_Variant_init(dst);
+    size_t elem_size = src->type->memSize;
+    dst->data = UA_malloc(elem_size * count);
+    if(!dst->data)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    /* Copy the range */
+    size_t block_count = count / block_size;
     uintptr_t nextdst = (uintptr_t)dst->data;
-    size_t copied = 0;
-    for(size_t i = 0; i < copy_count; i++) {
-        if(src->type->fixedSize) {
-            memcpy((void*)nextdst, (void*)nextsrc, elem_size * contiguous_elems);
-        } else {
-            for(size_t j = 0; j < contiguous_elems; j++)
-                retval = UA_copy((const void*)(nextsrc + (j * elem_size)), (void*)(nextdst + (j * elem_size)),
-                                 src->type);
-            if(retval != UA_STATUSCODE_GOOD) {
-                UA_Array_delete(dst->data, src->type, copied);
-                return retval;
+    uintptr_t nextsrc = (uintptr_t)src->data + (elem_size * first_elem);
+    if(src->type->fixedSize) {
+        for(size_t i = 0; i < block_count; i++) {
+            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block_size);
+            nextdst += block_size * elem_size;
+            nextsrc += block_distance * elem_size;
+        }
+    } else {
+        for(size_t i = 0; i < block_count; i++) {
+            for(size_t j = 0; j < block_size && retval == UA_STATUSCODE_GOOD; j++) {
+                retval = UA_copy((const void*)nextsrc, (void*)nextdst, src->type);
+                nextdst += elem_size;
+                nextsrc += elem_size;
             }
-            copied += contiguous_elems;
+            nextsrc += (block_distance - block_size) * elem_size;
         }
-        nextdst += elem_size * contiguous_elems;
-        nextsrc += jump_length;
-    }
-
-    if(src->arrayDimensionsSize > 0) {
-        retval = UA_Array_copy(dims, (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_INT32], dims_count);
         if(retval != UA_STATUSCODE_GOOD) {
+            size_t copied = ((nextdst - elem_size) - (uintptr_t)dst->data) / elem_size;
             UA_Array_delete(dst->data, src->type, copied);
             return retval;
         }
-        for(UA_Int32 k = 0; k < dims_count; k++)
+    }
+
+    /* Copy the range dimensions*/
+    if(src->arrayDimensionsSize > 0) {
+        dst->arrayDimensions = UA_malloc(sizeof(UA_Int32) * src->arrayDimensionsSize);
+        if(!dst->arrayDimensions) {
+            UA_Array_delete(dst->data, src->type, count);
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        }
+        for(UA_Int32 k = 0; k < src->arrayDimensionsSize; k++)
             dst->arrayDimensions[k] = range.dimensions[k].max - range.dimensions[k].min + 1;
-        dst->arrayDimensionsSize = dims_count;
+        dst->arrayDimensionsSize = src->arrayDimensionsSize;
     }
     dst->arrayLength = count;
     dst->type = src->type;
-    dst->storageType = UA_VARIANT_DATA;
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode UA_Variant_setRange(UA_Variant *v, void *data, const UA_NumericRange range) {
+    size_t count, block_size, block_distance, first_elem;
+    UA_StatusCode retval = testRangeWithVariant(v, range, &count, &block_size, &block_distance, &first_elem);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    size_t block_count = count / block_size;
+    size_t elem_size = v->type->memSize;
+    uintptr_t nextdst = (uintptr_t)v->data + (first_elem * elem_size);
+    uintptr_t nextsrc = (uintptr_t)data;
+    if(v->type->fixedSize) {
+        for(size_t i = 0; i < block_count; i++) {
+            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block_size);
+            nextdst += block_size * elem_size;
+            nextsrc += block_distance * elem_size;
+        }
+    } else {
+        for(size_t i = 0; i < block_count; i++) {
+            for(size_t j = 0; j < block_size; j++) {
+                UA_deleteMembers((void*)nextdst, v->type);
+                nextdst += elem_size;
+            }
+            nextdst -= block_size * elem_size;
+            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block_size);
+            nextdst += block_size * elem_size;
+            nextsrc += block_distance * elem_size;
+        }
+    }
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode UA_Variant_setCopyRange(const UA_Variant *src, UA_Variant *dst, void *data,
+                                      const UA_NumericRange range) {
+    // todo: don't copy the entire variant but only the retained parts
+    UA_StatusCode retval = UA_Variant_copy(src, dst);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    retval = UA_Variant_setRange(dst, data, range);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Variant_deleteMembers(dst);
+        return retval;
+    }
     return UA_STATUSCODE_GOOD;
 }
 
@@ -725,7 +782,9 @@ UA_StatusCode UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32
 }
 
 /* DiagnosticInfo */
+UA_TYPE_NEW_DEFAULT(UA_DiagnosticInfo)
 UA_TYPE_DELETE_DEFAULT(UA_DiagnosticInfo)
+
 void UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
     UA_String_deleteMembers(&p->additionalInfo);
     if(p->hasInnerDiagnosticInfo && p->innerDiagnosticInfo) {
@@ -734,7 +793,6 @@ void UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
     }
 }
 
-UA_TYPE_NEW_DEFAULT(UA_DiagnosticInfo)
 void UA_DiagnosticInfo_init(UA_DiagnosticInfo *p) {
 	*((UA_Byte*)p) = 0; // zero out the bitfield
     p->symbolicId          = 0;
@@ -1111,7 +1169,7 @@ UA_StatusCode UA_Array_copy(const void *src, void **dst, const UA_DataType *data
 
     if(retval != UA_STATUSCODE_GOOD)
         UA_Array_delete(*dst, dataType, noElements);
-        
+
     return retval;
 }
 

+ 3 - 0
src/ua_util.h

@@ -15,6 +15,9 @@
 #ifndef _BSD_SOURCE
 # define _BSD_SOURCE
 #endif
+#ifndef _DEFAULT_SOURCE
+# define _DEFAULT_SOURCE
+#endif
 
 /*********************/
 /* Memory Management */

+ 6 - 4
tests/CMakeLists.txt

@@ -50,13 +50,15 @@ add_test(nodestore ${CMAKE_CURRENT_BINARY_DIR}/check_nodestore)
 add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/client_HELOPN.bin
                    PRE_BUILD
                    COMMAND python ${PROJECT_SOURCE_DIR}/tools/hex2bin.py ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_HELOPN.hex
+                                  ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_CreateActivateSession.hex
                    DEPENDS ${PROJECT_SOURCE_DIR}/tools/hex2bin.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_HELOPN.hex)
 
-add_executable(check_server_interaction_fileinput check_server_interaction_fileinput.c
-                                                  testing_networklayers.c
-                                                  ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
-                                                  $<TARGET_OBJECTS:open62541-object>)
+set(check_fileinput_source check_server_interaction_fileinput.c testing_networklayers.c $<TARGET_OBJECTS:open62541-object>)
+if(NOT ENABLE_AMALGAMATION)
+    list(APPEND check_fileinput_source ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
+endif()
+add_executable(check_server_interaction_fileinput ${check_fileinput_source})
 
 target_include_directories(check_server_interaction_fileinput PRIVATE ${PROJECT_SOURCE_DIR}/examples)
 target_include_directories(check_server_interaction_fileinput PRIVATE ${PROJECT_BINARY_DIR})

+ 8 - 13
tests/check_builtin.c

@@ -1287,9 +1287,9 @@ START_TEST(UA_Array_copyUA_StringShallWorkOnExample) {
 	UA_String *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 3);
 	UA_String *dstArray;
 
-	UA_String_copycstring("open", &srcArray[0]);
-	UA_String_copycstring("62541", &srcArray[1]);
-	UA_String_copycstring("opc ua", &srcArray[2]);
+	srcArray[0] = UA_STRING_ALLOC("open");
+	srcArray[1] = UA_STRING_ALLOC("62541");
+	srcArray[2] = UA_STRING_ALLOC("opc ua");
 	//when
 	UA_Array_copy((const void *)srcArray, (void **)&dstArray, &UA_TYPES[UA_TYPES_STRING], 3);
 	//then
@@ -1434,18 +1434,13 @@ END_TEST
 
 START_TEST(UA_LocalizedText_copycstringShallWorkOnInputExample) {
 	// given
-	const char src[8] = {'t', 'e', 'X', 't', '1', '2', '3', (char)0};
-	UA_LocalizedText dst;
+	char src[8] = {'t', 'e', 'X', 't', '1', '2', '3', (char)0};
+	const UA_LocalizedText dst = UA_LOCALIZEDTEXT("", src);
 
-	// when
-	UA_StatusCode ret = UA_LocalizedText_copycstring(src, &dst);
 	// then
-	ck_assert_int_eq(ret, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq('1', dst.text.data[4]);
 	ck_assert_int_eq(0, dst.locale.length);
 	ck_assert_int_eq(7, dst.text.length);
-	// finally
-	UA_LocalizedText_deleteMembers(&dst);
 }
 END_TEST
 
@@ -1506,9 +1501,9 @@ END_TEST
 START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
 	// given
 	UA_String *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 3);
-	UA_String_copycstring("__open", &srcArray[0]);
-	UA_String_copycstring("_62541", &srcArray[1]);
-	UA_String_copycstring("opc ua", &srcArray[2]);
+	srcArray[0] = UA_STRING_ALLOC("__open");
+	srcArray[1] = UA_STRING_ALLOC("_62541");
+	srcArray[2] = UA_STRING_ALLOC("opc ua");
 
 	UA_Int32 *dimensions;
 	dimensions = UA_malloc(sizeof(UA_Int32));

+ 17 - 0
tests/dumps/client_CreateActivateSession.hex

@@ -0,0 +1,17 @@
+4d 53 47 46 05 01 00 00 08 00 00 00 08 00 00 00  /* MSGF............ */
+34 00 00 00 02 00 00 00 01 00 cd 01 00 00 ad 6e  /* 4..............n */
+22 33 58 6c d0 01 01 00 00 00 00 00 00 00 ff ff  /* "3Xl............ */
+ff ff 00 00 00 00 00 00 00 14 00 00 00 75 72 6e  /* .............urn */
+3a 6c 6f 63 61 6c 68 6f 73 74 3a 55 41 3a 43 54  /* :localhost:UA:CT */
+54 1c 00 00 00 75 72 6e 3a 6f 70 63 66 6f 75 6e  /* T....urn:opcfoun */
+64 61 74 69 6f 6e 2e 6f 72 67 3a 55 41 3a 43 54  /* dation.org:UA:CT */
+54 03 02 00 00 00 65 6e 2d 00 00 00 4f 50 43 20  /* T.....en-...OPC  */
+55 6e 69 66 69 65 64 20 41 72 63 68 69 74 65 63  /* Unified Architec */
+74 75 72 65 20 43 6f 6d 70 6c 69 61 6e 63 65 20  /* ture Compliance  */
+54 65 73 74 20 54 6f 6f 6c 01 00 00 00 ff ff ff  /* Test Tool....... */
+ff ff ff ff ff 00 00 00 00 ff ff ff ff 1e 00 00  /* ................ */
+00 6f 70 63 2e 74 63 70 3a 2f 2f 31 39 32 2e 31  /* .opc.tcp://192.1 */
+36 38 2e 35 36 2e 31 30 31 3a 31 36 36 36 34 0e  /* 68.56.101:16664. */
+00 00 00 55 61 43 74 74 53 65 73 73 69 6f 6e 5f  /* ...UaCttSession_ */
+31 ff ff ff ff ff ff ff ff 00 00 00 00 00 4c fd  /* 1.............L. */
+40 00 00 00 00                                   /* @....            */

+ 2 - 0
tests/testing_networklayers.c

@@ -95,5 +95,7 @@ ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCal
     nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) NetworkLayer_FileInput_getWork;
     nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) NetworkLayer_FileInput_stop;
     nl.free = (void (*)(void*))NetworkLayer_FileInput_delete;
+    nl.discoveryUrl = UA_String_new();
+    *nl.discoveryUrl = UA_STRING_ALLOC("");
     return nl;
 }

+ 15 - 20
tools/.deployDoxygen.sh

@@ -1,27 +1,22 @@
 #!/bin/bash
 
 #
-# This sciprt is run by travis-ci and pushes generated
+# This script is run by travis-ci and pushes generated
 # Doxygen docs to open62541-www
 #
 
 git fetch origin coverity_scan
-COMMITS=`git log --oneline --since=today.midnight | wc -l`
-if [[ "$COMMITS" -le "1" ]]; then
-   git clone --depth=50 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
-   cd open62541-www
-   git rm -rf doc
-   cp -r ../build/doc ./
-   git add -A doc/*
-   cp ../build/open62541.* ./
-   git add open62541.*
-   git config --global user.email "open62541-travis-ci@users.noreply.github.com"
-   git config --global user.name "Open62541 travis-ci"
-   git config --global push.default simple
-   git commit -am "doxygen updated by travis-ci"
-   git push https://$GITAUTH@github.com/acplt/open62541-www
-   cd ..
-   rm -rf open62541-www
-else
-    echo "Not the first commit of the day - no doxygen update required"
-fi
+git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
+cd open62541-www
+git rm -rf doc
+cp -r ../build/doc ./
+git add -A doc/*
+cp ../build/open62541.* ./
+git add open62541.*
+git config --global user.email "open62541-travis-ci@users.noreply.github.com"
+git config --global user.name "Open62541 travis-ci"
+git config --global push.default simple
+git commit -am "doxygen updated by travis-ci"
+git push https://$GITAUTH@github.com/acplt/open62541-www
+cd ..
+rm -rf open62541-www