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

Merge branch 'master' into client

Conflicts:
	examples/networklayer_tcp.c
	examples/networklayer_tcp.h
	examples/server.c
	src/ua_types.c
	src/ua_util.h
Julius Pfrommer преди 10 години
родител
ревизия
e3c14e1077
променени са 59 файла, в които са добавени 3945 реда и са изтрити 3599 реда
  1. 73 136
      CMakeLists.txt
  2. 14 12
      README.md
  3. 0 7
      include/queue.h
  4. 0 60
      examples/api-design/check_server-api.c
  5. 0 4
      examples/api-design/open62541-ns0-pico.h
  6. 0 19
      examples/api-design/open62541-server.h
  7. 0 1
      examples/api-design/open62541-tcp.h
  8. 0 2
      examples/api-design/open62541.h
  9. 0 45
      examples/api-design/server.c
  10. 21 28
      examples/opcuaClient.c
  11. 3 5
      examples/statelessClient.c
  12. 13 10
      examples/networklayer_tcp.c
  13. 16 16
      examples/networklayer_udp.c
  14. 1 1
      examples/networklayer_udp.h
  15. 24 33
      examples/opcuaServer.c
  16. 51 0
      examples/server.cpp
  17. 136 0
      examples/server_datasource.c
  18. 47 0
      examples/server_udp.c
  19. 5 21
      include/ua_server.h
  20. 293 166
      include/ua_types.h
  21. 3 5
      ports/WAGO-750-860.patch
  22. 0 0
      src/ongoing/opcuaServerMini.c
  23. 307 0
      src/server/ua_nodes.c
  24. 89 0
      src/server/ua_nodes.h
  25. 19 52
      src/server/ua_nodestore.c
  26. 11 10
      src/server/ua_nodestore.h
  27. 31 92
      src/server/ua_nodestore_concurrent.c
  28. 2 2
      src/server/ua_nodestore_hash.inc
  29. 3 0
      src/server/ua_securechannel_manager.c
  30. 1 0
      src/server/ua_securechannel_manager.h
  31. 146 125
      src/server/ua_server.c
  32. 83 59
      src/server/ua_server_addressspace.c
  33. 54 52
      src/server/ua_server_binary.c
  34. 7 2
      src/server/ua_server_internal.h
  35. 169 236
      src/server/ua_services_attribute.c
  36. 0 1
      src/server/ua_services_discovery.c
  37. 52 48
      src/server/ua_services_nodemanagement.c
  38. 10 13
      src/server/ua_services_view.c
  39. 1 0
      src/server/ua_session_manager.h
  40. 2 11
      src/ua_config.h.in
  41. 5 0
      src/ua_securechannel.c
  42. 0 1
      src/ua_securechannel.h
  43. 0 50
      src/ua_transport.c
  44. 0 22
      src/ua_transport.h
  45. 485 520
      src/ua_types.c
  46. 858 616
      src/ua_types_encoding_binary.c
  47. 11 34
      src/ua_types_encoding_binary.h
  48. 0 76
      src/ua_types_macros.h
  49. 7 7
      src/ua_util.h
  50. 242 197
      tests/check_builtin.c
  51. 46 47
      tests/check_memory.c
  52. 65 62
      tests/check_nodestore.c
  53. 0 415
      tools/generate_builtin.py
  54. 467 0
      tools/generate_datatypes.py
  55. 0 237
      tools/generate_namespace.py
  56. 62 0
      tools/generate_nodeids.py
  57. 0 13
      tools/plugin_Node.py
  58. 10 2
      tools/schema/Custom.Opc.Ua.Transport.bsd
  59. 0 26
      tools/type_lists.py

+ 73 - 136
CMakeLists.txt

@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.8.8)
 project(open62541 C)
 set(open62541_VERSION_MAJOR 0)
 set(open62541_VERSION_MINOR 0)
-set(NVIM_VERSION_PATCH 0)
+set(open62541_VERSION_PATCH 0)
 
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
 
@@ -14,142 +14,78 @@ if (NOT CMAKE_BUILD_TYPE)
     set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build." FORCE)
 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
+                -Wshadow -Wcast-align -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wconversion
+                -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()
+	if(NOT WIN32)
+	    add_definitions(-fstack-protector -fPIC -fvisibility=hidden)
+	endif()
+endif()
+
 # main sources of libopen62541
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
 include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src")
 file(GLOB_RECURSE exported_headers "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")
-file(GLOB_RECURSE headers "${CMAKE_CURRENT_SOURCE_DIR}/src/*.h")
 file(GLOB generated_headers "${PROJECT_BINARY_DIR}/src_generated/*.h")
 set(lib_sources src/ua_types.c
                 src/ua_types_encoding_binary.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
-                ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_0.c
-                src/ua_transport.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
+                ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                 src/ua_securechannel.c
                 src/ua_session.c
                 src/client/ua_client.c
                 src/server/ua_server.c
 				src/server/ua_server_addressspace.c
 				src/server/ua_server_binary.c
+				src/server/ua_nodes.c
                 src/server/ua_server_worker.c
                 src/server/ua_securechannel_manager.c
                 src/server/ua_session_manager.c
-                src/server/ua_services_attribute.c
-                src/server/ua_services_session.c
                 src/server/ua_services_discovery.c
                 src/server/ua_services_securechannel.c
+                src/server/ua_services_session.c
+                src/server/ua_services_attribute.c
                 src/server/ua_services_nodemanagement.c
                 src/server/ua_services_view.c
 				${exported_headers}
-				${generated_headers}
-                ${headers})
+				${generated_headers} )
 
-# compiler flags
-if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
-add_definitions(-std=c99 -pedantic -pipe -Wall -Wextra -Werror -Wformat
-                -Wno-unused-parameter -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
-                -Wshadow -Wcast-align -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wconversion
-                -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()
-	if(NOT WIN32)
-	    add_definitions(-fstack-protector -fPIC -fvisibility=hidden)
-	endif()
-endif()
-
-# build settings
-set(generate_src_options) # the options for the tools that generate code from xml-schema definitions
-
-## set debug flag
-if(CMAKE_BUILD_TYPE MATCHES Debug)
-    set(UA_DEBUG ON)
+## multithreading
+option(MULTITHREADING "Enable multithreading" OFF)
+if(MULTITHREADING)
+    set(UA_MULTITHREADING ON)
+    find_package(Threads REQUIRED)
+    list(APPEND lib_sources src/server/ua_nodestore_concurrent.c)
 else()
-    set(UA_DEBUG OFF)
+    list(APPEND lib_sources src/server/ua_nodestore.c)
 endif()
 
 ## extensions
-option(EXTENSION_STATELESS "Enable stateless extension" OFF)
 option(EXTENSION_UDP "Enable udp extension" OFF)
-
 if(EXTENSION_UDP)
 	set(EXTENSION_STATELESS ON)
 	message(STATUS "Extensions: enabling udp")
 	add_definitions(-DEXTENSION_UDP)
 endif()
 
+option(EXTENSION_STATELESS "Enable stateless extension" OFF)
 if(EXTENSION_STATELESS)
 	message(STATUS "Extensions: enabling stateless")
 	add_definitions(-DEXTENSION_STATELESS)
-	add_executable(statelessClient $<TARGET_OBJECTS:open62541-objects> examples/statelessClient.c)
-    if(MULTITHREADING)
-        target_link_libraries(statelessClient urcu-cds urcu urcu-common pthread)
-    endif()
 endif()
 
-## self-signed certificates
-option(ENABLE_SELFSIGNED "Enable self-signed certificates" OFF)
-if(ENABLE_SELFSIGNED)
-    message(STATUS "Enabling self-signed certificates")
-    SET(lib_sources ${lib_sources} ${PROJECT_BINARY_DIR}/localhost.der ${PROJECT_BINARY_DIR}/ca.crt)
-    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/localhost.der
-                              ${PROJECT_BINARY_DIR}/ca.crt
-                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py ${PROJECT_BINARY_DIR}
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/certs/create_self-signed.py
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/certs/localhost.cnf)
-endif()
-
-## auto-generate all types or only the relevant subset?
-option(TYPES_ONLY_NEEDED "Include only compile-needed types" OFF)
-if(TYPES_ONLY_NEEDED)
-    list(APPEND generate_src_options "--only-needed")
-endif()
-
-## encodings
-set(UA_ENCODING_AMOUNT 1) # binary encoding
-
-### xml
-option(ENABLE_XML_ENCODING "Enable XML-encoding of the UA types" OFF)
-if(ENABLE_XML_ENCODING)
-    MATH(EXPR UA_ENCODING_AMOUNT "${UA_ENCODING_AMOUNT}+1")
-    find_package(EXPAT REQUIRED)
-    if(EXPAT_FOUND)
-        include_directories(${EXPAT_INCLUDE_DIRS})
-    else(EXPAT_FOUND)
-        message(FATAL_ERROR "Expat library not found.")
-    endif(EXPAT_FOUND)
-	include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src/ongoing")
-    list(APPEND lib_sources src/ongoing/ua_types_encoding_xml.c
-                            src/ongoing/ua_namespace_xml.c
-                            src/ongoing/ua_xml.c)
-    list(APPEND generate_src_options "--with-xml")
-endif()
-
-# ### json
-# option(ENABLE_JSON_ENCODING "Enable JSON-encoding of the UA types" OFF)
-# if(ENABLE_JSON_ENCODING)
-#     MATH(EXPR UA_ENCODING_AMOUNT "${UA_ENCODING_AMOUNT}+1")
-# 	include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src/ongoing")
-#     list(APPEND lib_sources src/ongoing/ua_types_encoding_json.c)
-#     list(APPEND generate_src_options "--with-json")
-# endif(ENABLE_JSON_ENCODING)
-
-## multithreading
-option(MULTITHREADING "Enable multithreading" OFF)
-if(MULTITHREADING)
-    set(UA_MULTITHREADING ON)
-    find_package(Threads REQUIRED)
-    list(APPEND lib_sources src/server/ua_nodestore_concurrent.c)
-else()
-    list(APPEND lib_sources src/server/ua_nodestore.c)
-endif()
-
-add_library(open62541-objects OBJECT ${lib_sources}) 
+add_library(open62541-objects OBJECT ${lib_sources})
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-objects>)
 add_library(open62541-static STATIC $<TARGET_OBJECTS:open62541-objects>)
 SET_TARGET_PROPERTIES(open62541-static PROPERTIES OUTPUT_NAME open62541 CLEAN_DIRECT_OUTPUT 1) # static version that exports all symbols
@@ -171,42 +107,31 @@ endif()
 # set the precompiler flags
 configure_file("src/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
 
-# download queue.h if required
-if(WIN32)
-    if(NOT EXISTS "${PROJECT_BINARY_DIR}/src_generated/queue.h")
-        file(DOWNLOAD "http://openbsd.cs.toronto.edu/cgi-bin/cvsweb/~checkout~/src/sys/sys/queue.h" "${PROJECT_BINARY_DIR}/src_generated/queue.h" STATUS result)
-        list(GET result 0 download_ok)
-        if(NOT ${download_ok} MATCHES 0)
-            file(REMOVE "${PROJECT_BINARY_DIR}/src_generated/queue.h") # remove empty file if created
-            message(FATAL_ERROR "queue.h could not be downloaded")
-        endif()
-    endif()
-endif(WIN32)
-
 # generate code from xml definitions
 file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
 include_directories("${PROJECT_BINARY_DIR}/src_generated") 
+
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                    PRE_BUILD
-                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/generate_builtin.py --export-prototypes ${generate_src_options} ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_builtin.py
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd)
-
-add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_0.c
-                          ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_0.h
-                   PRE_BUILD
-                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/generate_namespace.py ${generate_src_options} ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_0
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_namespace.py
+                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
+                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
 
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
                    PRE_BUILD
-                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/generate_builtin.py --additional-includes=ua_transport.h ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_transport
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_builtin.py
+                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --ns0-types-xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd 1 ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_transport
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd)
 
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
+                   PRE_BUILD
+                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/generate_nodeids.py ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_nodeids.py
+                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
+
 # build example client
 option(CLIENT "Build a test client" OFF)
 if(CLIENT)
@@ -214,31 +139,43 @@ if(CLIENT)
 	add_definitions( -DBENCHMARK=1 )
     # the client is built directly with the .o files as it currently uses
     # internal functions that are not exported to the shared lib.
-	add_executable(exampleClient $<TARGET_OBJECTS:open62541-objects> examples/opcuaClient.c)
+	add_executable(exampleClient $<TARGET_OBJECTS:open62541-objects> examples/client.c)
     if(MULTITHREADING)
         target_link_libraries(exampleClient urcu-cds urcu urcu-common pthread)
     endif()
+    if(EXTENSION_STATELESS)
+        add_executable(statelessClient $<TARGET_OBJECTS:open62541-objects> examples/client_stateless.c)
+        if(MULTITHREADING)
+            target_link_libraries(statelessClient urcu-cds urcu urcu-common pthread)
+        endif()
+    endif()
 endif()
 
 # build example server
 option(EXAMPLESERVER "Build a test server" OFF)
 if(EXAMPLESERVER)
-set(server_sources examples/opcuaServer.c
-                   examples/networklayer_tcp.c
-                   examples/logger_stdout.c)
-if(EXTENSION_UDP)
-	list(APPEND server_sources examples/networklayer_udp.c)
-endif()
-add_executable(exampleServer ${server_sources} ${exported_headers} ${generated_headers})
-target_link_libraries(exampleServer open62541)
-if(WIN32)
-    target_link_libraries(exampleServer ws2_32)
-else()
-    target_link_libraries(exampleServer rt)
-endif(WIN32)
-if(MULTITHREADING)
-    target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
+    add_executable(exampleServer examples/server.c examples/networklayer_tcp.c examples/logger_stdout.c ${exported_headers} ${generated_headers})
+    target_link_libraries(exampleServer open62541)
+    if(WIN32)
+        target_link_libraries(exampleServer ws2_32)
+    else()
+        target_link_libraries(exampleServer rt)
+    endif()
+    if(MULTITHREADING)
+        target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
+    endif()
 endif()
+
+## self-signed certificates
+option(GENERATE_SELFSIGNED "Generate self-signed certificates" OFF)
+if(GENERATE_SELFSIGNED)
+    message(STATUS "Enabling self-signed certificates")
+    SET(lib_sources ${lib_sources} ${PROJECT_BINARY_DIR}/localhost.der ${PROJECT_BINARY_DIR}/ca.crt)
+    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/localhost.der
+                              ${PROJECT_BINARY_DIR}/ca.crt
+                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py ${PROJECT_BINARY_DIR}
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/certs/create_self-signed.py
+                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/certs/localhost.cnf)
 endif()
 
 # build unit tests

+ 14 - 12
README.md

@@ -31,7 +31,6 @@ As an open source project, we invite new contributors to help improving open6241
 
 /* provided by the open62541 lib */
 #include "ua_server.h"
-#include "ua_namespace_0.h"
 
 /* provided by the user, implementations available in the /examples folder */
 #include "logger_stdout.h"
@@ -51,20 +50,23 @@ int main(int argc, char** argv) {
 
     /* init the server */
 	UA_Server *server = UA_Server_new();
-    NetworklayerTCP *nl = NetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT);
+    NetworklayerTCP *nl = ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT);
     UA_Server_addNetworkLayer(server, nl);
 
     /* add a variable node */
-    UA_Int32 myInteger = 42;
-    UA_String myIntegerName;
-    UA_STRING_STATIC(myIntegerName, "The Answer");
-    UA_Server_addScalarVariableNode(server,
-                 /* the browse name, the value, and the datatype vtable */
-                 &myIntegerName, (void*)&myInteger, &UA_TYPES[UA_INT32],
-                 /* the parent node of the variable */
-                 &UA_NODEIDS[UA_OBJECTSFOLDER],
-                 /* the (hierarchical) referencetype from the parent */
-                 &UA_NODEIDS[UA_ORGANIZES]);
+    UA_Int32 *myInteger = UA_Int32_new();
+    *myInteger = 42;
+    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_Variant_setValue(myIntegerVariant, myInteger, UA_TYPES_INT32);
+    UA_QualifiedName myIntegerName;
+    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "the answer");
+    UA_Server_addVariableNode(server,
+                              myIntegerVariant, /* the variant */
+                              &UA_NODEID_NULL, /* assign a new nodeid */
+                              &myIntegerName, /* the browse name */
+                              /* the parent node and the referencetype to the parent */
+                              &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
 
     /* run the server loop */
     UA_StatusCode retval = UA_Server_run(server, WORKER_THREADS, &running);

+ 0 - 7
include/queue.h

@@ -99,13 +99,6 @@ struct name {								\
 #define	SLIST_HEAD_INITIALIZER(head)					\
 	{ NULL }
  
-
-/*changes by Stasik0 to avoid conflicts with winnt.h*/
-#ifdef SLIST_ENTRY
-#undef SLIST_ENTRY
-#endif
-/**/
-
 #define SLIST_ENTRY(type)						\
 struct {								\
 	struct type *sle_next;	/* next element */			\

+ 0 - 60
examples/api-design/check_server-api.c

@@ -1,60 +0,0 @@
-#include "open62541.h"
-#include "open62541-server.h"
-#include "check.h"
-
-START_TEST(addingVariableNodeTwiceShallRedirectPointer) {
-	//GIVEN
-	UA_Int32 myInteger = 0, otherInteger = 0;
-	UA_NodeId myIntegerNode = {1, UA_NODEIDTYPE_NUMERIC, 50};
-
-	//WHEN
-	UA_Application_addVariableNode(application, &myIntegerNode, UA_INT32, &myInteger);
-	UA_Application_addVariableNode(application, &myIntegerNode, UA_INT32, &otherInteger);
-
-	//THEN
-	ck_assert_ptr_eq(otherInteger,UA_Application_getVariableNodeAppPtr(application, &myIntegerNode);
-}
-END_TEST
-
-START_TEST(addingDifferentVariableNodesWithSameMemoryShallResultInTwoViewsOnOneMemoryLocation) {
-	//GIVEN
-	UA_Int32 myInteger = 0;
-	UA_NodeId myIntegerNode = {1, UA_NODEIDTYPE_NUMERIC, 50};
-	UA_NodeId otherIntegerNode = {1, UA_NODEIDTYPE_NUMERIC, 51};
-
-	//WHEN
-	UA_Application_addVariableNode(application, &myIntegerNode, UA_INT32, &myInteger);
-	UA_Application_addVariableNode(application, &otherIntegerNode, UA_INT32, &myInteger);
-
-	//THEN
-	ck_assert_ptr_eq(myInteger,UA_Application_getVariableNodeAppPtr(application, &myIntegerNode);
-	ck_assert_ptr_eq(myInteger,UA_Application_getVariableNodeAppPtr(application, &otherIntegerNode);
-}
-END_TEST
-
-Suite *testSuite_builtin(void) {
-	Suite *s = suite_create("Test api");
-
-	TCase *tc_ns0 = tcase_create("populating namespaces");
-	tcase_add_test(tc_ns0, addingVariableNodeTwiceShallRedirectPointer);
-	tcase_add_test(tc_ns0, addingDifferentVariableNodesWithSameMemoryShallResultInTwoViewsOnOneMemoryLocation);
-	suite_add_tcase(s, tc_ns0);
-
-	return s;
-}
-
-
-int main(void) {
-	int      number_failed = 0;
-	Suite   *s;
-	SRunner *sr;
-
-	s  = testSuite_builtin();
-	sr = srunner_create(s);
-	//srunner_set_fork_status(sr, CK_NOFORK);
-	srunner_run_all(sr, CK_NORMAL);
-	number_failed += srunner_ntests_failed(sr);
-	srunner_free(sr);
-
-	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}

+ 0 - 4
examples/api-design/open62541-ns0-pico.h

@@ -1,4 +0,0 @@
-#include "ua_namespace.h"
-
-Namespace UA_NamespaceZero_Static;_
-

+ 0 - 19
examples/api-design/open62541-server.h

@@ -1,19 +0,0 @@
-#include "open62541.h"
-
-struct UA_NetworkLayer;
-typedef struct UA_NetworkLayer UA_NetworkLayer;
-
-struct UA_Application;
-typedef struct UA_Application UA_Application;
-
-typedef struct UA_ServerConfiguration {
-	UA_String certificatePublic;
-	UA_String certificatePrivate;
-	UA_Networklayer *networklayer;
-} UA_ServerConfiguration;
-
-typedef struct UA_Server {
-	UA_ServerConfiguration configuration;
-	UA_Int32 applicationsSize;
-	UA_Application *applications;
-} UA_Server;

+ 0 - 1
examples/api-design/open62541-tcp.h

@@ -1 +0,0 @@
-#include "../networklayer.h"

+ 0 - 2
examples/api-design/open62541.h

@@ -1,2 +0,0 @@
-#include "ua_types.h"
-#include "ua_application.h"

+ 0 - 45
examples/api-design/server.c

@@ -1,45 +0,0 @@
-#include "open62541.h"
-#include "open62541-server.h"
-#include "open62541-tcp.h"
-
-#include "open62541-ns0-pico.h" // UA_NamespaceZero_Static
-
-#define PORT 1234
-#define MAX_CONNECTIONS 1024
-
-int main(int argc, char ** argv) {
-	// Set up UA_Application
-	UA_Application *application;
-	UA_Application_new(&application);
-
-	// Set up namespace Zero and typical application parameters
-	UA_Application_addNamespace(application, 0, &UA_NamespaceZero_Static);
-
-	UA_ApplicationDescription *applicationDescription;
-	UA_Application_new(&applicationDescription);
-	UA_ApplicationDescription_setApplicationName("Application");
-	UA_ApplicationDescription_setApplicationUri("http://open62541.org/api-design/");
-	UA_Application_setVariableNodeNS0(application, UA_APPLICATIONDESCRIPTION_NS0, applicationDescription);
-
-	// Set up application specific namespace
-	UA_Application_addNamespace(application, 1, UA_NULL);
-
-	UA_Int32 myInteger = 0;
-	UA_NodeId myIntegerNode = {1, UA_NODEIDTYPE_NUMERIC, 50};
-	UA_Application_addVariableNode(application, &myIntegerNode, UA_INT32, &myInteger);
-
-	// Set up server with network layer and add application
-	UA_Server *server;
-	UA_Server_new(&server);
-	UA_TcpNetworkLayer_new(&server.configuration.networklayer, PORT, MAX_CONNECTIONS);
-	UA_Server_addApplication(server, application);
-
-	// Run server
-	UA_Server_start(server);
-
-	// Clean up (? first server then application ?)
-	UA_Server_delete(server);
-	UA_Application_delete(application);
-
-	return 0;
-}

+ 21 - 28
examples/opcuaClient.c

@@ -11,7 +11,7 @@
 #include <unistd.h> // for close
 #include <stdlib.h> // pulls in declaration of malloc, free
 #include "ua_transport_generated.h"
-#include "ua_namespace_0.h"
+#include "ua_types_encoding_binary.h"
 #include "ua_util.h"
 
 typedef struct ConnectionInfo {
@@ -25,8 +25,7 @@ typedef struct ConnectionInfo {
 static UA_Int32 sendHello(UA_Int32 sock, UA_String *endpointURL) {
 
 	UA_TcpMessageHeader messageHeader;
-	messageHeader.isFinal = 'F';
-	messageHeader.messageType = UA_MESSAGETYPE_HEL;
+	messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
 
 	UA_TcpHelloMessage hello;
 	UA_String_copy(endpointURL, &hello.endpointUrl);
@@ -41,7 +40,7 @@ static UA_Int32 sendHello(UA_Int32 sock, UA_String *endpointURL) {
 	UA_ByteString message;
 	UA_ByteString_newMembers(&message, messageHeader.messageSize);
 
-	UA_UInt32 offset = 0;
+	size_t offset = 0;
 	UA_TcpMessageHeader_encodeBinary((UA_TcpMessageHeader const*) &messageHeader, &message, &offset);
 	UA_TcpHelloMessage_encodeBinary((UA_TcpHelloMessage const*) &hello, &message, &offset);
 
@@ -56,8 +55,7 @@ static UA_Int32 sendHello(UA_Int32 sock, UA_String *endpointURL) {
 
 static int sendOpenSecureChannel(UA_Int32 sock) {
 	UA_TcpMessageHeader msghdr;
-	msghdr.isFinal = 'F';
-	msghdr.messageType = UA_MESSAGETYPE_OPN;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
 
 	UA_UInt32 secureChannelId = 0;
 	UA_String securityPolicy;
@@ -97,7 +95,7 @@ static int sendOpenSecureChannel(UA_Int32 sock) {
 
 	UA_ByteString message;
 	UA_ByteString_newMembers(&message, 1000);
-	UA_UInt32 offset = 0;
+	size_t offset = 0;
 	UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
 	UA_UInt32_encodeBinary(&secureChannelId, &message, &offset);
 	UA_String_encodeBinary(&securityPolicy, &message, &offset);
@@ -125,11 +123,10 @@ static UA_Int32 sendCreateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32
     UA_ByteString message;
 	UA_ByteString_newMembers(&message, 65536);
 	UA_UInt32 tmpChannelId = channelId;
-	UA_UInt32 offset = 0;
+	size_t offset = 0;
 
 	UA_TcpMessageHeader msghdr;
-	msghdr.isFinal = 'F';
-	msghdr.messageType = UA_MESSAGETYPE_MSG;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
 
 	UA_NodeId type;
 	type.identifier.numeric = 461;
@@ -174,7 +171,7 @@ static UA_Int32 sendCreateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32
 }
 
 static UA_Int32 closeSession(ConnectionInfo *connectionInfo) {
-	UA_UInt32 offset = 0;
+	size_t offset = 0;
 
 	UA_ByteString message;
 	UA_ByteString_newMembers(&message, 65536);
@@ -191,8 +188,7 @@ static UA_Int32 closeSession(ConnectionInfo *connectionInfo) {
     rq.deleteSubscriptions = UA_TRUE;
 
 	UA_TcpMessageHeader msghdr;
-	msghdr.isFinal = 'F';
-	msghdr.messageType = UA_MESSAGETYPE_MSG;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
 
 	UA_NodeId type;
 	type.identifier.numeric = 473;
@@ -222,7 +218,7 @@ static UA_Int32 closeSession(ConnectionInfo *connectionInfo) {
 }
 
 static UA_Int32 closeSecureChannel(ConnectionInfo *connectionInfo) {
-	UA_UInt32 offset = 0;
+	size_t offset = 0;
 
 	UA_ByteString message;
 	UA_ByteString_newMembers(&message, 65536);
@@ -238,8 +234,7 @@ static UA_Int32 closeSecureChannel(ConnectionInfo *connectionInfo) {
 	rq.requestHeader.authenticationToken.namespaceIndex = 10;
 
 	UA_TcpMessageHeader msghdr;
-	msghdr.isFinal = 'F';
-	msghdr.messageType = UA_MESSAGETYPE_CLO;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
 
 	msghdr.messageSize = 4 + UA_TcpMessageHeader_calcSizeBinary(&msghdr) +
                          UA_CloseSecureChannelRequest_calcSizeBinary(&rq);
@@ -264,11 +259,10 @@ static UA_Int32 sendActivateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt3
 	UA_ByteString *message = UA_ByteString_new();
 	UA_ByteString_newMembers(message, 65536);
 	UA_UInt32 tmpChannelId = channelId;
-	UA_UInt32 offset = 0;
+	size_t offset = 0;
 
 	UA_TcpMessageHeader msghdr;
-	msghdr.isFinal = 'F';
-	msghdr.messageType = UA_MESSAGETYPE_MSG;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
 	msghdr.messageSize = 86;
 
 	UA_NodeId type;
@@ -312,11 +306,10 @@ static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds
 	UA_ByteString *message = UA_ByteString_new();
 	UA_ByteString_newMembers(message, 65536);
 	UA_UInt32 tmpChannelId = connectionInfo->channelId;
-	UA_UInt32 offset = 0;
+	size_t offset = 0;
 
 	UA_TcpMessageHeader msghdr;
-	msghdr.isFinal = 'F';
-	msghdr.messageType = UA_MESSAGETYPE_MSG;
+	msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
 
 	UA_NodeId type;
 	type.identifier.numeric = 631;
@@ -326,7 +319,7 @@ static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds
 	UA_ReadRequest rq;
 	UA_ReadRequest_init(&rq);
 	rq.maxAge = 0;
-	UA_Array_new((void **)&rq.nodesToRead, nodeIds_size, &UA_TYPES[UA_READVALUEID]);
+	rq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
 	rq.nodesToReadSize = nodeIds_size;
 	for(UA_Int32 i=0;i<nodeIds_size;i++) {
 		UA_ReadValueId_init(&(rq.nodesToRead[i]));
@@ -354,7 +347,7 @@ static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds
 
 	UA_DateTime tic = UA_DateTime_now();
 	UA_Int32 sendret = send(connectionInfo->socket, message->data, offset, 0);
-	UA_Array_delete(rq.nodesToRead,nodeIds_size,&UA_TYPES[UA_READVALUEID]);
+	UA_Array_delete(rq.nodesToRead, &UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
 	UA_ByteString_delete(message);
 
 	if (sendret < 0) {
@@ -402,7 +395,7 @@ static int ua_client_connectUA(char* ipaddress,int port, UA_String *endpointUrl,
 			sendOpenSecureChannel(sock);
 			recv(sock, reply.data, reply.length, 0);
 
-			UA_UInt32 recvOffset = 0;
+			size_t recvOffset = 0;
 			UA_TcpMessageHeader msghdr;
 			UA_TcpMessageHeader_decodeBinary(&reply, &recvOffset, &msghdr);
 
@@ -509,7 +502,7 @@ int main(int argc, char *argv[]) {
 
 /* REQUEST START*/
     UA_NodeId *nodesToRead;
-    UA_Array_new((void**)&nodesToRead,nodesToReadSize,&UA_TYPES[UA_NODEID]);
+    nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_NODEID], nodesToReadSize);
 
 	for(UA_UInt32 i = 0; i<nodesToReadSize; i++) {
 		if(alwaysSameNode)
@@ -523,7 +516,7 @@ int main(int argc, char *argv[]) {
 	UA_DateTime tic, toc;
 	UA_Double *timeDiffs;
 	UA_Int32 received;
-	UA_Array_new((void**)&timeDiffs,tries,&UA_TYPES[UA_DOUBLE]);
+	timeDiffs = UA_Array_new(&UA_TYPES[UA_TYPES_DOUBLE], tries);
 	UA_Double sum = 0;
 
 	for(UA_UInt32 i = 0; i < tries; i++) {
@@ -583,7 +576,7 @@ int main(int argc, char *argv[]) {
 	fclose(fHandle);
 
 	UA_String_deleteMembers(&reply);
-	UA_Array_delete(nodesToRead,nodesToReadSize,&UA_TYPES[UA_NODEID]);
+	UA_Array_delete(nodesToRead,&UA_TYPES[UA_TYPES_NODEID], nodesToReadSize);
     UA_free(timeDiffs);
 
 	return 0;

+ 3 - 5
examples/statelessClient.c

@@ -9,8 +9,8 @@
 #include <stdlib.h> // pulls in declaration of malloc, free
 
 #include "ua_transport_generated.h"
-#include "ua_namespace_0.h"
 #include "ua_util.h"
+#include "ua_types_encoding_binary.h"
 
 
 int main(int argc , char *argv[])
@@ -72,7 +72,7 @@ int main(int argc , char *argv[])
 	req.requestHeader.additionalHeader = reqHeaderAdditionalHeader;
 	UA_ExtensionObject_init(&(req.requestHeader.additionalHeader));
 
-	UA_Array_new((void **)&req.nodesToRead, 1, &UA_TYPES[UA_READVALUEID]);
+	UA_Array_new((void **)&req.nodesToRead, 1, &UA_TYPES[UA_TYPES_READVALUEID]);
 	req.nodesToReadSize = 1;
 
 	UA_ReadValueId_init(&(req.nodesToRead[0]));
@@ -91,10 +91,8 @@ int main(int argc , char *argv[])
 			UA_ReadRequest_calcSizeBinary(&req);
 
 	UA_TcpMessageHeader_init(&reqTcpHeader);
-	reqTcpHeader.messageType = UA_MESSAGETYPE_MSG;
+	reqTcpHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
 	reqTcpHeader.messageSize = messageEncodedLength;
-	reqTcpHeader.isFinal = 'F';
-
 
 	UA_TcpMessageHeader_encodeBinary(&reqTcpHeader, &message, &messagepos);
 	UA_UInt32_encodeBinary(&reqSecureChannelId, &message, &messagepos);

+ 13 - 10
examples/networklayer_tcp.c

@@ -14,6 +14,7 @@
 #else
 #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
@@ -122,7 +123,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     c->layer = layer;
     c->connection.state = UA_CONNECTION_OPENING;
     c->connection.localConf = layer->conf;
-    c->connection.channel = UA_NULL;
+    c->connection.channel = (void*)0;
     c->connection.close = (void (*)(void*))closeConnection;
     c->connection.write = (void (*)(void*, UA_ByteStringArray))writeCallback;
 
@@ -145,10 +146,10 @@ static UA_UInt32 batchDeleteLinks(ServerNetworkLayerTCP *layer, UA_WorkItem **re
 		return 0;
 	}
 #ifdef UA_MULTITHREADING
-    struct deleteLink *d = uatomic_xchg(&layer->deleteLinkList, UA_NULL);
+    struct deleteLink *d = uatomic_xchg(&layer->deleteLinkList, (void*)0);
 #else
     struct deleteLink *d = layer->deleteLinkList;
-    layer->deleteLinkList = UA_NULL;
+    layer->deleteLinkList = (void*)0;
 #endif
     UA_UInt32 count = 0;
     while(d) {
@@ -303,7 +304,7 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer) {
 
 static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_WorkItem **workItems,
                                         UA_UInt16 timeout) {
-    UA_WorkItem *items = UA_NULL;
+    UA_WorkItem *items = (void*)0;
     UA_Int32 itemsCount = batchDeleteLinks(layer, &items);
     setFDSet(layer);
     struct timeval tmptv = {0, timeout};
@@ -320,6 +321,8 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
 		struct sockaddr_in cli_addr;
 		socklen_t cli_len = sizeof(cli_addr);
 		int newsockfd = accept(layer->serversockfd, (struct sockaddr *) &cli_addr, &cli_len);
+		int i = 1;
+		setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&i, sizeof(i));
 		if (newsockfd >= 0)
 			ServerNetworkLayerTCP_add(layer, newsockfd);
 	}
@@ -382,19 +385,19 @@ static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
 }
 
 UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
-    ServerNetworkLayerTCP *tcplayer = malloc(sizeof(ServerNetworkLayerTCP));
+    NetworkLayerTCP *tcplayer = malloc(sizeof(NetworkLayerTCP));
 	tcplayer->conf = conf;
 	tcplayer->conLinksSize = 0;
 	tcplayer->conLinks = NULL;
     tcplayer->port = port;
-    tcplayer->deleteLinkList = UA_NULL;
+    tcplayer->deleteLinkList = (void*)0;
 
     UA_ServerNetworkLayer nl;
     nl.nlHandle = tcplayer;
-    nl.start = (UA_StatusCode (*)(void*))ServerNetworkLayerTCP_start;
-    nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16))ServerNetworkLayerTCP_getWork;
-    nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**))ServerNetworkLayerTCP_stop;
-    nl.free = (void (*)(void*))ServerNetworkLayerTCP_delete;
+    nl.start = (UA_StatusCode (*)(void*))NetworkLayerTCP_start;
+    nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) NetworkLayerTCP_getWork;
+    nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) NetworkLayerTCP_stop;
+    nl.free = (void (*)(void*))NetworkLayerTCP_delete;
     return nl;
 }
 

+ 16 - 16
examples/networklayer_udp.c

@@ -34,7 +34,7 @@
 
 #define MAXBACKLOG 100
 
-struct Networklayer_UDP;
+struct ServerNetworklayerUDP;
 
 /* Forwarded to the server as a (UA_Connection) and used for callbacks back into
    the networklayer */
@@ -42,10 +42,10 @@ typedef struct {
 	UA_Connection connection;
 	struct sockaddr from;
 	socklen_t fromlen;
-	struct NetworkLayerUDP *layer;
+	struct ServerNetworkLayerUDP *layer;
 } UDPConnection;
 
-typedef struct NetworkLayerUDP {
+typedef struct ServerNetworkLayerUDP {
 	UA_ConnectionConfig conf;
 	fd_set fdset;
 #ifdef _WIN32
@@ -54,7 +54,7 @@ typedef struct NetworkLayerUDP {
 	UA_Int32 serversockfd;
 #endif
     UA_UInt32 port;
-} NetworkLayerUDP;
+} ServerNetworkLayerUDP;
 
 static UA_StatusCode setNonBlocking(int sockid) {
 #ifdef _WIN32
@@ -69,7 +69,7 @@ static UA_StatusCode setNonBlocking(int sockid) {
 	return UA_STATUSCODE_GOOD;
 }
 
-static void setFDSet(NetworkLayerUDP *layer) {
+static void setFDSet(ServerNetworkLayerUDP *layer) {
 	FD_ZERO(&layer->fdset);
 	FD_SET(layer->serversockfd, &layer->fdset);
 }
@@ -150,7 +150,7 @@ void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
 #endif
 }
 
-static UA_StatusCode NetworkLayerUDP_start(NetworkLayerUDP *layer) {
+static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer) {
 #ifdef _WIN32
 	WORD wVersionRequested;
 	WSADATA wsaData;
@@ -195,7 +195,7 @@ static UA_StatusCode NetworkLayerUDP_start(NetworkLayerUDP *layer) {
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_Int32 NetworkLayerUDP_getWork(NetworkLayerUDP *layer, UA_WorkItem **workItems,
+static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_WorkItem **workItems,
                                         UA_UInt16 timeout) {
     UA_WorkItem *items = UA_NULL;
     setFDSet(layer);
@@ -267,25 +267,25 @@ static UA_Int32 NetworkLayerUDP_getWork(NetworkLayerUDP *layer, UA_WorkItem **wo
     return j;
 }
 
-static UA_Int32 NetworkLayerUDP_stop(NetworkLayerUDP * layer, UA_WorkItem **workItems) {
+static UA_Int32 ServerNetworkLayerUDP_stop(ServerNetworkLayerUDP * layer, UA_WorkItem **workItems) {
 	CLOSESOCKET(layer->serversockfd);
 	return 0;
 }
 
-static void NetworkLayerUDP_delete(NetworkLayerUDP *layer) {
+static void ServerNetworkLayerUDP_delete(ServerNetworkLayerUDP *layer) {
 	free(layer);
 }
 
-UA_NetworkLayer NetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
-    NetworkLayerUDP *udplayer = malloc(sizeof(NetworkLayerUDP));
+UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port){
+    ServerNetworkLayerUDP *udplayer = malloc(sizeof(ServerNetworkLayerUDP));
 	udplayer->conf = conf;
     udplayer->port = port;
 
-    UA_NetworkLayer nl;
+    UA_ServerNetworkLayer nl;
     nl.nlHandle = udplayer;
-    nl.start = (UA_StatusCode (*)(void*))NetworkLayerUDP_start;
-    nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) NetworkLayerUDP_getWork;
-    nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) NetworkLayerUDP_stop;
-    nl.delete = (void (*)(void*))NetworkLayerUDP_delete;
+    nl.start = (UA_StatusCode (*)(void*))ServerNetworkLayerUDP_start;
+    nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16)) ServerNetworkLayerUDP_getWork;
+    nl.stop = (UA_Int32 (*)(void*, UA_WorkItem**)) ServerNetworkLayerUDP_stop;
+    nl.free = (void (*)(void*))ServerNetworkLayerUDP_delete;
     return nl;
 }

+ 1 - 1
examples/networklayer_udp.h

@@ -13,7 +13,7 @@ extern "C" {
 #include "ua_server.h"
 
 /** @brief Create the UDP networklayer and listen to the specified port */
-UA_NetworkLayer NetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UInt32 port);
 
 #ifdef __cplusplus
 } // extern "C"

+ 24 - 33
examples/opcuaServer.c

@@ -2,6 +2,8 @@
  * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
+#include <time.h>
+#include "ua_types.h"
 
 #include <stdio.h>
 #include <stdlib.h> 
@@ -10,15 +12,10 @@
 
 // provided by the open62541 lib
 #include "ua_server.h"
-#include "ua_namespace_0.h"
 
 // provided by the user, implementations available in the /examples folder
 #include "logger_stdout.h"
 #include "networklayer_tcp.h"
-#ifdef EXTENSION_UDP
-#include "networklayer_udp.h"
-#endif
-
 
 UA_Boolean running = 1;
 
@@ -28,6 +25,7 @@ static void stopHandler(int sign) {
 }
 
 static UA_ByteString loadCertificate(void) {
+
     UA_ByteString certificate = UA_STRING_NULL;
 	FILE *fp = NULL;
 	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
@@ -61,46 +59,39 @@ int main(int argc, char** argv) {
 
 	UA_Server *server = UA_Server_new();
     UA_Server_setServerCertificate(server, loadCertificate());
-#ifdef EXTENSION_UDP
-    UA_Server_addNetworkLayer(server, NetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664));
-#else
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-#endif
 
+    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = testCallback, .data = NULL} };
+    UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL); // call every 2 sec
 
-    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = testCallback, .data = UA_NULL} };
-    UA_Server_addRepeatedWorkItem(server, &work, 20000000, UA_NULL); // call every 2 sec
-
-	//add a node to the adresspace
+	// add a variable node to the adresspace
     UA_Int32 *myInteger = UA_Int32_new();
     *myInteger = 42;
+    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_Variant_setValue(myIntegerVariant, myInteger, UA_TYPES_INT32);
     UA_QualifiedName myIntegerName;
-    UA_QUALIFIEDNAME_STATIC(myIntegerName, "the answer");
-    UA_Server_addScalarVariableNode(server, &myIntegerName,
-                                    myInteger, &UA_TYPES[UA_INT32],
-                                    &UA_EXPANDEDNODEIDS[UA_OBJECTSFOLDER],
-                                    &UA_NODEIDS[UA_ORGANIZES]);
+    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "the answer");
+    UA_Server_addVariableNode(server, myIntegerVariant, &UA_NODEID_NULL, &myIntegerName,
+                              &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+    // add node with a callback to the userspace
+    
     
 #ifdef BENCHMARK
     UA_UInt32 nodeCount = 500;
-    UA_Int32 data = 42;
     char str[15];
     for(UA_UInt32 i = 0;i<nodeCount;i++) {
-        UA_VariableNode *tmpNode = UA_VariableNode_new();
+        UA_Int32 *data = UA_Int32_new();
+        *data = 42;
+        UA_Variant *variant = UA_Variant_new();
+        UA_Variant_setValue(variant, data, UA_TYPES_INT32);
+        UA_QualifiedName *nodeName = UA_QualifiedName_new();
         sprintf(str,"%d",i);
-        UA_QualifiedName_copycstring(str,&tmpNode->browseName);
-        UA_LocalizedText_copycstring(str,&tmpNode->displayName);
-        UA_LocalizedText_copycstring("integer value", &tmpNode->description);
-        tmpNode->nodeId.identifier.numeric = 19000+i;
-        tmpNode->nodeClass = UA_NODECLASS_VARIABLE;
-        //tmpNode->valueRank = -1;
-        tmpNode->value.vt = &UA_TYPES[UA_INT32];
-        tmpNode->value.storage.data.dataPtr = &data;
-        tmpNode->value.storageType = UA_VARIANT_DATA_NODELETE;
-        tmpNode->value.storage.data.arrayLength = 1;
-        UA_Server_addNode(server, (const UA_Node**)&tmpNode,
-                          &UA_EXPANDEDNODEIDS[UA_OBJECTSFOLDER],
-                          &UA_NODEIDS[UA_HASCOMPONENT]);
+        UA_QualifiedName_copycstring(str, nodeName);
+        UA_Server_addVariableNode(server, variant, &UA_NODEID_NULL, nodeName,
+                                  &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
     }
 #endif
 

+ 51 - 0
examples/server.cpp

@@ -0,0 +1,51 @@
+/*
+ * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ */
+#include <iostream>
+
+// provided by the open62541 lib
+#include "ua_server.h"
+
+// provided by the user, implementations available in the /examples folder
+#include "logger_stdout.h"
+#include "networklayer_tcp.h"
+
+/**
+ * Build Instructions (Linux)
+ *
+ * To build this C++ server, first compile the open62541 library. Then, compile the network layer and logging with a C compiler.
+ * - gcc -std=c99 -c networklayer_tcp.c -I../include -I../build/src_generated
+ * - gcc -std=c99 -c logger_stdout.c -I../include -I../build/src_generated
+ * Lastly, compile and link the C++ server with
+ * - g++ server.cpp networklayer_tcp.o logger_stdout.o ../build/libopen62541.a -I../include -I../build/src_generated -o server
+ */
+
+using namespace std;
+
+int main()
+{
+	UA_Server *server = UA_Server_new();
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+	//add a node to the adresspace
+    UA_Int32 *myInteger = UA_Int32_new();
+    *myInteger = 42;
+    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_Variant_setValue(myIntegerVariant, myInteger, UA_TYPES_INT32);
+    UA_QualifiedName myIntegerName;
+    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "the answer");
+    UA_NodeId nullnode, objects, organizes;
+    UA_NODEID_ASSIGN(nullnode, 0, 0);
+    UA_NODEID_ASSIGN(objects, UA_NS0ID_OBJECTSFOLDER, 0);
+    UA_NODEID_ASSIGN(organizes, UA_NS0ID_ORGANIZES, 0);
+    
+    UA_Server_addVariableNode(server, myIntegerVariant, &nullnode, &myIntegerName,
+                              &objects, &organizes);
+
+    UA_Boolean running = UA_TRUE;
+    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+	UA_Server_delete(server);
+
+	return retval;
+}

+ 136 - 0
examples/server_datasource.c

@@ -0,0 +1,136 @@
+/*
+ * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ */
+#include <time.h>
+#include "ua_types.h"
+
+#include <stdio.h>
+#include <stdlib.h> 
+#include <signal.h>
+#define __USE_XOPEN2K
+#include <pthread.h>
+
+// provided by the open62541 lib
+#include "ua_server.h"
+
+// provided by the user, implementations available in the /examples folder
+#include "logger_stdout.h"
+#include "networklayer_tcp.h"
+
+/*************************/
+/* Read-only data source */
+/*************************/
+static UA_StatusCode readTimeData(const void *handle, UA_VariantData *data) {
+    UA_DateTime *currentTime = UA_DateTime_new();
+    if(!currentTime)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    *currentTime = UA_DateTime_now();
+    data->arrayLength = 1;
+    data->dataPtr = currentTime;
+    data->arrayDimensionsSize = -1;
+    data->arrayDimensions = UA_NULL;
+    return UA_STATUSCODE_GOOD;
+}
+
+static void releaseTimeData(const void *handle, UA_VariantData *data) {
+    UA_DateTime_delete((UA_DateTime*)data->dataPtr);
+}
+
+static UA_StatusCode writeTimeData(const void *handle, const UA_VariantData *data) {
+    return UA_STATUSCODE_BADINTERNALERROR;
+}
+
+/**************************/
+/* Read/write data source */
+/**************************/
+UA_Int32 deviceStatus = 0;
+pthread_rwlock_t deviceStatusLock;
+
+static void printDeviceStatus(UA_Server *server, void *data) {
+    printf("Device Status: %i\n", deviceStatus);
+}
+
+static UA_StatusCode readDeviceStatus(const void *handle, UA_VariantData *data) {
+    /* In order to reduce blocking time, we could alloc memory for every read
+       and return a copy of the data. */
+    pthread_rwlock_rdlock(&deviceStatusLock);
+    data->arrayLength = 1;
+    data->dataPtr = &deviceStatus;
+    data->arrayDimensionsSize = -1;
+    data->arrayDimensions = UA_NULL;
+    return UA_STATUSCODE_GOOD;
+}
+
+static void releaseDeviceStatus(const void *handle, UA_VariantData *data) {
+    /* If we allocated memory for a specific read, free the content of the
+       variantdata. */
+    data->dataPtr = UA_NULL;
+    data->arrayLength = -1;
+    pthread_rwlock_unlock(&deviceStatusLock);
+}
+
+static UA_StatusCode writeDeviceStatus(const void *handle, const UA_VariantData *data) {
+    pthread_rwlock_wrlock(&deviceStatusLock);
+    if(data->dataPtr != UA_NULL)
+        deviceStatus = *(UA_Int32*)data->dataPtr;
+    pthread_rwlock_unlock(&deviceStatusLock);
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_Boolean running = 1;
+
+static void stopHandler(int sign) {
+    printf("Received Ctrl-C\n");
+	running = 0;
+}
+
+int main(int argc, char** argv) {
+	signal(SIGINT, stopHandler); /* catches ctrl-c */
+    pthread_rwlock_init(&deviceStatusLock, 0);
+
+	UA_Server *server = UA_Server_new();
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+    // add node with the datetime data source
+    UA_Variant *dateVariant = UA_Variant_new();
+    dateVariant->storageType = UA_VARIANT_DATASOURCE;
+    dateVariant->storage.datasource = (UA_VariantDataSource)
+        {.handle = UA_NULL,
+         .read = readTimeData,
+         .release = releaseTimeData,
+         .write = writeTimeData};
+    dateVariant->type = &UA_TYPES[UA_TYPES_DATETIME];
+    dateVariant->typeId = UA_NODEID_STATIC(0, UA_TYPES_IDS[UA_TYPES_DATETIME]);
+    UA_QualifiedName dateName;
+    UA_QUALIFIEDNAME_ASSIGN(dateName, "the time");
+    UA_Server_addVariableNode(server, dateVariant, &UA_NODEID_NULL, &dateName,
+                              &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+    // print the status every 2 sec
+    UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL, .work.methodCall = {.method = printDeviceStatus, .data = UA_NULL} };
+    UA_Server_addRepeatedWorkItem(server, &work, 20000000, UA_NULL);
+
+    // add node with the device status data source
+    UA_Variant *statusVariant = UA_Variant_new();
+    statusVariant->storageType = UA_VARIANT_DATASOURCE;
+    statusVariant->storage.datasource = (UA_VariantDataSource)
+        {.handle = UA_NULL,
+         .read = readDeviceStatus,
+         .release = releaseDeviceStatus,
+         .write = writeDeviceStatus};
+    statusVariant->type = &UA_TYPES[UA_TYPES_INT32];
+    statusVariant->typeId = UA_NODEID_STATIC(0, UA_TYPES_IDS[UA_TYPES_INT32]);
+    UA_QualifiedName statusName;
+    UA_QUALIFIEDNAME_ASSIGN(statusName, "device status");
+    UA_Server_addVariableNode(server, statusVariant, &UA_NODEID_NULL, &statusName,
+                              &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+	UA_Server_delete(server);
+    pthread_rwlock_destroy(&deviceStatusLock);
+
+	return retval;
+}

+ 47 - 0
examples/server_udp.c

@@ -0,0 +1,47 @@
+/*
+ * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
+ */
+#include <time.h>
+#include "ua_types.h"
+
+#include <stdio.h>
+#include <stdlib.h> 
+#include <signal.h>
+
+// provided by the open62541 lib
+#include "ua_server.h"
+
+// provided by the user, implementations available in the /examples folder
+#include "logger_stdout.h"
+#include "networklayer_udp.h"
+
+UA_Boolean running = 1;
+
+static void stopHandler(int sign) {
+    printf("Received Ctrl-C\n");
+	running = 0;
+}
+
+int main(int argc, char** argv) {
+	signal(SIGINT, stopHandler); /* catches ctrl-c */
+
+	UA_Server *server = UA_Server_new();
+    UA_Server_addNetworkLayer(server, ServerNetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664));
+
+	// add a variable node to the adresspace
+    UA_Int32 *myInteger = UA_Int32_new();
+    *myInteger = 42;
+    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_Variant_setValue(myIntegerVariant, myInteger, UA_TYPES_INT32);
+    UA_QualifiedName myIntegerName;
+    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "the answer");
+    UA_Server_addVariableNode(server, myIntegerVariant, &UA_NODEID_NULL, &myIntegerName,
+                              &UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+	UA_Server_delete(server);
+
+	return retval;
+}

+ 5 - 21
include/ua_server.h

@@ -21,8 +21,8 @@ extern "C" {
 #endif
 
 #include "ua_types.h"
-#include "ua_util.h"
 #include "ua_types_generated.h"
+#include "ua_nodeids.h"
 #include "ua_connection.h"
 #include "ua_log.h"
 
@@ -55,28 +55,12 @@ void UA_EXPORT UA_Server_delete(UA_Server *server);
  */
 UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
 
-/**
- * Add a node to the server's address space
- *
- * If adding the node succeeds, the pointer to the node is set to null. If the
- * original nodeid is null (ns=0,i=0), a unique new nodeid is created for the
- * node and returned in the AddNodesResult struct. */
-UA_AddNodesResult UA_EXPORT UA_Server_addNode(UA_Server *server, const UA_Node **node,
-                                              const UA_ExpandedNodeId *parentNodeId,
-                                              const UA_NodeId *referenceTypeId);
-
 /** Add a reference to the server's address space */
 UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item);
 
-/**
- * Add a scalar variable (node) to the server's address space
- *
- * The value must lie on the heap and must not be reused after adding it, as it
- * becomes attached to the lifecycle of the VariableNode. */
-void UA_EXPORT UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName,
-                                               void *value, const UA_TypeVTable *vt,
-                                               const UA_ExpandedNodeId *parentNodeId,
-                                               const UA_NodeId *referenceTypeId );
+UA_StatusCode UA_EXPORT UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, UA_NodeId *nodeId,
+                                                  UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
+                                                  const UA_NodeId *referenceTypeId);
 
 /** Work that is run in the main loop (singlethreaded) or dispatched to a worker
     thread. */
@@ -257,7 +241,7 @@ typedef struct UA_ExternalNodeStore {
 	UA_ExternalNodeStore_browseNodes browseNodes;
 	UA_ExternalNodeStore_addReferences addReferences;
 	UA_ExternalNodeStore_deleteReferences deleteReferences;
-	UA_ExternalNodeStore_delete delete;
+	UA_ExternalNodeStore_delete destroy;
 } UA_ExternalNodeStore;
 
 UA_StatusCode UA_EXPORT

+ 293 - 166
include/ua_types.h

@@ -20,13 +20,10 @@
 extern "C" {
 #endif
 
-#include "ua_config.h"
-
 #include <stdint.h>
 #include <stdbool.h>
-#ifdef UA_DEBUG
-#include <stdio.h>
-#endif
+#include <stddef.h>
+#include "ua_config.h"
 
 /**
  * @defgroup types Datatypes
@@ -89,7 +86,7 @@ typedef uint16_t UA_UInt16;
 /** @brief An integer value between -2 147 483 648 and 2 147 483 647. */
 typedef int32_t UA_Int32;
 #define UA_INT32_MAX 2147483647
-#define UA_INT32_MIN 2147483648
+#define UA_INT32_MIN -2147483648
 
 /** @brief An integer value between 0 and 429 4967 295. */
 typedef uint32_t UA_UInt32;
@@ -99,7 +96,7 @@ typedef uint32_t UA_UInt32;
 /** @brief An integer value between -10 223 372 036 854 775 808 and 9 223 372 036 854 775 807 */
 typedef int64_t UA_Int64;
 #define UA_INT64_MAX 9223372036854775807
-#define UA_INT64_MIN 9223372036854775808
+#define UA_INT64_MIN -9223372036854775808
 
 /** @brief An integer value between 0 and 18 446 744 073 709 551 615. */
 typedef uint64_t UA_UInt64;
@@ -119,7 +116,6 @@ typedef struct {
 } UA_String;
 
 /** @brief An instance in time.
- *
  * A DateTime value is encoded as a 64-bit signed integer which represents the
  * number of 100 nanosecond intervals since January 1, 1601 (UTC).
  */
@@ -192,40 +188,46 @@ typedef struct {
     UA_ByteString body; // contains either the bytestring or a pointer to the memory-object
 } UA_ExtensionObject;
 
-struct UA_TypeVTable; // forward declaration
-typedef struct UA_TypeVTable UA_TypeVTable;
-
 /** @brief Pointers to data that is stored in memory. The "type" of the data is
     stored in the variant itself. */
 typedef struct {
     UA_Int32  arrayLength;        // total number of elements in the data-pointer
     void     *dataPtr;
-    UA_Int32  arrayDimensionsLength;
+    UA_Int32  arrayDimensionsSize;
     UA_Int32 *arrayDimensions;
 } UA_VariantData;
 
 /** @brief A datasource is the interface to interact with a local data provider.
  *
  *  Implementors of datasources need to provide functions for the callbacks in
- *  this structure. As a rule, datasources are never copied, but only their
- *  content. The only way to write into a datasource is via the write-service. */
+ *  this structure. After every read, the handle needs to be released to
+ *  indicate that the pointer is no longer accessed. As a rule, datasources are
+ *  never copied, but only their content. The only way to write into a
+ *  datasource is via the write-service. */
 typedef struct {
-    const void *identifier; /**< whatever id the datasource uses internally. Can be ignored if the datasource functions do not use it. */
-    UA_Int32 (*read)(const void *identifier, const UA_VariantData **); /**< Get the current data from the datasource. When it is no longer used, the data has to be relased. */
-    void (*release)(const void *identifier, const UA_VariantData *); /**< For concurrent access, the datasource needs to know when the last reader releases replaced/deleted data. Release decreases the reference count. */
-    UA_Int32 (*write)(const void **identifier, const UA_VariantData *); /**< Replace the data in the datasource. Also used to replace the identifier pointer for lookups. Do not free the variantdata afterwards! */
-    void (*delete)(const void *identifier); /**< Indicates that the node with the datasource was removed from the namespace. */
+    const void *handle;
+    UA_StatusCode (*read)(const void *handle, UA_VariantData *data);
+    void (*release)(const void *handle, UA_VariantData *data);
+    UA_StatusCode (*write)(const void *handle, const UA_VariantData *data);
 } UA_VariantDataSource;
 
-/** @brief Variants store (arrays of) any data type. Either they provide a
-    pointer to the data in memory, or functions from which the data can be
-    accessed. */
+struct UA_DataType;
+typedef struct UA_DataType UA_DataType; 
+
+/** @brief Variants store (arrays of) any data type. Either they provide a pointer to the data in
+    memory, or functions from which the data can be accessed. Variants are replaced together with
+    the data they store (exception: use a data source).*/
 typedef struct {
-    const UA_TypeVTable *vt; /// The VTable of the datatype in question
+    const UA_DataType *type;
+    UA_NodeId typeId;
     enum {
-        UA_VARIANT_DATA, ///< The data is stored in memory and "owned" by this variant
-        UA_VARIANT_DATA_NODELETE, ///< The data is stored in memory, but only "borrowed" and shall not be deleted at the end of this variant's lifecycle
-        UA_VARIANT_DATASOURCE ///< The data is provided externally. Call the functions in the datasource to get a current version
+        UA_VARIANT_DATA, ///< The data is "owned" by this variant (copied and deleted together)
+        UA_VARIANT_DATA_NODELETE, /**< The data is "borrowed" by the variant and shall not be
+                                       deleted at the end of this variant's lifecycle. It is not
+                                       possible to overwrite borrowed data due to concurrent access.
+                                       Use a custom datasource with a mutex. */
+        UA_VARIANT_DATASOURCE /**< The data is provided externally. Call the functions in the
+                                   datasource to get a current version */
     } storageType;
     union {
         UA_VariantData       data;
@@ -235,7 +237,12 @@ typedef struct {
 
 /** @brief A data value with an associated status code and timestamps. */
 typedef struct {
-    UA_Byte       encodingMask;
+    UA_Boolean    hasVariant : 1;
+    UA_Boolean    hasStatus : 1;
+    UA_Boolean    hasSourceTimestamp : 1;
+    UA_Boolean    hasServerTimestamp : 1;
+    UA_Boolean    hasSourcePicoseconds : 1;
+    UA_Boolean    hasServerPicoseconds : 1;
     UA_Variant    value;
     UA_StatusCode status;
     UA_DateTime   sourceTimestamp;
@@ -244,18 +251,15 @@ typedef struct {
     UA_Int16      serverPicoseconds;
 } UA_DataValue;
 
-enum UA_DATAVALUE_ENCODINGMASKTYPE_enum {
-    UA_DATAVALUE_ENCODINGMASK_VARIANT           = 0x01,
-    UA_DATAVALUE_ENCODINGMASK_STATUSCODE        = 0x02,
-    UA_DATAVALUE_ENCODINGMASK_SOURCETIMESTAMP   = 0x04,
-    UA_DATAVALUE_ENCODINGMASK_SERVERTIMESTAMP   = 0x08,
-    UA_DATAVALUE_ENCODINGMASK_SOURCEPICOSECONDS = 0x10,
-    UA_DATAVALUE_ENCODINGMASK_SERVERPICOSECONDS = 0x20
-};
-
 /** @brief A structure that contains detailed error and diagnostic information associated with a StatusCode. */
 typedef struct UA_DiagnosticInfo {
-    UA_Byte       encodingMask;     // Type of the Enum UA_DIAGNOSTICINFO_ENCODINGMASKTYPE
+    UA_Boolean    hasSymbolicId : 1;
+    UA_Boolean    hasNamespaceUri : 1;
+    UA_Boolean    hasLocalizedText : 1;
+    UA_Boolean    hasLocale : 1;
+    UA_Boolean    hasAdditionalInfo : 1;
+    UA_Boolean    hasInnerStatusCode : 1;
+    UA_Boolean    hasInnerDiagnosticInfo : 1;
     UA_Int32      symbolicId;
     UA_Int32      namespaceUri;
     UA_Int32      localizedText;
@@ -265,96 +269,86 @@ typedef struct UA_DiagnosticInfo {
     struct UA_DiagnosticInfo *innerDiagnosticInfo;
 } UA_DiagnosticInfo;
 
-enum UA_DIAGNOSTICINFO_ENCODINGMASKTYPE_enum {
-    UA_DIAGNOSTICINFO_ENCODINGMASK_SYMBOLICID          = 0x01,
-    UA_DIAGNOSTICINFO_ENCODINGMASK_NAMESPACE           = 0x02,
-    UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALIZEDTEXT       = 0x04,
-    UA_DIAGNOSTICINFO_ENCODINGMASK_LOCALE              = 0x08,
-    UA_DIAGNOSTICINFO_ENCODINGMASK_ADDITIONALINFO      = 0x10,
-    UA_DIAGNOSTICINFO_ENCODINGMASK_INNERSTATUSCODE     = 0x20,
-    UA_DIAGNOSTICINFO_ENCODINGMASK_INNERDIAGNOSTICINFO = 0x40
-};
-
-/** @brief Type use internally to denote an invalid datatype. */
-typedef void UA_InvalidType;
-
-/*************/
-/* Functions */
-/*************/
-
-#ifdef UA_DEBUG
-#define PRINTTYPE(TYPE) void UA_EXPORT TYPE##_print(const TYPE *p, FILE *stream);
-#define PRINTTYPE_NOEXPORT(TYPE) void TYPE##_print(const TYPE *p, FILE *stream);
-#else
-#define PRINTTYPE(TYPE)
-#define PRINTTYPE_NOEXPORT(TYPE)
-#endif
-
-#define UA_TYPE_PROTOTYPES(TYPE)                                     \
+#define UA_TYPE_HANDLING_FUNCTIONS(TYPE)                             \
     TYPE UA_EXPORT * TYPE##_new(void);                               \
     void UA_EXPORT TYPE##_init(TYPE * p);                            \
     void UA_EXPORT TYPE##_delete(TYPE * p);                          \
     void UA_EXPORT TYPE##_deleteMembers(TYPE * p);                   \
-    UA_StatusCode UA_EXPORT TYPE##_copy(const TYPE *src, TYPE *dst); \
-    PRINTTYPE(TYPE)
-
-#define UA_TYPE_PROTOTYPES_NOEXPORT(TYPE)                            \
-    TYPE * TYPE##_new(void);                                         \
-    void TYPE##_init(TYPE * p);                                      \
-    void TYPE##_delete(TYPE * p);                                    \
-    void TYPE##_deleteMembers(TYPE * p);                             \
-    UA_StatusCode TYPE##_copy(const TYPE *src, TYPE *dst);           \
-    PRINTTYPE_NOEXPORT(TYPE)
+    UA_StatusCode UA_EXPORT TYPE##_copy(const TYPE *src, TYPE *dst);
 
 /* Functions for all types */
-UA_TYPE_PROTOTYPES(UA_Boolean)
-UA_TYPE_PROTOTYPES(UA_SByte)
-UA_TYPE_PROTOTYPES(UA_Byte)
-UA_TYPE_PROTOTYPES(UA_Int16)
-UA_TYPE_PROTOTYPES(UA_UInt16)
-UA_TYPE_PROTOTYPES(UA_Int32)
-UA_TYPE_PROTOTYPES(UA_UInt32)
-UA_TYPE_PROTOTYPES(UA_Int64)
-UA_TYPE_PROTOTYPES(UA_UInt64)
-UA_TYPE_PROTOTYPES(UA_Float)
-UA_TYPE_PROTOTYPES(UA_Double)
-UA_TYPE_PROTOTYPES(UA_String)
-UA_TYPE_PROTOTYPES(UA_DateTime)
-UA_TYPE_PROTOTYPES(UA_Guid)
-UA_TYPE_PROTOTYPES(UA_ByteString)
-UA_TYPE_PROTOTYPES(UA_XmlElement)
-UA_TYPE_PROTOTYPES(UA_NodeId)
-UA_TYPE_PROTOTYPES(UA_ExpandedNodeId)
-UA_TYPE_PROTOTYPES(UA_StatusCode)
-UA_TYPE_PROTOTYPES(UA_QualifiedName)
-UA_TYPE_PROTOTYPES(UA_LocalizedText)
-UA_TYPE_PROTOTYPES(UA_ExtensionObject)
-UA_TYPE_PROTOTYPES(UA_DataValue)
-UA_TYPE_PROTOTYPES(UA_Variant)
-UA_TYPE_PROTOTYPES(UA_DiagnosticInfo)
-UA_TYPE_PROTOTYPES(UA_InvalidType)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Boolean)
+UA_TYPE_HANDLING_FUNCTIONS(UA_SByte)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Byte)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Int16)
+UA_TYPE_HANDLING_FUNCTIONS(UA_UInt16)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Int32)
+UA_TYPE_HANDLING_FUNCTIONS(UA_UInt32)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Int64)
+UA_TYPE_HANDLING_FUNCTIONS(UA_UInt64)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Float)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Double)
+UA_TYPE_HANDLING_FUNCTIONS(UA_String)
+#define UA_DateTime_new UA_Int64_new
+#define UA_DateTime_init UA_Int64_init
+#define UA_DateTime_delete UA_Int64_delete
+#define UA_DateTime_deleteMembers UA_Int64_deleteMembers
+#define UA_DateTime_copy UA_Int64_copy
+UA_TYPE_HANDLING_FUNCTIONS(UA_Guid)
+#define UA_ByteString_new UA_String_new
+#define UA_ByteString_init UA_String_init
+#define UA_ByteString_delete UA_String_delete
+#define UA_ByteString_deleteMembers UA_String_deleteMembers
+#define UA_ByteString_copy UA_String_copy
+#define UA_XmlElement_new UA_String_new
+#define UA_XmlElement_init UA_String_init
+#define UA_XmlElement_delete UA_String_delete
+#define UA_XmlElement_deleteMembers UA_String_deleteMembers
+#define UA_XmlElement_copy UA_String_copy
+UA_TYPE_HANDLING_FUNCTIONS(UA_NodeId)
+UA_TYPE_HANDLING_FUNCTIONS(UA_ExpandedNodeId)
+#define UA_StatusCode_new UA_Int32_new
+#define UA_StatusCode_init UA_Int32_init
+#define UA_StatusCode_delete UA_Int32_delete
+#define UA_StatusCode_deleteMembers UA_Int32_deleteMembers
+#define UA_StatusCode_copy UA_Int32_copy
+UA_TYPE_HANDLING_FUNCTIONS(UA_QualifiedName)
+UA_TYPE_HANDLING_FUNCTIONS(UA_LocalizedText)
+UA_TYPE_HANDLING_FUNCTIONS(UA_ExtensionObject)
+UA_TYPE_HANDLING_FUNCTIONS(UA_DataValue)
+UA_TYPE_HANDLING_FUNCTIONS(UA_Variant)
+UA_TYPE_HANDLING_FUNCTIONS(UA_DiagnosticInfo)
 
 /**********************************************/
 /* Custom functions for the builtin datatypes */
 /**********************************************/
 
-/* String */
-#define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
-#define UA_STRING_STATIC(VARIABLE, STRING) do { \
-        VARIABLE.length = sizeof(STRING)-1;     \
-        VARIABLE.data   = (UA_Byte *)STRING; } while(0)
+#ifdef __cplusplus
+#define CPP_ONLY(STR) STR
+#else
+#define CPP_ONLY(STR)
+#endif
 
+/* 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);
+
+/** 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, ...);
+
+/** Compares two strings */
 UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
-#ifdef UA_DEBUG
-void UA_EXPORT UA_String_printf(char const *label, const UA_String *string);
-void UA_EXPORT UA_String_printx(char const *label, const UA_String *string);
-void UA_EXPORT UA_String_printx_hex(char const *label, const UA_String *string);
-#endif
+
+#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);
+
 typedef struct UA_DateTimeStruct {
     UA_Int16 nanoSec;
     UA_Int16 microSec;
@@ -366,92 +360,225 @@ typedef struct UA_DateTimeStruct {
     UA_Int16 month;
     UA_Int16 year;
 } UA_DateTimeStruct;
+
 UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
 UA_StatusCode UA_EXPORT UA_DateTime_toString(UA_DateTime time, UA_String *timeString);
 
 /* Guid */
+/** Compares two guids */
 UA_Boolean UA_EXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
-/** Do not use for security-critical entropy! */
+    
+/** Returns a randomly generated guid. Do not use for security-critical entropy! */
 UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
 
 /* ByteString */
-UA_Boolean UA_EXPORT UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2);
+#define UA_ByteString_equal(string1, string2) \
+    UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
+
+/** Allocates memory of size length for the bytestring. The content is not set to zero. */
 UA_StatusCode UA_EXPORT UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length);
-#ifdef UA_DEBUG
-void UA_EXPORT UA_ByteString_printf(char *label, const UA_ByteString *string);
-void UA_EXPORT UA_ByteString_printx(char *label, const UA_ByteString *string);
-void UA_EXPORT UA_ByteString_printx_hex(char *label, const UA_ByteString *string);
-#endif
 
 /* NodeId */
+/** Compares two nodeids */
 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_STATIC(NAMESPACE, NUMERICID) (UA_NodeId) {              \
+    .namespaceIndex = NAMESPACE, .identifierType = UA_NODEIDTYPE_NUMERIC, \
+    .identifier.numeric = NUMERICID }
+
+#define UA_NODEID_NULL UA_NODEID_STATIC(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 },                                    \
+        .serverIndex = 0, .namespaceUri = UA_STRING_NULL }
+    
 /* QualifiedName */
-#define UA_QUALIFIEDNAME_STATIC(VARIABLE, STRING) do { \
-        VARIABLE.namespaceIndex = 0;                   \
-        UA_STRING_STATIC(VARIABLE.name, STRING); } while(0)
 UA_StatusCode UA_EXPORT UA_QualifiedName_copycstring(char const *src, UA_QualifiedName *dst);
-#ifdef UA_DEBUG
-void UA_EXPORT UA_QualifiedName_printf(char const *label, const UA_QualifiedName *qn);
-#endif
+#define UA_QUALIFIEDNAME_ASSIGN(VARIABLE, STRING) do {          \
+        VARIABLE.namespaceIndex = 0;                            \
+        UA_STRING_ASSIGN(VARIABLE.name, STRING); } while(0)
 
 /* LocalizedText */
-#define UA_LOCALIZEDTEXT_STATIC(VARIABLE, STRING) do { \
-        UA_STRING_STATIC(VARIABLE.locale, "en");       \
-        UA_STRING_STATIC(VARIABLE.text, STRING); } while(0)
-
+/** 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);
 
 /* Variant */
-UA_StatusCode UA_EXPORT UA_Variant_copySetValue(UA_Variant *v, const UA_TypeVTable *vt, const void *value);
-UA_StatusCode UA_EXPORT UA_Variant_copySetArray(UA_Variant *v, const UA_TypeVTable *vt, UA_Int32 arrayLength, const void *array);
 
-/* Array operations */
-UA_StatusCode UA_EXPORT UA_Array_new(void **p, UA_Int32 noElements, const UA_TypeVTable *vt);
-void UA_EXPORT UA_Array_init(void *p, UA_Int32 noElements, const UA_TypeVTable *vt);
-void UA_EXPORT UA_Array_delete(void *p, UA_Int32 noElements, const UA_TypeVTable *vt);
-
-/* @brief The destination array is allocated with size noElements. */
-UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, UA_Int32 noElements, const UA_TypeVTable *vt, void **dst);
-#ifdef UA_DEBUG
-void UA_EXPORT UA_Array_print(const void *p, UA_Int32 noElements, const UA_TypeVTable *vt, FILE *stream);
-#endif
+/**
+ * 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.
+ *
+ * @param v The variant
+ * @param p A pointer to the data
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Variant_setValue(UA_Variant *v, void *p, UA_UInt16 typeIndex);
+
+/**
+ * Set the variant to a scalar value that is copied from an existing variable.
+ *
+ * @param v The variant
+ * @param p A pointer to the data
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Variant_copySetValue(UA_Variant *v, const void *p, UA_UInt16 typeIndex);
 
-/**********/
-/* VTable */
-/**********/
-
-typedef struct UA_Encoding {
-    /**  Returns the size of the encoded element.*/
-    UA_UInt32 (*calcSize)(const void *p);
-    /** Encodes the type into the destination bytestring. */
-    UA_StatusCode (*encode)(const void *src, UA_ByteString *dst, UA_UInt32 *offset);
-    /** Decodes a ByteString into an UA datatype. */
-    UA_StatusCode (*decode)(const UA_ByteString *src, UA_UInt32 *offset, void *dst);
-} UA_Encoding;
-
-#define UA_ENCODING_BINARY 0 // Binary encoding is always available
-
-struct UA_TypeVTable {
-    UA_NodeId     typeId;
-    UA_Byte       *name;
-    void *        (*new)(void);
-    void          (*init)(void *p);
-    UA_StatusCode (*copy)(void const *src, void *dst);
-    void          (*delete)(void *p);
-    void          (*deleteMembers)(void *p);
-#ifdef UA_DEBUG
-    void          (*print)(const void *p, FILE *stream);
+/**
+ * Set the variant to an array that already resides in memory. The array takes on the lifecycle of
+ * the variant and is deleted with it.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param noElements The size of the array
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @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, UA_UInt16 typeIndex);
+
+/**
+ * Set the variant to an array that is copied from an existing array.
+ *
+ * @param v The variant
+ * @param array A pointer to the array data
+ * @param noElements The size of the array
+ * @param typeIndex The index of the datatype (from namespace 0) as defined in ua_types_generated.h.
+ * For example, typeIndex == UA_TYPES_INT32
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Variant_copySetArray(UA_Variant *v, const void *array, UA_Int32 noElements, UA_UInt16 typeIndex);
+
+/****************************/
+/* Structured Type Handling */
+/****************************/
+
+#define UA_MAX_TYPE_MEMBERS 13 // Maximum number of members per complex type
+
+#ifndef _WIN32
+# define UA_BITFIELD(SIZE) : SIZE
+#else
+# define UA_BITFIELD(SIZE)
 #endif
-    UA_UInt32  memSize;                        // size of the struct
-    UA_Boolean dynMembers;                     // does the type contain members that are dynamically on the heap?
-    UA_Encoding encodings[UA_ENCODING_AMOUNT]; // binary, xml, ... UA_ENCODING_AMOUNT is set by the build script
+
+typedef struct {
+    UA_UInt16 memberTypeIndex UA_BITFIELD(9); ///< Index of the member in the datatypetable
+    UA_Boolean namespaceZero UA_BITFIELD(1); /**< The type of the member is defined in namespace
+                                                  zero. In this implementation, types from custom
+                                                  namespace may contain members from the same
+                                                  namespace or ns0 only.*/
+    UA_Byte padding UA_BITFIELD(5); /**< How much padding is there before this member element? For
+                                         arrays this is split into 2 bytes padding for for the
+                                         length index (max 4 bytes) and 3 bytes padding for the
+                                         pointer (max 8 bytes) */
+    UA_Boolean isArray UA_BITFIELD(1); ///< The member is an array of the given type
+} UA_DataTypeMember;
+    
+struct UA_DataType {
+    size_t memSize UA_BITFIELD(16); ///< Size of the struct in memory
+    size_t typeIndex UA_BITFIELD(13); ///< Index of the type in the datatytypetable
+    UA_Boolean namespaceZero UA_BITFIELD(1); ///< The type is defined in namespace zero.
+    UA_Boolean fixedSize UA_BITFIELD(1); ///< The type (and its members) contains no pointers
+    UA_Boolean zeroCopyable UA_BITFIELD(1); ///< Can the type be copied directly off the stream?
+    UA_Byte membersSize; ///< How many members does the type have?
+    UA_DataTypeMember members[UA_MAX_TYPE_MEMBERS];
 };
 
+/**
+ * Allocates and initializes a variable of type dataType
+ *
+ * @param dataType The datatype description
+ * @return Returns the memory location of the variable or (void*)0 if no memory is available
+ */
+void UA_EXPORT * UA_new(const UA_DataType *dataType);
+
+/**
+ * Initializes a variable to default values
+ *
+ * @param p The memory location of the variable
+ * @param dataType The datatype description
+ */
+void UA_EXPORT UA_init(void *p, const UA_DataType *dataType);
+
+/**
+ * Copies the content of two variables. If copying fails (e.g. because no memory was available for
+ * an array), then dst is emptied and initialized to prevent memory leaks.
+ *
+ * @param src The memory location of the source variable
+ * @param dst The memory location of the destination variable
+ * @param dataType The datatype description
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_copy(const void *src, void *dst, const UA_DataType *dataType);
+
+/**
+ * Deletes the dynamically assigned content of a variable (e.g. a member-array). Afterwards, the
+ * variable can be safely deleted without causing memory leaks. But the variable is not initialized
+ * and may contain old data that is not memory-relevant.
+ *
+ * @param p The memory location of the variable
+ * @param dataType The datatype description of the variable
+ */
+void UA_EXPORT UA_deleteMembers(void *p, const UA_DataType *dataType);
+
+/**
+ * Deletes (frees) a variable and all of its content.
+ *
+ * @param p The memory location of the variable
+ * @param dataType The datatype description of the variable
+ */
+void UA_EXPORT UA_delete(void *p, const UA_DataType *dataType);
+
+/********************/
+/* Array operations */
+/********************/
+
+#define MAX_ARRAY_SIZE 104857600 // arrays must be smaller than 100MB
+
+/**
+ * Allocates and initializes an array of variables of a specific type
+ *
+ * @param dataType The datatype description
+ * @return Returns the memory location of the variable or (void*)0 if no memory could be allocated
+ */
+void UA_EXPORT * UA_Array_new(const UA_DataType *dataType, UA_Int32 noElements);
+
+/**
+ * Allocates and copies an array. dst is set to (void*)0 if not enough memory is available.
+ *
+ * @param src The memory location of the souce array
+ * @param dst The memory location where the pointer to the destination array is written
+ * @param dataType The datatype of the array members
+ * @param noElements The size of the array
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, void **dst, const UA_DataType *dataType, UA_Int32 noElements);
+
+/**
+ * Deletes an array.
+ *
+ * @param src The memory location of the array
+ * @param dataType The datatype of the array members
+ * @param noElements The size of the array
+ */
+void UA_EXPORT UA_Array_delete(void *p, const UA_DataType *dataType, UA_Int32 noElements);
+
 /** @} */
 
 #ifdef __cplusplus

+ 3 - 5
ports/WAGO-750-860.patch

@@ -16,7 +16,7 @@ index c785182..9e66da0 100644
  
  # compiler flags
  if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
--add_definitions(-std=c99 -pedantic -pipe -Wall -Wextra -Werror -Wformat
+-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
 -                -Wshadow -Wcast-align -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wconversion
 -                -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -ffunction-sections -fdata-sections)
@@ -36,10 +36,10 @@ index c785182..9e66da0 100644
  	endif()
  endif()
  
-@@ -149,10 +149,7 @@ else()
+@@ -90,10 +90,7 @@ else()
  endif()
  
- add_library(open62541-objects OBJECT ${lib_sources}) 
+ add_library(open62541-objects OBJECT ${lib_sources})
 -add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-objects>)
 -add_library(open62541-static STATIC $<TARGET_OBJECTS:open62541-objects>)
 -SET_TARGET_PROPERTIES(open62541-static PROPERTIES OUTPUT_NAME open62541 CLEAN_DIRECT_OUTPUT 1) # static version that exports all symbols
@@ -48,6 +48,3 @@ index c785182..9e66da0 100644
  
  ## logging
  set(UA_LOGLEVEL 400 CACHE STRING "Level at which logs shall be reported")
-2.2.0
-

examples/opcuaServerMini.c → src/ongoing/opcuaServerMini.c


+ 307 - 0
src/server/ua_nodes.c

@@ -0,0 +1,307 @@
+#include "ua_nodes.h"
+#include "ua_util.h"
+
+/* UA_Node */
+static void UA_Node_init(UA_Node *p) {
+	UA_NodeId_init(&p->nodeId);
+	UA_NodeClass_init(&p->nodeClass);
+	UA_QualifiedName_init(&p->browseName);
+	UA_LocalizedText_init(&p->displayName);
+	UA_LocalizedText_init(&p->description);
+	UA_UInt32_init(&p->writeMask);
+	UA_UInt32_init(&p->userWriteMask);
+	p->referencesSize = -1;
+	p->references = UA_NULL;
+}
+
+static void UA_Node_deleteMembers(UA_Node *p) {
+	UA_NodeId_deleteMembers(&p->nodeId);
+	UA_QualifiedName_deleteMembers(&p->browseName);
+	UA_LocalizedText_deleteMembers(&p->displayName);
+	UA_LocalizedText_deleteMembers(&p->description);
+	UA_Array_delete(p->references, &UA_TYPES[UA_TYPES_REFERENCENODE], p->referencesSize);
+}
+
+static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
+	UA_StatusCode retval = UA_STATUSCODE_GOOD;
+	UA_Node_init(dst);
+	retval |= UA_NodeId_copy(&src->nodeId, &dst->nodeId);
+	dst->nodeClass = src->nodeClass;
+	retval |= UA_QualifiedName_copy(&src->browseName, &dst->browseName);
+	retval |= UA_LocalizedText_copy(&src->displayName, &dst->displayName);
+	retval |= UA_LocalizedText_copy(&src->description, &dst->description);
+	dst->writeMask = src->writeMask;
+	dst->userWriteMask = src->userWriteMask;
+	dst->referencesSize = src->referencesSize;
+	retval |= UA_Array_copy(src->references, (void**)&dst->references, &UA_TYPES[UA_TYPES_REFERENCENODE],
+                            src->referencesSize);
+	if(retval)
+    	UA_Node_deleteMembers(dst);
+	return retval;
+}
+
+/* UA_ObjectNode */
+void UA_ObjectNode_init(UA_ObjectNode *p) {
+	UA_Node_init((UA_Node*)p);
+    p->nodeClass = UA_NODECLASS_OBJECT;
+    p->eventNotifier = 0;
+}
+
+UA_ObjectNode * UA_ObjectNode_new(void) {
+    UA_ObjectNode *p = (UA_ObjectNode*)UA_malloc(sizeof(UA_ObjectNode));
+    if(p)
+        UA_ObjectNode_init(p);
+    return p;
+}
+
+void UA_ObjectNode_deleteMembers(UA_ObjectNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+}
+
+void UA_ObjectNode_delete(UA_ObjectNode *p) {
+    UA_ObjectNode_deleteMembers(p);
+    UA_free(p);
+}
+
+UA_StatusCode UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
+    dst->eventNotifier = src->eventNotifier;
+	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+}
+
+/* UA_ObjectTypeNode */
+void UA_ObjectTypeNode_init(UA_ObjectTypeNode *p) {
+	UA_Node_init((UA_Node*)p);
+    p->nodeClass = UA_NODECLASS_OBJECTTYPE;
+    p->isAbstract = UA_FALSE;
+}
+
+UA_ObjectTypeNode * UA_ObjectTypeNode_new(void) {
+    UA_ObjectTypeNode *p = (UA_ObjectTypeNode*)UA_malloc(sizeof(UA_ObjectTypeNode));
+    if(p)
+        UA_ObjectTypeNode_init(p);
+    return p;
+}
+
+void UA_ObjectTypeNode_deleteMembers(UA_ObjectTypeNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+}
+
+void UA_ObjectTypeNode_delete(UA_ObjectTypeNode *p) {
+    UA_ObjectTypeNode_deleteMembers(p);
+    UA_free(p);
+}
+
+UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
+    dst->isAbstract = src->isAbstract;
+	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+}
+
+/* UA_VariableNode */
+void UA_VariableNode_init(UA_VariableNode *p) {
+	UA_Node_init((UA_Node*)p);
+    p->nodeClass = UA_NODECLASS_VARIABLE;
+    UA_Variant_init(&p->value);
+    p->valueRank = -2; // scalar or array of any dimension
+    p->accessLevel = 0;
+    p->userAccessLevel = 0;
+    p->minimumSamplingInterval = 0.0;
+    p->historizing = UA_FALSE;
+}
+
+UA_VariableNode * UA_VariableNode_new(void) {
+    UA_VariableNode *p = (UA_VariableNode*)UA_malloc(sizeof(UA_VariableNode));
+    if(p)
+        UA_VariableNode_init(p);
+    return p;
+}
+
+void UA_VariableNode_deleteMembers(UA_VariableNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+    UA_Variant_deleteMembers(&p->value);
+}
+
+void UA_VariableNode_delete(UA_VariableNode *p) {
+    UA_VariableNode_deleteMembers(p);
+    UA_free(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);
+    retval = UA_Variant_copy(&src->value, &dst->value);
+    if(retval) {
+        UA_VariableNode_deleteMembers(dst);
+        return retval;
+    }
+    dst->accessLevel = src->accessLevel;
+    dst->userAccessLevel = src->accessLevel;
+    dst->minimumSamplingInterval = src->minimumSamplingInterval;
+    dst->historizing = src->historizing;
+    return UA_STATUSCODE_GOOD;
+}
+
+/* UA_VariableTypeNode */
+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->isAbstract = UA_FALSE;
+}
+
+UA_VariableTypeNode * UA_VariableTypeNode_new(void) {
+    UA_VariableTypeNode *p = (UA_VariableTypeNode*)UA_malloc(sizeof(UA_VariableTypeNode));
+    if(p)
+        UA_VariableTypeNode_init(p);
+    return p;
+}
+
+void UA_VariableTypeNode_deleteMembers(UA_VariableTypeNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+    UA_Variant_deleteMembers(&p->value);
+}
+
+void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
+    UA_VariableTypeNode_deleteMembers(p);
+    UA_free(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);
+    if(retval) {
+        UA_VariableTypeNode_deleteMembers(dst);
+        return retval;
+    }
+    dst->isAbstract = src->isAbstract;
+    return UA_STATUSCODE_GOOD;
+}
+
+/* UA_ReferenceTypeNode */
+void UA_ReferenceTypeNode_init(UA_ReferenceTypeNode *p) {
+	UA_Node_init((UA_Node*)p);
+    p->nodeClass = UA_NODECLASS_REFERENCETYPE;
+    p->isAbstract = UA_FALSE;
+    p->symmetric = UA_FALSE;
+    UA_LocalizedText_init(&p->inverseName);
+}
+
+UA_ReferenceTypeNode * UA_ReferenceTypeNode_new(void) {
+    UA_ReferenceTypeNode *p = (UA_ReferenceTypeNode*)UA_malloc(sizeof(UA_ReferenceTypeNode));
+    if(p)
+        UA_ReferenceTypeNode_init(p);
+    return p;
+}
+
+void UA_ReferenceTypeNode_deleteMembers(UA_ReferenceTypeNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+    UA_LocalizedText_deleteMembers(&p->inverseName);
+}
+
+void UA_ReferenceTypeNode_delete(UA_ReferenceTypeNode *p) {
+    UA_ReferenceTypeNode_deleteMembers(p);
+    UA_free(p);
+}
+
+UA_StatusCode UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src, UA_ReferenceTypeNode *dst) {
+	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+    if(retval)
+        return retval;
+    retval = UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
+    if(retval) {
+        UA_ReferenceTypeNode_deleteMembers(dst);
+        return retval;
+    }
+    dst->isAbstract = src->isAbstract;
+    dst->symmetric = src->symmetric;
+    return UA_STATUSCODE_GOOD;
+}
+
+/* UA_MethodNode */
+void UA_MethodNode_init(UA_MethodNode *p) {
+	UA_Node_init((UA_Node*)p);
+    p->nodeClass = UA_NODECLASS_METHOD;
+    p->executable = UA_FALSE;
+    p->userExecutable = UA_FALSE;
+}
+
+UA_MethodNode * UA_MethodNode_new(void) {
+    UA_MethodNode *p = (UA_MethodNode*)UA_malloc(sizeof(UA_MethodNode));
+    if(p)
+        UA_MethodNode_init(p);
+    return p;
+}
+
+void UA_MethodNode_deleteMembers(UA_MethodNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+}
+
+void UA_MethodNode_delete(UA_MethodNode *p) {
+    UA_MethodNode_deleteMembers(p);
+    UA_free(p);
+}
+
+UA_StatusCode UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
+    dst->executable = src->executable;
+    dst->userExecutable = src->userExecutable;
+	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+}
+
+/* UA_ViewNode */
+void UA_ViewNode_init(UA_ViewNode *p) {
+	UA_Node_init((UA_Node*)p);
+    p->nodeClass = UA_NODECLASS_VIEW;
+    p->containsNoLoops = UA_FALSE;
+    p->eventNotifier = 0;
+}
+
+UA_ViewNode * UA_ViewNode_new(void) {
+    UA_ViewNode *p = UA_malloc(sizeof(UA_ViewNode));
+    if(p)
+        UA_ViewNode_init(p);
+    return p;
+}
+
+void UA_ViewNode_deleteMembers(UA_ViewNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+}
+
+void UA_ViewNode_delete(UA_ViewNode *p) {
+    UA_ViewNode_deleteMembers(p);
+    UA_free(p);
+}
+
+UA_StatusCode UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
+    dst->containsNoLoops = src->containsNoLoops;
+    dst->eventNotifier = src->eventNotifier;
+	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+}
+
+/* UA_DataTypeNode */
+void UA_DataTypeNode_init(UA_DataTypeNode *p) {
+	UA_Node_init((UA_Node*)p);
+    p->nodeClass = UA_NODECLASS_DATATYPE;
+    p->isAbstract = UA_FALSE;
+}
+
+UA_DataTypeNode * UA_DataTypeNode_new(void) {
+    UA_DataTypeNode *p = UA_malloc(sizeof(UA_DataTypeNode));
+    if(p)
+        UA_DataTypeNode_init(p);
+    return p;
+}
+
+void UA_DataTypeNode_deleteMembers(UA_DataTypeNode *p) {
+    UA_Node_deleteMembers((UA_Node*)p);
+}
+
+void UA_DataTypeNode_delete(UA_DataTypeNode *p) {
+    UA_DataTypeNode_deleteMembers(p);
+    UA_free(p);
+}
+
+UA_StatusCode UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) {
+    dst->isAbstract = src->isAbstract;
+	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+}

+ 89 - 0
src/server/ua_nodes.h

@@ -0,0 +1,89 @@
+#ifndef UA_NODES_H_
+#define UA_NODES_H_
+
+#include "ua_types_generated.h"
+#include "ua_types_encoding_binary.h"
+
+#define UA_STANDARD_NODEMEMBERS                 \
+    UA_NodeId nodeId;                           \
+    UA_NodeClass nodeClass;                     \
+    UA_QualifiedName browseName;                \
+    UA_LocalizedText displayName;               \
+    UA_LocalizedText description;               \
+    UA_UInt32 writeMask;                        \
+    UA_UInt32 userWriteMask;                    \
+    UA_Int32 referencesSize;                    \
+    UA_ReferenceNode *references;
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+} UA_Node;
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Byte eventNotifier;
+} UA_ObjectNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectNode)
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Boolean isAbstract;
+} UA_ObjectTypeNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Variant value;
+    // datatype is taken from the value
+    UA_Int32 valueRank; /**< n >= 1: the value is an array with the specified number of dimensions.
+                             n = 0: the value is an array with one or more dimensions.
+                             n = -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. */
+    // array dimensions are taken from the value-variant
+    UA_Byte accessLevel;
+    UA_Byte userAccessLevel;
+    UA_Double minimumSamplingInterval;
+    UA_Boolean historizing;
+} UA_VariableNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_VariableNode)
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Variant value;
+    // datatype is taken from the value
+    UA_Int32 valueRank;
+    // array dimensions are taken from the value-variant
+    UA_Boolean isAbstract;
+} UA_VariableTypeNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Boolean isAbstract;
+    UA_Boolean symmetric;
+    UA_LocalizedText inverseName;
+} UA_ReferenceTypeNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_ReferenceTypeNode)
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Boolean executable;
+    UA_Boolean userExecutable;
+} UA_MethodNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_MethodNode)
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Boolean containsNoLoops;
+    UA_Byte eventNotifier;
+} UA_ViewNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_ViewNode)
+
+typedef struct {
+    UA_STANDARD_NODEMEMBERS
+    UA_Boolean isAbstract;
+} UA_DataTypeNode;
+UA_TYPE_HANDLING_FUNCTIONS(UA_DataTypeNode)
+
+#endif /* UA_NODES_H_ */

+ 19 - 52
src/server/ua_nodestore.c

@@ -164,9 +164,8 @@ static void deleteEntry(struct nodeEntry *entry) {
 }
 
 /** Copies the node into the entry. Then free the original node (but not its content). */
-static INLINE struct nodeEntry * nodeEntryFromNode(UA_Node *node) {
-    UA_UInt32 nodesize = 0;
-    
+static struct nodeEntry * nodeEntryFromNode(UA_Node *node) {
+    size_t nodesize = 0;
     switch(node->nodeClass) {
     case UA_NODECLASS_OBJECT:
         nodesize = sizeof(UA_ObjectNode);
@@ -241,69 +240,55 @@ void UA_NodeStore_delete(UA_NodeStore *ns) {
     UA_free(ns);
 }
 
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged) {
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node **inserted) {
     if(ns->size * 3 <= ns->count * 4) {
         if(expand(ns) != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADINTERNALERROR;
     }
     
-    /* The node is const so the user gets a const pointer back. Still, we want
-       to make small changes to the node internally, then add it to the hashmap
-       and return a new const pointer. */
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
-    UA_Node *editableNode = (UA_Node*)*node;
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
     // get a free slot
     struct nodeEntry **slot;
-    UA_NodeId *nodeId = &editableNode->nodeId;
-    if(UA_NodeId_isNull(nodeId)) {
+    if(UA_NodeId_isNull(&node->nodeId)) {
         // find a unique nodeid that is not taken
-        nodeId->identifierType = UA_NODEIDTYPE_NUMERIC;
-        nodeId->namespaceIndex = 1; // namespace 1 is always in the local nodestore
+        node->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
+        node->nodeId.namespaceIndex = 1; // namespace 1 is always in the local nodestore
         UA_Int32 identifier = ns->count+1; // start value
         UA_Int32 size = ns->size;
         hash_t increase = mod2(identifier, size);
         while(UA_TRUE) {
-            nodeId->identifier.numeric = identifier;
-            if(!containsNodeId(ns, nodeId, &slot))
+            node->nodeId.identifier.numeric = identifier;
+            if(!containsNodeId(ns, &node->nodeId, &slot))
                 break;
             identifier += increase;
             if(identifier >= size)
                 identifier -= size;
         }
     } else {
-        if(containsNodeId(ns, nodeId, &slot))
+        if(containsNodeId(ns, &node->nodeId, &slot))
             return UA_STATUSCODE_BADNODEIDEXISTS;
     }
     
-    struct nodeEntry *entry = nodeEntryFromNode(editableNode);
+    struct nodeEntry *entry = nodeEntryFromNode(node);
     if(!entry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
     *slot = entry;
     ns->count++;
 
-    if(getManaged) {
+    if(inserted) {
         entry->refcount = ALIVE_BIT + 1;
-        *node = &entry->node;
+        *inserted = &entry->node;
     } else {
         entry->refcount = ALIVE_BIT;
-        *node = UA_NULL;
     }
 
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode,
-                                   const UA_Node **node, UA_Boolean getManaged) {
+UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_Node *node,
+                                   const UA_Node **inserted) {
     struct nodeEntry **slot;
-    const UA_NodeId *nodeId = &(*node)->nodeId;
+    const UA_NodeId *nodeId = &node->nodeId;
     if(!containsNodeId(ns, nodeId, &slot))
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
@@ -312,28 +297,18 @@ UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode,
     if(&(*slot)->node != oldNode)
         return UA_STATUSCODE_BADINTERNALERROR;
 
-    /* We need to able to free the new node when copying it into the entry. */
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
-    struct nodeEntry *entry = nodeEntryFromNode((UA_Node *)*node);
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
+    struct nodeEntry *entry = nodeEntryFromNode(node);
     if(!entry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
     (*slot)->refcount &= ~ALIVE_BIT; // mark dead
     *slot = entry;
 
-    if(getManaged) {
+    if(inserted) {
         entry->refcount = ALIVE_BIT + 1;
-        *node = &entry->node;
+        *inserted = &entry->node;
     } else {
         entry->refcount = ALIVE_BIT;
-        *node = UA_NULL;
     }
     return UA_STATUSCODE_GOOD;
 }
@@ -374,15 +349,7 @@ void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visit
 void UA_NodeStore_release(const UA_Node *managed) {
     /* We know what we are doing here and remove a compiler warning. Nobody has
        a reference to the const pointer, so we can free it. */
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#pragma GCC diagnostic ignored "-Wcast-align"
-#endif
-    struct nodeEntry *entry = (struct nodeEntry *) ((UA_Byte*)managed - offsetof(struct nodeEntry, node));
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
+    struct nodeEntry *entry = (struct nodeEntry *) ((uintptr_t)managed - offsetof(struct nodeEntry, node));
     entry->refcount--;
     deleteEntry(entry);
 }

+ 11 - 10
src/server/ua_nodestore.h

@@ -2,6 +2,7 @@
 #define UA_NODESTORE_H_
 
 #include "ua_types_generated.h"
+#include "ua_nodes.h"
 
 /**
  * @ingroup server
@@ -34,20 +35,20 @@ UA_NodeStore * UA_NodeStore_new(void);
 void UA_NodeStore_delete(UA_NodeStore *ns);
 
 /**
- * Inserts a new node into the namespace. With the getManaged flag, the node
- * pointer is replaced with the managed pointer. Otherwise, it is set to
- * UA_NULL. If the nodeid is zero, then a fresh numeric nodeid from namespace 1
- * is assigned.
+ * Inserts a new node into the namespace. If the nodeid is zero, then a fresh
+ * numeric nodeid from namespace 1 is assigned. The memory of the original node
+ * is freed and the content is moved to a managed (immutable) node. If inserted
+ * is not NULL, then a pointer to the managed node is returned (and must be
+ * released).
  */
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged);
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node **inserted);
 
 /**
- * Replace an existing node in the nodestore. With the getManaged flag, the node
- * pointer is replaced with the managed pointer. Otherwise, it is set to
- * UA_NULL. If the return value is UA_STATUSCODE_BADINTERNALERROR, try again.
- * Presumably the oldNode was already replaced by another thread.
+ * Replace an existing node in the nodestore. If the node was already replaced,
+ * UA_STATUSCODE_BADINTERNALERROR is returned. If inserted is not NULL, a
+ * pointer to the managed (immutable) node is returned.
  */
-UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, const UA_Node **node, UA_Boolean getManaged);
+UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_Node *node, const UA_Node **inserted);
 
 /**
  * Remove a node from the namespace. Always succeeds, even if the node was not

+ 31 - 92
src/server/ua_nodestore_concurrent.c

@@ -66,15 +66,7 @@ static int compare(struct cds_lfht_node *htn, const void *orig) {
    section) increased the refcount, we only need to wait for the refcount
    to reach zero. */
 static void markDead(struct rcu_head *head) {
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-#endif
-    struct nodeEntry *entry = caa_container_of(head, struct nodeEntry, rcu_head);
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
+    struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)head - offsetof(struct nodeEntry, rcu_head)); 
     uatomic_and(&entry->refcount, ~ALIVE_BIT); // set the alive bit to zero
     if(uatomic_read(&entry->refcount) > 0)
         return;
@@ -85,20 +77,11 @@ static void markDead(struct rcu_head *head) {
 
 /* Free the entry if it is dead and nobody uses it anymore */
 void UA_NodeStore_release(const UA_Node *managed) {
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-#endif
-    struct nodeEntry *entry = caa_container_of(managed, struct nodeEntry, node); // pointer to the first entry
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-    if(uatomic_add_return(&entry->refcount, -1) > 0)
-        return;
-
-    node_deleteMembers(&entry->node);
-    UA_free(entry);
+    struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)managed - offsetof(struct nodeEntry, node)); 
+    if(uatomic_add_return(&entry->refcount, -1) == 0) {
+        node_deleteMembers(&entry->node);
+        UA_free(entry);
+    }
 }
 
 UA_NodeStore * UA_NodeStore_new() {
@@ -123,14 +106,7 @@ void UA_NodeStore_delete(UA_NodeStore *ns) {
     cds_lfht_first(ht, &iter);
     while(iter.node) {
         if(!cds_lfht_del(ht, iter.node)) {
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-#endif
-            struct nodeEntry *entry = caa_container_of(iter.node, struct nodeEntry, htn);
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
+            struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)iter.node - offsetof(struct nodeEntry, htn)); 
             call_rcu(&entry->rcu_head, markDead);
         }
         cds_lfht_next(ht, &iter);
@@ -141,10 +117,10 @@ void UA_NodeStore_delete(UA_NodeStore *ns) {
     UA_free(ns);
 }
 
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged) {
-    UA_UInt32 nodesize;
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node **inserted) {
+    size_t nodesize;
     /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
-    switch((*node)->nodeClass) {
+    switch(node->nodeClass) {
     case UA_NODECLASS_OBJECT:
         nodesize = sizeof(UA_ObjectNode);
         break;
@@ -176,16 +152,16 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boo
     struct nodeEntry *entry;
     if(!(entry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
         return UA_STATUSCODE_BADOUTOFMEMORY;
-    UA_memcpy((void*)&entry->node, *node, nodesize);
+    UA_memcpy((void*)&entry->node, node, nodesize);
 
     cds_lfht_node_init(&entry->htn);
     entry->refcount = ALIVE_BIT;
-    if(getManaged) // increase the counter before adding the node
+    if(inserted) // increase the counter before adding the node
         entry->refcount++;
 
     struct cds_lfht_node *result;
-    if(!UA_NodeId_isNull(&(*node)->nodeId)) {
-        hash_t h = hash(&(*node)->nodeId);
+    if(!UA_NodeId_isNull(&node->nodeId)) {
+        hash_t h = hash(&node->nodeId);
         rcu_read_lock();
         result = cds_lfht_add_unique(ns->ht, h, compare, &entry->node.nodeId, &entry->htn);
         rcu_read_unlock();
@@ -217,27 +193,17 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boo
         rcu_read_unlock();
     }
 
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
-    UA_free((UA_Node *)*node);     /* The old node is replaced by a managed node. */
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-    if(getManaged)
-        *node = &entry->node;
-    else
-        *node = UA_NULL;
+    UA_free(node);
+    if(inserted)
+        *inserted = &entry->node;
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode,
-                                   const UA_Node **node, UA_Boolean getManaged) {
-    UA_UInt32 nodesize;
+UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_Node *node,
+                                   const UA_Node **inserted) {
+    size_t nodesize;
     /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
-    switch((*node)->nodeClass) {
+    switch(node->nodeClass) {
     case UA_NODECLASS_OBJECT:
         nodesize = sizeof(UA_ObjectNode);
         break;
@@ -269,18 +235,17 @@ UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode,
     struct nodeEntry *newEntry;
     if(!(newEntry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
         return UA_STATUSCODE_BADOUTOFMEMORY;
-    UA_memcpy((void*)&newEntry->node, *node, nodesize);
+    UA_memcpy((void*)&newEntry->node, node, nodesize);
 
     cds_lfht_node_init(&newEntry->htn);
     newEntry->refcount = ALIVE_BIT;
-    if(getManaged) // increase the counter before adding the node
+    if(inserted) // increase the counter before adding the node
         newEntry->refcount++;
 
-    hash_t h = hash(&(*node)->nodeId);
-
+    hash_t h = hash(&node->nodeId);
     struct cds_lfht_iter iter;
     rcu_read_lock();
-    cds_lfht_lookup(ns->ht, h, compare, &(*node)->nodeId, &iter);
+    cds_lfht_lookup(ns->ht, h, compare, &node->nodeId, &iter);
 
     /* No node found that can be replaced */
     if(!iter.node) {
@@ -289,14 +254,7 @@ UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode,
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
     }
 
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-#endif
-    struct nodeEntry *oldEntry = caa_container_of(iter.node, struct nodeEntry, htn);
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
+    struct nodeEntry *oldEntry = (struct nodeEntry*) ((uintptr_t)iter.node - offsetof(struct nodeEntry, htn)); 
     /* The node we found is obsolete*/
     if(&oldEntry->node != oldNode) {
         rcu_read_unlock();
@@ -305,7 +263,7 @@ UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode,
     }
 
     /* The old node is replaced by a managed node. */
-    if(cds_lfht_replace(ns->ht, &iter, h, compare, &(*node)->nodeId, &newEntry->htn) != 0) {
+    if(cds_lfht_replace(ns->ht, &iter, h, compare, &node->nodeId, &newEntry->htn) != 0) {
         /* Replacing failed. Maybe the node got replaced just before this thread tried to.*/
         rcu_read_unlock();
         UA_free(newEntry);
@@ -315,21 +273,10 @@ UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode,
     /* If an entry got replaced, mark it as dead. */
     call_rcu(&oldEntry->rcu_head, markDead);
     rcu_read_unlock();
+    UA_free(node);
 
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#endif
-    UA_free((UA_Node *)*node); // was copied to newEntry and is obsolete
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-    if(getManaged)
-        *node = &newEntry->node;
-    else
-        *node = UA_NULL;
-
+    if(inserted)
+        *inserted = &newEntry->node;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -345,15 +292,7 @@ UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
     }
 
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
-#endif
-    struct nodeEntry *entry = caa_container_of(iter.node, struct nodeEntry, htn);
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
+    struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)iter.node - offsetof(struct nodeEntry, htn)); 
     call_rcu(&entry->rcu_head, markDead);
     rcu_read_unlock();
 

+ 2 - 2
src/server/ua_nodestore_hash.inc

@@ -1,7 +1,7 @@
 typedef UA_UInt32 hash_t;
 
-static INLINE hash_t mod(hash_t h, hash_t size) { return h % size; }
-static INLINE hash_t mod2(hash_t h, hash_t size) { return 1 + (h % (size - 2)); }
+static hash_t mod(hash_t h, hash_t size) { return h % size; }
+static hash_t mod2(hash_t h, hash_t size) { return 1 + (h % (size - 2)); }
 
 /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
 static hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {

+ 3 - 0
src/server/ua_securechannel_manager.c

@@ -62,6 +62,9 @@ UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager           *cm
     if(!entry) return UA_STATUSCODE_BADOUTOFMEMORY;
     UA_SecureChannel_init(&entry->channel);
 
+    response->responseHeader.stringTableSize = 0;
+    response->responseHeader.timestamp       = UA_DateTime_now();
+
     entry->channel.connection = conn;
     conn->channel = &entry->channel;
     entry->channel.securityToken.channelId       = cm->lastChannelId++;

+ 1 - 0
src/server/ua_securechannel_manager.h

@@ -1,6 +1,7 @@
 #ifndef UA_CHANNEL_MANAGER_H_
 #define UA_CHANNEL_MANAGER_H_
 
+#include "../deps/queue.h"
 #include "ua_server.h"
 #include "ua_securechannel.h"
 #include "ua_util.h"

+ 146 - 125
src/server/ua_server.c

@@ -1,15 +1,15 @@
 #ifdef UA_MULTITHREADING
 #define _LGPL_SOURCE
 #include <urcu.h>
-//#include <urcu-call-rcu.h>
 #endif
 
+#include "ua_types.h"
 #include "ua_server_internal.h"
-#include "ua_namespace_0.h"
 #include "ua_securechannel_manager.h"
 #include "ua_session_manager.h"
 #include "ua_util.h"
 #include "ua_services.h"
+#include "ua_nodeids.h"
 
 /**********************/
 /* Namespace Handling */
@@ -22,7 +22,7 @@ static void UA_ExternalNamespace_init(UA_ExternalNamespace *ens) {
 
 static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
 	UA_String_deleteMembers(&ens->url);
-    ens->externalNodeStore.delete(ens->externalNodeStore.ensHandle);
+    ens->externalNodeStore.destroy(ens->externalNodeStore.ensHandle);
 }
 
 /*****************/
@@ -61,7 +61,7 @@ void UA_Server_delete(UA_Server *server) {
     UA_SessionManager_deleteMembers(&server->sessionManager);
     UA_NodeStore_delete(server->nodestore);
     UA_ByteString_deleteMembers(&server->serverCertificate);
-    UA_Array_delete(server->endpointDescriptions, server->endpointDescriptionsSize, &UA_TYPES[UA_ENDPOINTDESCRIPTION]);
+    UA_Array_delete(server->endpointDescriptions, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], server->endpointDescriptionsSize);
 #ifdef UA_MULTITHREADING
     pthread_cond_destroy(&server->dispatchQueue_condition); // so the workers don't spin if the queue is empty
     rcu_barrier(); // wait for all scheduled call_rcu work to complete
@@ -123,7 +123,7 @@ UA_Server * UA_Server_new(void) {
 
 #define MAXCHANNELCOUNT 100
 #define STARTCHANNELID 1
-#define TOKENLIFETIME 10000
+#define TOKENLIFETIME 600000
 #define STARTTOKENID 1
     UA_SecureChannelManager_init(&server->secureChannelManager, MAXCHANNELCOUNT,
                                  TOKENLIFETIME, STARTCHANNELID, STARTTOKENID);
@@ -135,7 +135,7 @@ UA_Server * UA_Server_new(void) {
 
     server->nodestore = UA_NodeStore_new();
 
-#define ADDREFERENCE(NODEID, REFTYPE_NODEID, TARGET_EXPNODEID) do { \
+#define ADDREFERENCE(NODEID, REFTYPE_NODEID, TARGET_EXPNODEID) do {     \
         UA_AddReferencesItem item;                                      \
         UA_AddReferencesItem_init(&item);                               \
         item.sourceNodeId = NODEID;                                     \
@@ -158,316 +158,334 @@ UA_Server * UA_Server_new(void) {
     /* bootstrap by manually inserting "references" and "hassubtype" */
     UA_ReferenceTypeNode *references = UA_ReferenceTypeNode_new();
     COPYNAMES(references, "References");
-    references->nodeId     = UA_NODEIDS[UA_REFERENCES];
+    references->nodeId.identifier.numeric = UA_NS0ID_REFERENCES;
     references->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     references->isAbstract = UA_TRUE;
     references->symmetric  = UA_TRUE;
     // this node has no parent??
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&references, UA_FALSE);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)references, UA_NULL);
 
     UA_ReferenceTypeNode *hassubtype = UA_ReferenceTypeNode_new();
     COPYNAMES(hassubtype, "HasSubtype");
     UA_LocalizedText_copycstring("SubtypeOf", &hassubtype->inverseName);
-    hassubtype->nodeId     = UA_NODEIDS[UA_HASSUBTYPE];
+    hassubtype->nodeId.identifier.numeric = UA_NS0ID_HASSUBTYPE;
     hassubtype->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hassubtype->isAbstract = UA_FALSE;
     hassubtype->symmetric  = UA_FALSE;
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&hassubtype, UA_FALSE);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)hassubtype, UA_NULL);
 
     /* continue adding reference types with normal "addnode" */
     UA_ReferenceTypeNode *hierarchicalreferences = UA_ReferenceTypeNode_new();
     COPYNAMES(hierarchicalreferences, "Hierarchicalreferences");
-    hierarchicalreferences->nodeId     = UA_NODEIDS[UA_HIERARCHICALREFERENCES];
+    hierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_HIERARCHICALREFERENCES;
     hierarchicalreferences->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node**)&hierarchicalreferences,
-                      &UA_EXPANDEDNODEIDS[UA_REFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hierarchicalreferences,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_REFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
     COPYNAMES(nonhierarchicalreferences, "NonHierarchicalReferences");
-    nonhierarchicalreferences->nodeId     = UA_NODEIDS[UA_NONHIERARCHICALREFERENCES];
+    nonhierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_NONHIERARCHICALREFERENCES;
     nonhierarchicalreferences->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&nonhierarchicalreferences,
-                      &UA_EXPANDEDNODEIDS[UA_REFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)nonhierarchicalreferences,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_REFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
     COPYNAMES(haschild, "HasChild");
-    haschild->nodeId     = UA_NODEIDS[UA_HASCHILD];
+    haschild->nodeId.identifier.numeric = UA_NS0ID_HASCHILD;
     haschild->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     haschild->isAbstract = UA_TRUE;
     haschild->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&haschild,
-                      &UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)haschild,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
     COPYNAMES(organizes, "Organizes");
     UA_LocalizedText_copycstring("OrganizedBy", &organizes->inverseName);
-    organizes->nodeId     = UA_NODEIDS[UA_ORGANIZES];
+    organizes->nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     organizes->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     organizes->isAbstract = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&organizes,
-                      &UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)organizes,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
     COPYNAMES(haseventsource, "HasEventSource");
     UA_LocalizedText_copycstring("EventSourceOf", &haseventsource->inverseName);
-    haseventsource->nodeId     = UA_NODEIDS[UA_HASEVENTSOURCE];
+    haseventsource->nodeId.identifier.numeric = UA_NS0ID_HASEVENTSOURCE;
     haseventsource->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     haseventsource->isAbstract = UA_FALSE;
     haseventsource->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&haseventsource,
-                      &UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)haseventsource,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
     COPYNAMES(hasmodellingrule, "HasModellingRule");
     UA_LocalizedText_copycstring("ModellingRuleOf", &hasmodellingrule->inverseName);
-    hasmodellingrule->nodeId     = UA_NODEIDS[UA_HASMODELLINGRULE];
+    hasmodellingrule->nodeId.identifier.numeric = UA_NS0ID_HASMODELLINGRULE;
     hasmodellingrule->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasmodellingrule->isAbstract = UA_FALSE;
     hasmodellingrule->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hasmodellingrule,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hasmodellingrule,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
     COPYNAMES(hasencoding, "HasEncoding");
     UA_LocalizedText_copycstring("EncodingOf", &hasencoding->inverseName);
-    hasencoding->nodeId     = UA_NODEIDS[UA_HASENCODING];
+    hasencoding->nodeId.identifier.numeric = UA_NS0ID_HASENCODING;
     hasencoding->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasencoding->isAbstract = UA_FALSE;
     hasencoding->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hasencoding,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hasencoding,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
     COPYNAMES(hasdescription, "HasDescription");
     UA_LocalizedText_copycstring("DescriptionOf", &hasdescription->inverseName);
-    hasdescription->nodeId     = UA_NODEIDS[UA_HASDESCRIPTION];
+    hasdescription->nodeId.identifier.numeric = UA_NS0ID_HASDESCRIPTION;
     hasdescription->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasdescription->isAbstract = UA_FALSE;
     hasdescription->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hasdescription,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hasdescription,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
     COPYNAMES(hastypedefinition, "HasTypeDefinition");
     UA_LocalizedText_copycstring("TypeDefinitionOf", &hastypedefinition->inverseName);
-    hastypedefinition->nodeId     = UA_NODEIDS[UA_HASTYPEDEFINITION];
+    hastypedefinition->nodeId.identifier.numeric = UA_NS0ID_HASTYPEDEFINITION;
     hastypedefinition->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hastypedefinition->isAbstract = UA_FALSE;
     hastypedefinition->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hastypedefinition,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hastypedefinition,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
     COPYNAMES(generatesevent, "GeneratesEvent");
     UA_LocalizedText_copycstring("GeneratedBy", &generatesevent->inverseName);
-    generatesevent->nodeId     = UA_NODEIDS[UA_GENERATESEVENT];
+    generatesevent->nodeId.identifier.numeric = UA_NS0ID_GENERATESEVENT;
     generatesevent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     generatesevent->isAbstract = UA_FALSE;
     generatesevent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&generatesevent,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)generatesevent,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
     COPYNAMES(aggregates, "Aggregates");
     // Todo: Is there an inverse name?
-    aggregates->nodeId     = UA_NODEIDS[UA_AGGREGATES];
+    aggregates->nodeId.identifier.numeric = UA_NS0ID_AGGREGATES;
     aggregates->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     aggregates->isAbstract = UA_TRUE;
     aggregates->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&aggregates,
-                      &UA_EXPANDEDNODEIDS[UA_HASCHILD], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)aggregates,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASCHILD),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     // complete bootstrap of hassubtype
-    ADDREFERENCE(UA_NODEIDS[UA_HASCHILD], UA_NODEIDS[UA_HASSUBTYPE],
-                 UA_EXPANDEDNODEIDS[UA_HASSUBTYPE]);
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_HASCHILD), UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
     COPYNAMES(hasproperty, "HasProperty");
     UA_LocalizedText_copycstring("PropertyOf", &hasproperty->inverseName);
-    hasproperty->nodeId     = UA_NODEIDS[UA_HASPROPERTY];
+    hasproperty->nodeId.identifier.numeric = UA_NS0ID_HASPROPERTY;
     hasproperty->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasproperty->isAbstract = UA_FALSE;
     hasproperty->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hasproperty,
-                      &UA_EXPANDEDNODEIDS[UA_AGGREGATES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hasproperty,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_AGGREGATES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
     COPYNAMES(hascomponent, "HasComponent");
     UA_LocalizedText_copycstring("ComponentOf", &hascomponent->inverseName);
-    hascomponent->nodeId     = UA_NODEIDS[UA_HASCOMPONENT];
+    hascomponent->nodeId.identifier.numeric = UA_NS0ID_HASCOMPONENT;
     hascomponent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hascomponent->isAbstract = UA_FALSE;
     hascomponent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hascomponent,
-                      &UA_EXPANDEDNODEIDS[UA_AGGREGATES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hascomponent,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_AGGREGATES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
     COPYNAMES(hasnotifier, "HasNotifier");
     UA_LocalizedText_copycstring("NotifierOf", &hasnotifier->inverseName);
-    hasnotifier->nodeId     = UA_NODEIDS[UA_HASNOTIFIER];
+    hasnotifier->nodeId.identifier.numeric = UA_NS0ID_HASNOTIFIER;
     hasnotifier->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasnotifier->isAbstract = UA_FALSE;
     hasnotifier->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hasnotifier,
-                      &UA_EXPANDEDNODEIDS[UA_HASEVENTSOURCE], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hasnotifier,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASEVENTSOURCE),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
     COPYNAMES(hasorderedcomponent, "HasOrderedComponent");
     UA_LocalizedText_copycstring("OrderedComponentOf", &hasorderedcomponent->inverseName);
-    hasorderedcomponent->nodeId     = UA_NODEIDS[UA_HASORDEREDCOMPONENT];
+    hasorderedcomponent->nodeId.identifier.numeric = UA_NS0ID_HASORDEREDCOMPONENT;
     hasorderedcomponent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasorderedcomponent->isAbstract = UA_FALSE;
     hasorderedcomponent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hasorderedcomponent,
-                      &UA_EXPANDEDNODEIDS[UA_HASCOMPONENT], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hasorderedcomponent,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
     COPYNAMES(hasmodelparent, "HasModelParent");
     UA_LocalizedText_copycstring("ModelParentOf", &hasmodelparent->inverseName);
-    hasmodelparent->nodeId     = UA_NODEIDS[UA_HASMODELPARENT];
+    hasmodelparent->nodeId.identifier.numeric = UA_NS0ID_HASMODELPARENT;
     hasmodelparent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasmodelparent->isAbstract = UA_FALSE;
     hasmodelparent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hasmodelparent,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hasmodelparent,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
     COPYNAMES(fromstate, "FromState");
     UA_LocalizedText_copycstring("ToTransition", &fromstate->inverseName);
-    fromstate->nodeId     = UA_NODEIDS[UA_FROMSTATE];
+    fromstate->nodeId.identifier.numeric = UA_NS0ID_FROMSTATE;
     fromstate->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     fromstate->isAbstract = UA_FALSE;
     fromstate->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&fromstate,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)fromstate,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
     COPYNAMES(tostate, "ToState");
     UA_LocalizedText_copycstring("FromTransition", &tostate->inverseName);
-    tostate->nodeId     = UA_NODEIDS[UA_TOSTATE];
+    tostate->nodeId.identifier.numeric = UA_NS0ID_TOSTATE;
     tostate->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     tostate->isAbstract = UA_FALSE;
     tostate->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&tostate,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)tostate,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
     COPYNAMES(hascause, "HasCause");
     UA_LocalizedText_copycstring("MayBeCausedBy", &hascause->inverseName);
-    hascause->nodeId     = UA_NODEIDS[UA_HASCAUSE];
+    hascause->nodeId.identifier.numeric = UA_NS0ID_HASCAUSE;
     hascause->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hascause->isAbstract = UA_FALSE;
     hascause->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hascause,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
-
+    UA_Server_addNode(server, (UA_Node*)hascause,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
+    
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
     COPYNAMES(haseffect, "HasEffect");
     UA_LocalizedText_copycstring("MayBeEffectedBy", &haseffect->inverseName);
-    haseffect->nodeId     = UA_NODEIDS[UA_HASEFFECT];
+    haseffect->nodeId.identifier.numeric = UA_NS0ID_HASEFFECT;
     haseffect->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     haseffect->isAbstract = UA_FALSE;
     haseffect->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&haseffect,
-                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)haseffect,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
     COPYNAMES(hashistoricalconfiguration, "HasHistoricalConfiguration");
     UA_LocalizedText_copycstring("HistoricalConfigurationOf", &hashistoricalconfiguration->inverseName);
-    hashistoricalconfiguration->nodeId     = UA_NODEIDS[UA_HASHISTORICALCONFIGURATION];
+    hashistoricalconfiguration->nodeId.identifier.numeric = UA_NS0ID_HASHISTORICALCONFIGURATION;
     hashistoricalconfiguration->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hashistoricalconfiguration->isAbstract = UA_FALSE;
     hashistoricalconfiguration->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&hashistoricalconfiguration,
-                      &UA_EXPANDEDNODEIDS[UA_AGGREGATES], &UA_NODEIDS[UA_HASSUBTYPE]);
+    UA_Server_addNode(server, (UA_Node*)hashistoricalconfiguration,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_AGGREGATES),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     /***********/
     /* Objects */
     /***********/
     
     UA_ObjectNode *folderType = UA_ObjectNode_new();
-    folderType->nodeId    = UA_NODEIDS[UA_FOLDERTYPE];
+    folderType->nodeId.identifier.numeric = UA_NS0ID_FOLDERTYPE;
     folderType->nodeClass = UA_NODECLASS_OBJECTTYPE;
     COPYNAMES(folderType, "FolderType");
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&folderType, UA_FALSE);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)folderType, UA_NULL);
 
     UA_ObjectNode *root = UA_ObjectNode_new();
     COPYNAMES(root, "Root");
-    root->nodeId    = UA_NODEIDS[UA_ROOTFOLDER];
+    root->nodeId.identifier.numeric = UA_NS0ID_ROOTFOLDER;
     root->nodeClass = UA_NODECLASS_OBJECT;
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&root, UA_FALSE);
-    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
-                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
-    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_ORGANIZES],
-                 UA_EXPANDEDNODEIDS[UA_OBJECTSFOLDER]);
-    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_ORGANIZES],
-                 UA_EXPANDEDNODEIDS[UA_TYPESFOLDER]);
-    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_ORGANIZES],
-                 UA_EXPANDEDNODEIDS[UA_VIEWSFOLDER]);
+    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_STATIC(0, UA_NS0ID_ROOTFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER));
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_ROOTFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_TYPESFOLDER));
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_ROOTFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_VIEWSFOLDER));
 
     UA_ObjectNode *objects = UA_ObjectNode_new();
     COPYNAMES(objects, "Objects");
-    objects->nodeId    = UA_NODEIDS[UA_OBJECTSFOLDER];
+    objects->nodeId.identifier.numeric = UA_NS0ID_OBJECTSFOLDER;
     objects->nodeClass = UA_NODECLASS_OBJECT;
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&objects, UA_FALSE);
-    ADDREFERENCE(UA_NODEIDS[UA_OBJECTSFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
-                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
-    ADDREFERENCE(UA_NODEIDS[UA_OBJECTSFOLDER], UA_NODEIDS[UA_ORGANIZES], UA_EXPANDEDNODEIDS[UA_SERVER]);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)objects, UA_NULL);
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER));
 
     UA_ObjectNode *types = UA_ObjectNode_new();
     COPYNAMES(types, "Types");
-    types->nodeId    = UA_NODEIDS[UA_TYPESFOLDER];
+    types->nodeId.identifier.numeric = UA_NS0ID_TYPESFOLDER;
     types->nodeClass = UA_NODECLASS_OBJECT;
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&types, UA_FALSE);
-    ADDREFERENCE(UA_NODEIDS[UA_TYPESFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
-                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)types, UA_NULL);
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_TYPESFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *views = UA_ObjectNode_new();
     COPYNAMES(views, "Views");
-    views->nodeId    = UA_NODEIDS[UA_VIEWSFOLDER];
+    views->nodeId.identifier.numeric = UA_NS0ID_VIEWSFOLDER;
     views->nodeClass = UA_NODECLASS_OBJECT;
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&views, UA_FALSE);
-    ADDREFERENCE(UA_NODEIDS[UA_VIEWSFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
-                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)views, UA_NULL);
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *servernode = UA_ObjectNode_new();
     COPYNAMES(servernode, "Server");
-    servernode->nodeId    = UA_NODEIDS[UA_SERVER];
+    servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
     servernode->nodeClass = UA_NODECLASS_OBJECT;
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&servernode, UA_FALSE);
-    ADDREFERENCE(UA_NODEIDS[UA_SERVER], UA_NODEIDS[UA_HASCOMPONENT],
-                 UA_EXPANDEDNODEIDS[UA_SERVER_SERVERCAPABILITIES]);
-    ADDREFERENCE(UA_NODEIDS[UA_SERVER], UA_NODEIDS[UA_HASPROPERTY], UA_EXPANDEDNODEIDS[UA_SERVER_SERVERARRAY]);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)servernode, UA_NULL);
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER), UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES));
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER), UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERARRAY));
 
     UA_VariableNode *namespaceArray = UA_VariableNode_new();
     COPYNAMES(namespaceArray, "NamespaceArray");
-    namespaceArray->nodeId    = UA_NODEIDS[UA_SERVER_NAMESPACEARRAY];
+    namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
     namespaceArray->nodeClass = UA_NODECLASS_VARIABLE;
-    UA_Array_new(&namespaceArray->value.storage.data.dataPtr, 2, &UA_TYPES[UA_STRING]);
-    namespaceArray->value.vt = &UA_TYPES[UA_STRING];
+    namespaceArray->value.storage.data.dataPtr = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
     namespaceArray->value.storage.data.arrayLength = 2;
+    namespaceArray->value.type = &UA_TYPES[UA_TYPES_STRING];
+    namespaceArray->value.typeId.identifier.numeric = UA_TYPES_IDS[UA_TYPES_STRING];
     // Fixme: Insert the external namespaces
     UA_String_copycstring("http://opcfoundation.org/UA/",
                           &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[0]);
     UA_String_copycstring("urn:myServer:myApplication",
                           &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[1]);
-    UA_UInt32 *dimensions = UA_malloc(sizeof(UA_UInt32));
-    if(dimensions) {
-        *dimensions = 2;
-        namespaceArray->arrayDimensions = dimensions;
-        namespaceArray->arrayDimensionsSize = 1;
-    }
-    namespaceArray->dataType = UA_NODEIDS[UA_STRING];
     namespaceArray->valueRank = 1;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->historizing = UA_FALSE;
-    UA_Server_addNode(server, (const UA_Node **)&namespaceArray,
-                      &UA_EXPANDEDNODEIDS[UA_SERVER], &UA_NODEIDS[UA_HASCOMPONENT]);
+    UA_Server_addNode(server, (UA_Node*)namespaceArray,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
 
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     status->startTime   = UA_DateTime_now();
@@ -483,25 +501,28 @@ UA_Server * UA_Server_new(void) {
     UA_LocalizedText_copycstring("because", &status->shutdownReason);
     UA_VariableNode *serverstatus = UA_VariableNode_new();
     COPYNAMES(serverstatus, "ServerStatus");
-    serverstatus->nodeId    = UA_NODEIDS[UA_SERVER_SERVERSTATUS];
+    serverstatus->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS;
     serverstatus->nodeClass = UA_NODECLASS_VARIABLE;
-    serverstatus->value.vt = &UA_TYPES[UA_SERVERSTATUSDATATYPE]; // gets encoded as an extensionobject
+    serverstatus->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
+    serverstatus->value.typeId.identifier.numeric = UA_TYPES_IDS[UA_TYPES_SERVERSTATUSDATATYPE];
     serverstatus->value.storage.data.arrayLength = 1;
     serverstatus->value.storage.data.dataPtr = status;
-    UA_Server_addNode(server, (const UA_Node **)&serverstatus,
-                      &UA_EXPANDEDNODEIDS[UA_SERVER], &UA_NODEIDS[UA_HASPROPERTY]);
+    UA_Server_addNode(server, (UA_Node*)serverstatus,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
 
     // todo: make this variable point to a member of the serverstatus
     UA_VariableNode *state = UA_VariableNode_new();
     UA_ServerState *stateEnum = UA_ServerState_new();
     *stateEnum = UA_SERVERSTATE_RUNNING;
     COPYNAMES(state, "State");
-    state->nodeId    = UA_NODEIDS[UA_SERVER_SERVERSTATUS_STATE];
+    state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
     state->nodeClass = UA_NODECLASS_VARIABLE;
-    state->value.vt = &UA_TYPES[UA_SERVERSTATE];
+    state->value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
+    state->value.typeId.identifier.numeric = UA_TYPES_IDS[UA_TYPES_SERVERSTATE];
     state->value.storage.data.arrayLength = 1;
     state->value.storage.data.dataPtr = stateEnum; // points into the other object.
     state->value.storageType = UA_VARIANT_DATA;
-    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&state, UA_FALSE);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)state, UA_NULL);
     return server;
 }

+ 83 - 59
src/server/ua_server_addressspace.c

@@ -1,45 +1,26 @@
 #include "ua_server.h"
 #include "ua_server_internal.h"
-#include "ua_namespace_0.h"
 
-static const UA_TypeVTable * UA_Node_getTypeVT(const UA_Node *node) {
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        return &UA_TYPES[UA_OBJECTNODE];
-    case UA_NODECLASS_VARIABLE:
-        return &UA_TYPES[UA_VARIABLENODE];
-    case UA_NODECLASS_METHOD:
-        return &UA_TYPES[UA_METHODNODE];
-    case UA_NODECLASS_OBJECTTYPE:
-        return &UA_TYPES[UA_OBJECTTYPENODE];
-    case UA_NODECLASS_VARIABLETYPE:
-        return &UA_TYPES[UA_VARIABLETYPENODE];
-    case UA_NODECLASS_REFERENCETYPE:
-        return &UA_TYPES[UA_REFERENCETYPENODE];
-    case UA_NODECLASS_DATATYPE:
-        return &UA_TYPES[UA_DATATYPENODE];
-    case UA_NODECLASS_VIEW:
-        return &UA_TYPES[UA_VIEWNODE];
-    default: break;
+UA_StatusCode UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, UA_NodeId *nodeId,
+                                        UA_QualifiedName *browseName, const UA_NodeId *parentNodeId,
+                                        const UA_NodeId *referenceTypeId) {
+    UA_VariableNode *node = UA_VariableNode_new();
+    node->value = *value; // copy content
+    UA_NodeId_copy(nodeId, &node->nodeId);
+    UA_QualifiedName_copy(browseName, &node->browseName);
+    UA_String_copy(&browseName->name, &node->displayName.text);
+    UA_ExpandedNodeId parentId; // we need an expandednodeid
+    UA_ExpandedNodeId_init(&parentId);
+    parentId.nodeId = *parentNodeId;
+    UA_AddNodesResult res = UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node,
+                                                         &parentId, referenceTypeId);
+    if(res.statusCode != UA_STATUSCODE_GOOD) {
+        UA_Variant_init(&node->value);
+        UA_VariableNode_delete(node);
+    } else {
+        UA_free(value);
     }
-
-    return &UA_TYPES[UA_INVALIDTYPE];
-}
-
-void UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
-                                     const UA_TypeVTable *vt, const UA_ExpandedNodeId *parentNodeId,
-                                     const UA_NodeId *referenceTypeId) {
-    UA_VariableNode *tmpNode = UA_VariableNode_new();
-    UA_QualifiedName_copy(browseName, &tmpNode->browseName);
-    UA_String_copy(&browseName->name, &tmpNode->displayName.text);
-    /* UA_LocalizedText_copycstring("integer value", &tmpNode->description); */
-    tmpNode->nodeClass = UA_NODECLASS_VARIABLE;
-    tmpNode->valueRank = -1;
-    tmpNode->value.vt = vt;
-    tmpNode->value.storage.data.dataPtr = value;
-    tmpNode->value.storageType = UA_VARIANT_DATA;
-    tmpNode->value.storage.data.arrayLength = 1;
-    UA_Server_addNode(server, (const UA_Node**)&tmpNode, parentNodeId, referenceTypeId);
+    return res.statusCode;
 }
 
 /* Adds a one-way reference to the local nodestore */
@@ -51,9 +32,52 @@ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session
     if(!node)
         return UA_STATUSCODE_BADINTERNALERROR;
 
-    const UA_TypeVTable *nodeVT = UA_Node_getTypeVT(node);
-    UA_Node *newNode = nodeVT->new();
-    nodeVT->copy(node, newNode);
+    UA_Node *newNode = UA_NULL;
+    void (*deleteNode)(UA_Node*) = UA_NULL;
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        newNode = (UA_Node*)UA_ObjectNode_new();
+        UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete;
+        break;
+    case UA_NODECLASS_VARIABLE:
+        newNode = (UA_Node*)UA_VariableNode_new();
+        UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete;
+        break;
+    case UA_NODECLASS_METHOD:
+        newNode = (UA_Node*)UA_MethodNode_new();
+        UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete;
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        newNode = (UA_Node*)UA_ObjectTypeNode_new();
+        UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete;
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        newNode = (UA_Node*)UA_VariableTypeNode_new();
+        UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete;
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        newNode = (UA_Node*)UA_ReferenceTypeNode_new();
+        UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete;
+        break;
+    case UA_NODECLASS_DATATYPE:
+        newNode = (UA_Node*)UA_DataTypeNode_new();
+        UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete;
+        break;
+    case UA_NODECLASS_VIEW:
+        newNode = (UA_Node*)UA_ViewNode_new();
+        UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode*)newNode);
+        deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
+        break;
+    default:
+        UA_assert(UA_FALSE);
+    }
 
     UA_Int32 count = node->referencesSize;
     if(count < 0)
@@ -61,7 +85,7 @@ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session
     UA_ReferenceNode *old_refs = newNode->references;
     UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1));
     if(!new_refs) {
-        nodeVT->delete(newNode);
+        deleteNode(newNode);
         UA_NodeStore_release(node);
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
@@ -73,10 +97,10 @@ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session
     new_refs[count].isInverse = !item->isForward;
     retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Array_delete(new_refs, ++count, &UA_TYPES[UA_REFERENCENODE]);
+        UA_Array_delete(new_refs, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count);
         newNode->references = UA_NULL;
         newNode->referencesSize = 0;
-        nodeVT->delete(newNode);
+        deleteNode(newNode);
         UA_NodeStore_release(node);
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
@@ -84,15 +108,14 @@ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session
     UA_free(old_refs);
     newNode->references = new_refs;
     newNode->referencesSize = ++count;
-    const UA_Node *constNode = newNode;
-    retval = UA_NodeStore_replace(server->nodestore, node, (const UA_Node **)&constNode, UA_FALSE);
+    retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
     UA_NodeStore_release(node);
     if(retval != UA_STATUSCODE_BADINTERNALERROR)
         return retval;
     
     // error presumably because the node was replaced and an old version was updated
     // just try again
-    nodeVT->delete(newNode);
+    deleteNode(newNode);
     return addOneWayReferenceWithSession(server, session, item);
 }
 
@@ -138,13 +161,14 @@ UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *s
     return retval;
 } 
 
-UA_AddNodesResult UA_Server_addNode(UA_Server *server, const UA_Node **node,
-                                    const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
+UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId *parentNodeId,
+                                    const UA_NodeId *referenceTypeId) {
     return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
 }
 
-UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, const UA_Node **node,
-                                               const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
+UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
+                                               const UA_ExpandedNodeId *parentNodeId,
+                                               const UA_NodeId *referenceTypeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
 
@@ -172,19 +196,20 @@ UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *se
     }
 
     // todo: test if the referencetype is hierarchical
-    if(UA_NodeId_isNull(&(*node)->nodeId)) {
-        if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
+    const UA_Node *managed = UA_NULL;
+    if(UA_NodeId_isNull(&node->nodeId)) {
+        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
             result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
             goto ret2;
         }
-        result.addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
+        result.addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
     } else {
-        if(UA_NodeId_copy(&(*node)->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
+        if(UA_NodeId_copy(&node->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
             result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
             goto ret2;
         }
 
-        if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
+        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
             result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS;  // todo: differentiate out of memory
             UA_NodeId_deleteMembers(&result.addedNodeId);
             goto ret2;
@@ -194,7 +219,7 @@ UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *se
     // reference back to the parent
     UA_AddReferencesItem item;
     UA_AddReferencesItem_init(&item);
-    item.sourceNodeId = (*node)->nodeId;
+    item.sourceNodeId = managed->nodeId;
     item.referenceTypeId = referenceType->nodeId;
     item.isForward = UA_FALSE;
     item.targetNodeId.nodeId = parent->nodeId;
@@ -202,8 +227,7 @@ UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *se
 
     // todo: error handling. remove new node from nodestore
 
-    UA_NodeStore_release(*node);
-    *node = UA_NULL;
+    UA_NodeStore_release(managed);
     
  ret2:
     UA_NodeStore_release((const UA_Node*)referenceType);

+ 54 - 52
src/server/ua_server_binary.c

@@ -1,12 +1,14 @@
 #include <stdio.h>
 
 #include "ua_server_internal.h"
+#include "ua_types_encoding_binary.h"
+#include "ua_transport_generated.h"
 #include "ua_services.h"
 #include "ua_statuscodes.h"
-#include "ua_namespace_0.h"
 #include "ua_securechannel_manager.h"
 #include "ua_session_manager.h"
 #include "ua_util.h"
+#include "ua_nodeids.h"
 
 /** Max size of messages that are allocated on the stack */
 #define MAX_STACK_MESSAGE 65536
@@ -19,7 +21,7 @@ static UA_StatusCode UA_ByteStringArray_deleteMembers(UA_ByteStringArray *string
     return UA_STATUSCODE_GOOD;
 }
 
-static void processHEL(UA_Connection *connection, const UA_ByteString *msg, UA_UInt32 *pos) {
+static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size_t *pos) {
     UA_TcpHelloMessage helloMessage;
     if(UA_TcpHelloMessage_decodeBinary(msg, pos, &helloMessage) != UA_STATUSCODE_GOOD) {
         connection->close(connection);
@@ -42,15 +44,14 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, UA_U
     ackMessage.maxChunkCount     = connection->localConf.maxChunkCount;
 
     UA_TcpMessageHeader ackHeader;
-    ackHeader.messageType = UA_MESSAGETYPE_ACK;
-    ackHeader.isFinal     = 'F';
+    ackHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_ACKF;
     ackHeader.messageSize = UA_TcpAcknowledgeMessage_calcSizeBinary(&ackMessage) +
                             UA_TcpMessageHeader_calcSizeBinary(&ackHeader);
 
     // The message is on the stack. That's ok since ack is very small.
     UA_ByteString ack_msg = (UA_ByteString){ .length = ackHeader.messageSize,
                                              .data = UA_alloca(ackHeader.messageSize) };
-    UA_UInt32 tmpPos = 0;
+    size_t tmpPos = 0;
     UA_TcpMessageHeader_encodeBinary(&ackHeader, &ack_msg, &tmpPos);
     UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &ack_msg, &tmpPos);
     UA_ByteStringArray answer_buf = { .stringsSize = 1, .strings = &ack_msg };
@@ -60,7 +61,7 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, UA_U
 }
 
 static void processOPN(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg,
-                        UA_UInt32 *pos) {
+                        size_t *pos) {
     if(connection->state != UA_CONNECTION_ESTABLISHED) {
         connection->close(connection);
         return;
@@ -91,12 +92,11 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
 
     /* Response */
     UA_SecureConversationMessageHeader respHeader;
-    respHeader.messageHeader.messageType = UA_MESSAGETYPE_OPN;
-    respHeader.messageHeader.isFinal     = 'F';
+    respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
     respHeader.messageHeader.messageSize = 0;
     respHeader.secureChannelId = p.securityToken.channelId;
 
-    UA_NodeId responseType = UA_NODEIDS[UA_OPENSECURECHANNELRESPONSE];
+    UA_NodeId responseType = UA_NODEID_STATIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE);
     responseType.identifier.numeric += UA_ENCODINGOFFSET_BINARY;
 
     respHeader.messageHeader.messageSize =
@@ -109,7 +109,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     UA_ByteString resp_msg = (UA_ByteString){ .length = respHeader.messageHeader.messageSize,
                                               .data = UA_alloca(respHeader.messageHeader.messageSize) };
 
-    UA_UInt32 tmpPos = 0;
+    size_t tmpPos = 0;
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
     UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
     UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back
@@ -129,12 +129,6 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
     r->timestamp       = UA_DateTime_now();
 }
 
-#define CHECK_PROCESS(CODE, CLEANUP)         \
-    do { if(CODE != UA_STATUSCODE_GOOD) {    \
-            CLEANUP;                         \
-            return;                          \
-        } } while(0)
-
 // if the message is small enough, we allocate it on the stack and save a malloc
 #define ALLOC_MESSAGE(MESSAGE, SIZE) do {                               \
         UA_UInt32 messageSize = SIZE;                                   \
@@ -149,7 +143,8 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
 #define INVOKE_SERVICE(TYPE) do {                                       \
         UA_##TYPE##Request p;                                           \
         UA_##TYPE##Response r;                                          \
-        CHECK_PROCESS(UA_##TYPE##Request_decodeBinary(msg, pos, &p),;); \
+        if(UA_##TYPE##Request_decodeBinary(msg, pos, &p))               \
+            return;                                                     \
         UA_##TYPE##Response_init(&r);                                   \
         init_response_header(&p.requestHeader, &r.responseHeader);      \
         Service_##TYPE(server, clientSession, &p, &r);                  \
@@ -160,7 +155,7 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
         responseType = requestType.identifier.numeric + 3;              \
     } while(0)
 
-static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, UA_UInt32 *pos) {
+static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
     // 1) Read in the securechannel
     UA_UInt32 secureChannelId;
     UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
@@ -182,7 +177,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     UA_UInt32 tokenId;
     UA_UInt32_decodeBinary(msg, pos, &tokenId);
     UA_SequenceHeader sequenceHeader;
-    CHECK_PROCESS(UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader),; );
+    if(UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader))
+        return;
 
     clientChannel->sequenceNumber = sequenceHeader.sequenceNumber;
     clientChannel->requestId = sequenceHeader.requestId;
@@ -192,7 +188,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
 
     // 3) Read the nodeid of the request
     UA_NodeId requestType;
-    CHECK_PROCESS(UA_NodeId_decodeBinary(msg, pos, &requestType),; );
+    if(UA_NodeId_decodeBinary(msg, pos, &requestType))
+        return;
     if(requestType.identifierType != UA_NODEIDTYPE_NUMERIC) {
         // if the nodeidtype is numeric, we do not have to free anything
         UA_NodeId_deleteMembers(&requestType);
@@ -205,22 +202,22 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     UA_ByteString *header     = &responseBufs[0];
     UA_ByteString *message    = &responseBufs[1];
     UA_Boolean messageOnStack = UA_FALSE;
-    UA_UInt32 sendOffset      = 0;
+    size_t sendOffset      = 0;
 
 #ifdef EXTENSION_STATELESS
     //only some calls allow to be stateless
     if(clientSession == &anonymousSession) {
     	//subtract UA_ENCODINGOFFSET_BINARY for binary encoding
     	switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
-    	case UA_READREQUEST_NS0:
+    	case UA_NS0ID_READREQUEST:
     		INVOKE_SERVICE(Read);
     		break;
 
-    	case UA_WRITEREQUEST_NS0:
+    	case UA_NS0ID_WRITEREQUEST:
     		INVOKE_SERVICE(Write);
     		break;
 
-    	case UA_BROWSEREQUEST_NS0:
+    	case UA_NS0ID_BROWSEREQUEST:
     		INVOKE_SERVICE(Browse);
     		break;
 
@@ -229,7 +226,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     				requestType.namespaceIndex, requestType.identifier.numeric);
     		UA_RequestHeader  p;
     		UA_ResponseHeader r;
-    		CHECK_PROCESS(UA_RequestHeader_decodeBinary(msg, pos, &p),; );
+    		if(UA_RequestHeader_decodeBinary(msg, pos, &p))
+                return;
     		UA_ResponseHeader_init(&r);
     		init_response_header(&p, &r);
     		r.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
@@ -237,7 +235,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     		UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
     		UA_RequestHeader_deleteMembers(&p);
     		UA_ResponseHeader_deleteMembers(&r);
-    		responseType = UA_NODEIDS[UA_RESPONSEHEADER].identifier.numeric + UA_ENCODINGOFFSET_BINARY; }
+    		responseType = UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY; }
             break;
     	}
     } else {
@@ -245,10 +243,11 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     	//non-stateless service calls
     	//subtract UA_ENCODINGOFFSET_BINARY for binary encoding
     	switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
-    	case UA_GETENDPOINTSREQUEST_NS0: {
+    	case UA_NS0ID_GETENDPOINTSREQUEST: {
     		UA_GetEndpointsRequest  p;
     		UA_GetEndpointsResponse r;
-    		CHECK_PROCESS(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p),; );
+    		if(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p))
+                return;
     		UA_GetEndpointsResponse_init(&r);
     		init_response_header(&p.requestHeader, &r.responseHeader);
     		Service_GetEndpoints(server, &p, &r);
@@ -260,10 +259,11 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     		break;
     	}
 
-    	case UA_CREATESESSIONREQUEST_NS0: {
+    	case UA_NS0ID_CREATESESSIONREQUEST: {
     		UA_CreateSessionRequest  p;
     		UA_CreateSessionResponse r;
-    		CHECK_PROCESS(UA_CreateSessionRequest_decodeBinary(msg, pos, &p),; );
+            if(UA_CreateSessionRequest_decodeBinary(msg, pos, &p))
+                return;
     		UA_CreateSessionResponse_init(&r);
     		init_response_header(&p.requestHeader, &r.responseHeader);
     		Service_CreateSession(server, clientChannel,  &p, &r);
@@ -275,10 +275,11 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     		break;
     	}
 
-    	case UA_ACTIVATESESSIONREQUEST_NS0: {
+    	case UA_NS0ID_ACTIVATESESSIONREQUEST: {
     		UA_ActivateSessionRequest  p;
     		UA_ActivateSessionResponse r;
-    		CHECK_PROCESS(UA_ActivateSessionRequest_decodeBinary(msg, pos, &p),; );
+    		if(UA_ActivateSessionRequest_decodeBinary(msg, pos, &p))
+                return;
     		UA_ActivateSessionResponse_init(&r);
     		init_response_header(&p.requestHeader, &r.responseHeader);
     		Service_ActivateSession(server, clientChannel,  &p, &r);
@@ -290,10 +291,11 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     		break;
     	}
 
-    	case UA_CLOSESESSIONREQUEST_NS0: {
+    	case UA_NS0ID_CLOSESESSIONREQUEST: {
     		UA_CloseSessionRequest  p;
     		UA_CloseSessionResponse r;
-    		CHECK_PROCESS(UA_CloseSessionRequest_decodeBinary(msg, pos, &p),; );
+    		if(UA_CloseSessionRequest_decodeBinary(msg, pos, &p))
+                return;
     		UA_CloseSessionResponse_init(&r);
     		init_response_header(&p.requestHeader, &r.responseHeader);
     		Service_CloseSession(server, &p, &r);
@@ -305,23 +307,23 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     		break;
     	}
 
-    	case UA_READREQUEST_NS0:
+    	case UA_NS0ID_READREQUEST:
     		INVOKE_SERVICE(Read);
     		break;
 
-    	case UA_WRITEREQUEST_NS0:
+    	case UA_NS0ID_WRITEREQUEST:
     		INVOKE_SERVICE(Write);
     		break;
 
-    	case UA_BROWSEREQUEST_NS0:
+    	case UA_NS0ID_BROWSEREQUEST:
     		INVOKE_SERVICE(Browse);
     		break;
 
-    	case UA_ADDREFERENCESREQUEST_NS0:
+    	case UA_NS0ID_ADDREFERENCESREQUEST:
     		INVOKE_SERVICE(AddReferences);
     		break;
 
-    	case UA_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_NS0:
+    	case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
     		INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
     		break;
 
@@ -330,7 +332,8 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     				requestType.namespaceIndex, requestType.identifier.numeric);
     		UA_RequestHeader  p;
     		UA_ResponseHeader r;
-    		CHECK_PROCESS(UA_RequestHeader_decodeBinary(msg, pos, &p),; );
+    		if(UA_RequestHeader_decodeBinary(msg, pos, &p))
+                return;
     		UA_ResponseHeader_init(&r);
     		init_response_header(&p, &r);
     		r.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
@@ -338,7 +341,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     		UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
     		UA_RequestHeader_deleteMembers(&p);
     		UA_ResponseHeader_deleteMembers(&r);
-    		responseType = UA_NODEIDS[UA_RESPONSEHEADER].identifier.numeric + UA_ENCODINGOFFSET_BINARY;
+    		responseType = UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY;
     	}
     	break;
     	}
@@ -348,8 +351,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
 
     // 5) Build the header
     UA_SecureConversationMessageHeader respHeader;
-    respHeader.messageHeader.messageType = UA_MESSAGETYPE_MSG;
-    respHeader.messageHeader.isFinal     = 'F';
+    respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
     respHeader.messageHeader.messageSize = 0;
     respHeader.secureChannelId = clientChannel->securityToken.channelId;
 
@@ -372,7 +374,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     *header = (UA_ByteString){ .length = headerSize, .data = UA_alloca(headerSize) };
     respHeader.messageHeader.messageSize = header->length + message->length;
 
-    UA_UInt32 rpos = 0;
+    size_t rpos = 0;
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, header, &rpos);
     UA_SymmetricAlgorithmSecurityHeader_encodeBinary(&symSecHeader, header, &rpos);
     UA_SequenceHeader_encodeBinary(&seqHeader, header, &rpos);
@@ -391,7 +393,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
 }
 
 static void processCLO(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg,
-                         UA_UInt32 *pos) {
+                         size_t *pos) {
     UA_UInt32 secureChannelId;
     UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
 
@@ -402,7 +404,7 @@ static void processCLO(UA_Connection *connection, UA_Server *server, const UA_By
 }
 
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg) {
-    UA_UInt32 pos = 0;
+    size_t pos = 0;
     UA_TcpMessageHeader tcpMessageHeader;
     do {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader) != UA_STATUSCODE_GOOD) {
@@ -411,17 +413,17 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             break;
         }
 
-        UA_UInt32 targetpos = pos - 8 + tcpMessageHeader.messageSize;
-        switch(tcpMessageHeader.messageType) {
-        case UA_MESSAGETYPE_HEL:
+        size_t targetpos = pos - 8 + tcpMessageHeader.messageSize;
+        switch(tcpMessageHeader.messageTypeAndFinal & 0xffffff) {
+        case UA_MESSAGETYPEANDFINAL_HELF & 0xffffff:
             processHEL(connection, msg, &pos);
             break;
 
-        case UA_MESSAGETYPE_OPN:
+        case UA_MESSAGETYPEANDFINAL_OPNF & 0xffffff:
             processOPN(connection, server, msg, &pos);
             break;
 
-        case UA_MESSAGETYPE_MSG:
+        case UA_MESSAGETYPEANDFINAL_MSGF & 0xffffff:
 #ifndef EXTENSION_STATELESS
             if(connection->state == UA_CONNECTION_ESTABLISHED && connection->channel != UA_NULL)
                 processMSG(connection, server, msg, &pos);
@@ -432,7 +434,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
 #endif
             break;
 
-        case UA_MESSAGETYPE_CLO:
+        case UA_MESSAGETYPEANDFINAL_CLOF & 0xffffff:
             processCLO(connection, server, msg, &pos);
             connection->close(connection);
             return;

+ 7 - 2
src/server/ua_server_internal.h

@@ -9,6 +9,7 @@
 #include <urcu/wfcqueue.h>
 #endif
 
+#include "../deps/queue.h"
 #include "ua_server.h"
 #include "ua_session_manager.h"
 #include "ua_securechannel_manager.h"
@@ -65,8 +66,12 @@ struct UA_Server {
 
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg);
 
-UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, const UA_Node **node,
-                                               const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId);
+UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
+                                               const UA_ExpandedNodeId *parentNodeId,
+                                               const UA_NodeId *referenceTypeId);
+
+UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId *parentNodeId,
+                                    const UA_NodeId *referenceTypeId);
 
 UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item);
 

+ 169 - 236
src/server/ua_services_attribute.c

@@ -3,13 +3,13 @@
 #include "ua_services.h"
 #include "ua_statuscodes.h"
 #include "ua_nodestore.h"
-#include "ua_namespace_0.h"
 #include "ua_util.h"
+#include "stdio.h"
 
 #define CHECK_NODECLASS(CLASS)                                  \
     if(!(node->nodeClass & (CLASS))) {                          \
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE; \
-        v->status       = UA_STATUSCODE_BADNOTREADABLE;         \
+        v->hasStatus = UA_TRUE;                                 \
+        v->status = UA_STATUSCODE_BADNOTREADABLE;               \
         break;                                                  \
     }
 
@@ -17,8 +17,8 @@
 static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue *v) {
     UA_Node const *node = UA_NodeStore_get(server->nodestore, &(id->nodeId));
     if(!node) {
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-        v->status       = UA_STATUSCODE_BADNODEIDUNKNOWN;
+        v->hasStatus = UA_TRUE;
+        v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
         return;
     }
 
@@ -26,157 +26,178 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
 
     switch(id->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_NODEID], &node->nodeId);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &node->nodeId, UA_TYPES_NODEID);
         break;
 
     case UA_ATTRIBUTEID_NODECLASS:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_INT32], &node->nodeClass);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &node->nodeClass, UA_TYPES_INT32);
         break;
 
     case UA_ATTRIBUTEID_BROWSENAME:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_QUALIFIEDNAME], &node->browseName);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &node->browseName, UA_TYPES_QUALIFIEDNAME);
         break;
 
     case UA_ATTRIBUTEID_DISPLAYNAME:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_LOCALIZEDTEXT], &node->displayName);
+        retval |= UA_Variant_copySetValue(&v->value, &node->displayName, UA_TYPES_LOCALIZEDTEXT);
+        if(retval == UA_STATUSCODE_GOOD)
+            v->hasVariant = UA_TRUE;
         break;
 
     case UA_ATTRIBUTEID_DESCRIPTION:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_LOCALIZEDTEXT], &node->description);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &node->description, UA_TYPES_LOCALIZEDTEXT);
         break;
 
     case UA_ATTRIBUTEID_WRITEMASK:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_UINT32], &node->writeMask);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &node->writeMask, UA_TYPES_UINT32);
         break;
 
     case UA_ATTRIBUTEID_USERWRITEMASK:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_UINT32], &node->userWriteMask);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &node->userWriteMask, UA_TYPES_UINT32);
         break;
 
     case UA_ATTRIBUTEID_ISABSTRACT:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE |
                         UA_NODECLASS_DATATYPE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BOOLEAN],
-                                          &((const UA_ReferenceTypeNode *)node)->isAbstract);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ReferenceTypeNode *)node)->isAbstract,
+                                          UA_TYPES_BOOLEAN);
         break;
 
     case UA_ATTRIBUTEID_SYMMETRIC:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BOOLEAN],
-                                          &((const UA_ReferenceTypeNode *)node)->symmetric);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ReferenceTypeNode *)node)->symmetric,
+                                          UA_TYPES_BOOLEAN);
         break;
 
     case UA_ATTRIBUTEID_INVERSENAME:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_LOCALIZEDTEXT],
-                                          &((const UA_ReferenceTypeNode *)node)->inverseName);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ReferenceTypeNode *)node)->inverseName,
+                                          UA_TYPES_LOCALIZEDTEXT);
         break;
 
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BOOLEAN],
-                                          &((const UA_ViewNode *)node)->containsNoLoops);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ViewNode *)node)->containsNoLoops,
+                                          UA_TYPES_BOOLEAN);
         break;
 
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BYTE],
-                                          &((const UA_ViewNode *)node)->eventNotifier);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ViewNode *)node)->eventNotifier,
+                                          UA_TYPES_BYTE);
         break;
 
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copy(&((const UA_VariableNode *)node)->value, &v->value); // todo: zero-copy
+        retval = UA_Variant_copy(&((const UA_VariableNode *)node)->value, &v->value);
+        if(retval == UA_STATUSCODE_GOOD)
+            v->hasVariant = UA_TRUE;
         break;
 
     case UA_ATTRIBUTEID_DATATYPE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_NODEID],
-                                          &((const UA_VariableTypeNode *)node)->dataType);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableTypeNode *)node)->value.typeId,
+                                          UA_TYPES_NODEID);
         break;
 
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_INT32],
-                                          &((const UA_VariableTypeNode *)node)->valueRank);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableTypeNode *)node)->valueRank,
+                                          UA_TYPES_INT32);
         break;
 
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        UA_Variant_copySetArray(&v->value, &UA_TYPES[UA_UINT32],
-                                ((const UA_VariableTypeNode *)node)->arrayDimensionsSize,
-                                &((const UA_VariableTypeNode *)node)->arrayDimensions);
+        {
+            const UA_VariantData *data = UA_NULL;
+            UA_VariantData datasourceData;
+            const UA_VariableNode *vn = (const UA_VariableNode *)node;
+            if(vn->value.storageType == UA_VARIANT_DATA || vn->value.storageType == UA_VARIANT_DATA_NODELETE)
+                data = &vn->value.storage.data;
+            else {
+                if((retval = vn->value.storage.datasource.read(vn->value.storage.datasource.handle,
+                                                               &datasourceData)) != UA_STATUSCODE_GOOD)
+                    break;
+                data = &datasourceData;
+            }
+            retval = UA_Variant_copySetArray(&v->value, data->arrayDimensions, data->arrayDimensionsSize,
+                                             UA_TYPES_INT32);
+            if(retval == UA_STATUSCODE_GOOD)
+                v->hasVariant = UA_TRUE;
+            if(vn->value.storageType == UA_VARIANT_DATASOURCE)
+                vn->value.storage.datasource.release(vn->value.storage.datasource.handle, &datasourceData);
+        }
         break;
 
     case UA_ATTRIBUTEID_ACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BYTE],
-                                          &((const UA_VariableNode *)node)->accessLevel);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->accessLevel,
+                                          UA_TYPES_BYTE);
         break;
 
     case UA_ATTRIBUTEID_USERACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BYTE],
-                                          &((const UA_VariableNode *)node)->userAccessLevel);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->userAccessLevel,
+                                          UA_TYPES_BYTE);
         break;
 
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_DOUBLE],
-                                          &((const UA_VariableNode *)node)->minimumSamplingInterval);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->minimumSamplingInterval,
+                                          UA_TYPES_DOUBLE);
         break;
 
     case UA_ATTRIBUTEID_HISTORIZING:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BOOLEAN],
-                                          &((const UA_VariableNode *)node)->historizing);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->historizing,
+                                          UA_TYPES_BOOLEAN);
         break;
 
     case UA_ATTRIBUTEID_EXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BOOLEAN],
-                                          &((const UA_MethodNode *)node)->executable);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_MethodNode *)node)->executable,
+                                          UA_TYPES_BOOLEAN);
         break;
 
     case UA_ATTRIBUTEID_USEREXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
-        retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BOOLEAN],
-                                          &((const UA_MethodNode *)node)->userExecutable);
+        v->hasVariant = UA_TRUE;
+        retval |= UA_Variant_copySetValue(&v->value, &((const UA_MethodNode *)node)->userExecutable,
+                                          UA_TYPES_BOOLEAN);
         break;
 
     default:
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-        v->status       = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
+        v->hasStatus = UA_TRUE;
+        v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
         break;
     }
 
     UA_NodeStore_release(node);
 
+    if(v->hasVariant && v->value.type == UA_NULL) {
+        printf("%i", id->attributeId);
+        UA_assert(UA_FALSE);
+    }
     if(retval != UA_STATUSCODE_GOOD) {
-        v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
-        v->status       = UA_STATUSCODE_BADNOTREADABLE;
+        v->hasStatus = UA_TRUE;
+        v->status = UA_STATUSCODE_BADNOTREADABLE;
     }
 }
 
@@ -187,10 +208,9 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToReadSize,
-                                        &UA_TYPES[UA_DATAVALUE]);
-    if(retval != UA_STATUSCODE_GOOD) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_DATAVALUE], request->nodesToReadSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 
@@ -227,16 +247,16 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 		UA_ExtensionObject additionalHeader;
 		UA_ExtensionObject_init(&additionalHeader);
 		additionalHeader.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-		additionalHeader.typeId = UA_NODEIDS[UA_VARIANT];
+		additionalHeader.typeId.identifier.numeric = UA_TYPES_IDS[UA_TYPES_VARIANT];
 
 		UA_Variant variant;
 		UA_Variant_init(&variant);
-		variant.vt = &UA_TYPES[UA_DATETIME];
+		variant.type = &UA_TYPES[UA_TYPES_DATETIME];
 		variant.storage.data.arrayLength = request->nodesToReadSize;
 
 		UA_DateTime* expireArray = UA_NULL;
 		UA_Array_new((void**)&expireArray, request->nodesToReadSize,
-												&UA_TYPES[UA_DATETIME]);
+												&UA_TYPES[UA_TYPES_DATETIME]);
 		variant.storage.data.dataPtr = expireArray;
 
 		UA_ByteString str;
@@ -256,176 +276,133 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 #endif
 }
 
-static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *aWriteValue) {
+static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
 
-    do {
-        const UA_Node *node = UA_NodeStore_get(server->nodestore, &aWriteValue->nodeId);
+    // we might repeat writing, e.g. when the node got replaced mid-work
+    UA_Boolean done = UA_FALSE;
+    while(!done) {
+        const UA_Node *node = UA_NodeStore_get(server->nodestore, &wvalue->nodeId);
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
-        UA_Node *newNode;
+        UA_Node* (*newNode)(void);
+        void (*deleteNode)(UA_Node*);
+        UA_StatusCode (*copyNode)(const UA_Node*, UA_Node*);
+
         switch(node->nodeClass) {
         case UA_NODECLASS_OBJECT:
-            newNode = (UA_Node *)UA_ObjectNode_new();
-            UA_ObjectNode_copy((const UA_ObjectNode*)node, (UA_ObjectNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_ObjectNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_ObjectNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ObjectNode_copy;
             break;
-
         case UA_NODECLASS_VARIABLE:
-            newNode = (UA_Node *)UA_VariableNode_new();
-            UA_VariableNode_copy((const UA_VariableNode*)node, (UA_VariableNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_VariableNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_VariableNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_VariableNode_copy;
             break;
-
         case UA_NODECLASS_METHOD:
-            newNode = (UA_Node *)UA_MethodNode_new();
-            UA_MethodNode_copy((const UA_MethodNode*)node, (UA_MethodNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_MethodNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_MethodNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_MethodNode_copy;
             break;
-
         case UA_NODECLASS_OBJECTTYPE:
-            newNode = (UA_Node *)UA_ObjectTypeNode_new();
-            UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)node, (UA_ObjectTypeNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_ObjectTypeNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_ObjectTypeNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ObjectTypeNode_copy;
             break;
-
         case UA_NODECLASS_VARIABLETYPE:
-            newNode = (UA_Node *)UA_VariableTypeNode_new();
-            UA_VariableTypeNode_copy((const UA_VariableTypeNode*)node, (UA_VariableTypeNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_VariableTypeNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_VariableTypeNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_VariableTypeNode_copy;
             break;
-
         case UA_NODECLASS_REFERENCETYPE:
-            newNode = (UA_Node *)UA_ReferenceTypeNode_new();
-            UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)node, (UA_ReferenceTypeNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_ReferenceTypeNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_ReferenceTypeNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ReferenceTypeNode_copy;
             break;
-
         case UA_NODECLASS_DATATYPE:
-            newNode = (UA_Node *)UA_DataTypeNode_new();
-            UA_DataTypeNode_copy((const UA_DataTypeNode*)node, (UA_DataTypeNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_DataTypeNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_DataTypeNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_DataTypeNode_copy;
             break;
-
         case UA_NODECLASS_VIEW:
-            newNode = (UA_Node *)UA_ViewNode_new();
-            UA_ViewNode_copy((const UA_ViewNode*)node, (UA_ViewNode *)newNode);
+            newNode = (UA_Node *(*)(void))UA_ViewNode_new;
+            deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
+            copyNode = (UA_StatusCode (*)(const UA_Node*, UA_Node*))UA_ViewNode_copy;
             break;
-
         default:
+            UA_NodeStore_release(node);
             return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
-            break;
         }
 
-        switch(aWriteValue->attributeId) {
+        switch(wvalue->attributeId) {
         case UA_ATTRIBUTEID_NODEID:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){ } */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_NODECLASS:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){ } */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_BROWSENAME:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_DISPLAYNAME:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_DESCRIPTION:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_WRITEMASK:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_USERWRITEMASK:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_ISABSTRACT:
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_SYMMETRIC:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_INVERSENAME:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
-            /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_EVENTNOTIFIER:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
             retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
             break;
-
         case UA_ATTRIBUTEID_VALUE:
-            if((newNode->nodeClass != UA_NODECLASS_VARIABLE) && (newNode->nodeClass != UA_NODECLASS_VARIABLETYPE)) {
+            if((node->nodeClass != UA_NODECLASS_VARIABLE) && (node->nodeClass != UA_NODECLASS_VARIABLETYPE)) {
                 retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
                 break;
             }
 
-            if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT)
-                retval |= UA_Variant_copy(&aWriteValue->value.value, &((UA_VariableNode *)newNode)->value); // todo: zero-copy
-            break;
+            const UA_VariableNode *vn = (const UA_VariableNode*)node;
+            // has the wvalue a variant of the right type?
+            // array sizes are not checked yet..
+            if(!wvalue->value.hasVariant || !UA_NodeId_equal(&vn->value.typeId, &wvalue->value.value.typeId)) {
+                retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+                break;
+            }
 
-        case UA_ATTRIBUTEID_DATATYPE:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+            if(vn->value.storageType == UA_VARIANT_DATASOURCE) {
+                retval = vn->value.storage.datasource.write(vn->value.storage.datasource.handle,
+                                                            &wvalue->value.value.storage.data);
+                done = UA_TRUE;
+            } else {
+                // could be a variable or variabletype node. They fit for the value.. member
+                UA_VariableNode *newVn = (UA_VariableNode*)newNode();
+                if(!newVn) {
+                    retval = UA_STATUSCODE_BADOUTOFMEMORY;
+                    break;
+                }
+                retval = copyNode((const UA_Node*)vn, (UA_Node*)newVn);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    deleteNode((UA_Node*)newVn);
+                    break;
+                }
+                retval = UA_Variant_copy(&wvalue->value.value, &newVn->value);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    deleteNode((UA_Node*)newVn);
+                    break;
+                }
+                if(UA_NodeStore_replace(server->nodestore,node,(UA_Node*)newVn,UA_NULL) == UA_STATUSCODE_GOOD)
+                    done = UA_TRUE;
+                else
+                    deleteNode((UA_Node*)newVn);
+            } 
             break;
-
+        case UA_ATTRIBUTEID_DATATYPE:
         case UA_ATTRIBUTEID_VALUERANK:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_ACCESSLEVEL:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_USERACCESSLEVEL:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_HISTORIZING:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_EXECUTABLE:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
-            retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-            break;
-
         case UA_ATTRIBUTEID_USEREXECUTABLE:
-            /* if(aWriteValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){} */
             retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
             break;
-
         default:
             retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
             break;
@@ -434,52 +411,8 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *aWriteValue) {
         if(retval != UA_STATUSCODE_GOOD)
             break;
 
-        const UA_Node *constPtr = newNode; // compilers complain if we directly cast
-        if(UA_NodeStore_replace(server->nodestore, node, &constPtr, UA_FALSE) == UA_STATUSCODE_GOOD) {
-            UA_NodeStore_release(node);
-            break;
-        }
-
-        /* The node was replaced in another thread. Restart. */
         UA_NodeStore_release(node);
-        switch(node->nodeClass) {
-        case UA_NODECLASS_OBJECT:
-            UA_ObjectNode_delete((UA_ObjectNode *)newNode);
-            break;
-
-        case UA_NODECLASS_VARIABLE:
-            UA_VariableNode_delete((UA_VariableNode *)newNode);
-            break;
-
-        case UA_NODECLASS_METHOD:
-            UA_MethodNode_delete((UA_MethodNode *)newNode);
-            break;
-            
-        case UA_NODECLASS_OBJECTTYPE:
-            UA_ObjectTypeNode_delete((UA_ObjectTypeNode *)newNode);
-            break;
-            
-        case UA_NODECLASS_VARIABLETYPE:
-            UA_VariableTypeNode_delete((UA_VariableTypeNode *)newNode);
-            break;
-            
-        case UA_NODECLASS_REFERENCETYPE:
-            UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *)newNode);
-            break;
-            
-        case UA_NODECLASS_DATATYPE:
-            UA_DataTypeNode_delete((UA_DataTypeNode *)newNode);
-            break;
-            
-        case UA_NODECLASS_VIEW:
-            UA_ViewNode_delete((UA_ViewNode *)newNode);
-            break;
-
-        default:
-            break;
-        }
-
-    } while(UA_TRUE);
+    }
 
     return retval;
 }
@@ -488,9 +421,9 @@ void Service_Write(UA_Server *server, UA_Session *session,
                    const UA_WriteRequest *request, UA_WriteResponse *response) {
     UA_assert(server != UA_NULL && session != UA_NULL && request != UA_NULL && response != UA_NULL);
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToWriteSize, &UA_TYPES[UA_STATUSCODE]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_STATUSCODE], request->nodesToWriteSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 

+ 0 - 1
src/server/ua_services_discovery.c

@@ -1,6 +1,5 @@
 #include "ua_server_internal.h"
 #include "ua_services.h"
-#include "ua_namespace_0.h"
 #include "ua_util.h"
 
 void Service_GetEndpoints(UA_Server                    *server,

+ 52 - 48
src/server/ua_services_nodemanagement.c

@@ -1,6 +1,5 @@
 #include "ua_server_internal.h"
 #include "ua_services.h"
-#include "ua_namespace_0.h"
 #include "ua_statuscodes.h"
 #include "ua_nodestore.h"
 #include "ua_session.h"
@@ -21,14 +20,13 @@
         vnode->userWriteMask = attr.userWriteMask;                      \
     } while(0)
 
-static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node,
-                                       const UA_TypeVTable **vt) {
+static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     if(attributes->typeId.identifier.numeric !=
-       UA_NODEIDS[UA_VARIABLEATTRIBUTES].identifier.numeric + UA_ENCODINGOFFSET_BINARY)
+       UA_TYPES_IDS[UA_TYPES_VARIABLEATTRIBUTES] + UA_ENCODINGOFFSET_BINARY)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
 
     UA_VariableAttributes attr;
-    UA_UInt32 pos = 0;
+    size_t pos = 0;
     // todo return more informative error codes from decodeBinary
     if(UA_VariableAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -57,18 +55,20 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
         vnode->valueRank = attr.valueRank;
 
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) {
-        vnode->arrayDimensionsSize = attr.arrayDimensionsSize;
-        vnode->arrayDimensions = attr.arrayDimensions;
-        attr.arrayDimensionsSize = -1;
-        attr.arrayDimensions = UA_NULL;
-    }
-
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE ||
-       attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) {
-        vnode->dataType = attr.dataType;
-        UA_NodeId_init(&attr.dataType);
-    }
+    // don't use extra dimension spec. This comes from the value.
+    /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) { */
+    /*     vnode->arrayDimensionsSize = attr.arrayDimensionsSize; */
+    /*     vnode->arrayDimensions = attr.arrayDimensions; */
+    /*     attr.arrayDimensionsSize = -1; */
+    /*     attr.arrayDimensions = UA_NULL; */
+    /* } */
+
+    // don't use the extra type id. This comes from the value.
+    /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DATATYPE || */
+    /*    attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_OBJECTTYPEORDATATYPE) { */
+    /*     vnode->dataType = attr.dataType; */
+    /*     UA_NodeId_init(&attr.dataType); */
+    /* } */
 
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
         vnode->value = attr.value;
@@ -78,17 +78,15 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     UA_VariableAttributes_deleteMembers(&attr);
 
     *new_node = (UA_Node*)vnode;
-    *vt = &UA_TYPES[UA_VARIABLENODE];
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode parseObjectNode(UA_ExtensionObject *attributes,
-                                     UA_Node **new_node, const UA_TypeVTable **vt) {
+static UA_StatusCode parseObjectNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     if(attributes->typeId.identifier.numeric !=
-       UA_NODEIDS[UA_OBJECTATTRIBUTES].identifier.numeric + UA_ENCODINGOFFSET_BINARY)  // VariableAttributes_Encoding_DefaultBinary
+       UA_TYPES_IDS[UA_TYPES_OBJECTATTRIBUTES] + UA_ENCODINGOFFSET_BINARY)  // VariableAttributes_Encoding_DefaultBinary
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
     UA_ObjectAttributes attr;
-    UA_UInt32 pos = 0;
+    size_t pos = 0;
     // todo return more informative error codes from decodeBinary
     if (UA_ObjectAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -104,14 +102,12 @@ static UA_StatusCode parseObjectNode(UA_ExtensionObject *attributes,
         vnode->eventNotifier = attr.eventNotifier;
     UA_ObjectAttributes_deleteMembers(&attr);
     *new_node = (UA_Node*) vnode;
-    *vt = &UA_TYPES[UA_OBJECTNODE];
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode parseReferenceTypeNode(UA_ExtensionObject *attributes,
-                                            UA_Node **new_node, const UA_TypeVTable **vt) {
+static UA_StatusCode parseReferenceTypeNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     UA_ReferenceTypeAttributes attr;
-    UA_UInt32 pos = 0;
+    size_t pos = 0;
     // todo return more informative error codes from decodeBinary
     if(UA_ReferenceTypeAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -136,14 +132,12 @@ static UA_StatusCode parseReferenceTypeNode(UA_ExtensionObject *attributes,
     }
     UA_ReferenceTypeAttributes_deleteMembers(&attr);
     *new_node = (UA_Node*) vnode;
-    *vt = &UA_TYPES[UA_REFERENCETYPENODE];
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode parseObjectTypeNode(UA_ExtensionObject *attributes,
-                                         UA_Node **new_node, const UA_TypeVTable **vt) {
+static UA_StatusCode parseObjectTypeNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     UA_ObjectTypeAttributes attr;
-    UA_UInt32 pos = 0;
+    size_t pos = 0;
     // todo return more informative error codes from decodeBinary
     if(UA_ObjectTypeAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -160,14 +154,12 @@ static UA_StatusCode parseObjectTypeNode(UA_ExtensionObject *attributes,
     }
     UA_ObjectTypeAttributes_deleteMembers(&attr);
     *new_node = (UA_Node*) vnode;
-    *vt = &UA_TYPES[UA_OBJECTTYPENODE];
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode parseViewNode(UA_ExtensionObject *attributes, UA_Node **new_node,
-                                   const UA_TypeVTable **vt) {
+static UA_StatusCode parseViewNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     UA_ViewAttributes attr;
-    UA_UInt32 pos = 0;
+    size_t pos = 0;
     // todo return more informative error codes from decodeBinary
     if(UA_ViewAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -184,7 +176,6 @@ static UA_StatusCode parseViewNode(UA_ExtensionObject *attributes, UA_Node **new
         vnode->eventNotifier = attr.eventNotifier;
     UA_ViewAttributes_deleteMembers(&attr);
     *new_node = (UA_Node*) vnode;
-    *vt = &UA_TYPES[UA_VIEWNODE];
     return UA_STATUSCODE_GOOD;
 }
 
@@ -198,20 +189,19 @@ static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_Add
 
     // parse the node
     UA_Node *node = UA_NULL;
-    const UA_TypeVTable *nodeVT = UA_NULL;
 
     switch (item->nodeClass) {
     case UA_NODECLASS_OBJECT:
-        result->statusCode = parseObjectNode(&item->nodeAttributes, &node, &nodeVT);
+        result->statusCode = parseObjectNode(&item->nodeAttributes, &node);
         break;
     case UA_NODECLASS_OBJECTTYPE:
-        result->statusCode = parseObjectTypeNode(&item->nodeAttributes, &node, &nodeVT);
+        result->statusCode = parseObjectTypeNode(&item->nodeAttributes, &node);
         break;
     case UA_NODECLASS_REFERENCETYPE:
-        result->statusCode = parseReferenceTypeNode(&item->nodeAttributes, &node, &nodeVT);
+        result->statusCode = parseReferenceTypeNode(&item->nodeAttributes, &node);
         break;
     case UA_NODECLASS_VARIABLE:
-        result->statusCode = parseVariableNode(&item->nodeAttributes, &node, &nodeVT);
+        result->statusCode = parseVariableNode(&item->nodeAttributes, &node);
         break;
     default:
         result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
@@ -221,11 +211,26 @@ static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_Add
         return;
 
     // add the node
-    const UA_Node *constNode = node; // compilers complain if we cast directly
-    *result = UA_Server_addNodeWithSession(server, session, &constNode, &item->parentNodeId,
+    *result = UA_Server_addNodeWithSession(server, session, node, &item->parentNodeId,
                                            &item->referenceTypeId);
-    if(result->statusCode != UA_STATUSCODE_GOOD)
-        nodeVT->delete(node);
+    if(result->statusCode != UA_STATUSCODE_GOOD) {
+        switch (node->nodeClass) {
+        case UA_NODECLASS_OBJECT:
+            UA_ObjectNode_delete((UA_ObjectNode*)node);
+            break;
+        case UA_NODECLASS_OBJECTTYPE:
+            UA_ObjectTypeNode_delete((UA_ObjectTypeNode*)node);
+            break;
+        case UA_NODECLASS_REFERENCETYPE:
+            UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode*)node);
+            break;
+        case UA_NODECLASS_VARIABLE:
+            UA_VariableNode_delete((UA_VariableNode*)node);
+            break;
+        default:
+            UA_assert(UA_FALSE);
+        }
+    }
 }
 
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
@@ -235,10 +240,9 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToAddSize,
-                                        &UA_TYPES[UA_ADDNODESRESULT]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_ADDNODESRESULT], request->nodesToAddSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 

+ 10 - 13
src/server/ua_services_view.c

@@ -2,7 +2,6 @@
 #include "ua_services.h"
 #include "ua_statuscodes.h"
 #include "ua_nodestore.h"
-#include "ua_namespace_0.h"
 #include "ua_util.h"
 
 /* Releases the current node, even if it was supplied as an argument. */
@@ -133,7 +132,7 @@ static UA_StatusCode findRelevantReferenceTypes(UA_NodeStore *ns, const UA_NodeI
     } while(++currentIndex <= currentLastIndex && retval == UA_STATUSCODE_GOOD);
 
     if(retval)
-        UA_Array_delete(typeArray, currentLastIndex, &UA_TYPES[UA_NODEID]);
+        UA_Array_delete(typeArray, &UA_TYPES[UA_TYPES_NODEID], currentLastIndex);
     else {
         *referenceTypes = typeArray;
         *referenceTypesSize = currentLastIndex + 1;
@@ -168,7 +167,7 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
     if(!parentNode) {
         browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         if(!returnAll)
-            UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_NODEID]);
+            UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
         return;
     }
 
@@ -203,7 +202,7 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
             if(fillReferenceDescription(ns, currentNode, &parentNode->references[i],
                                         browseDescription->resultMask,
                                         &browseResult->references[currentRefs]) != UA_STATUSCODE_GOOD) {
-                UA_Array_delete(browseResult->references, currentRefs, &UA_TYPES[UA_REFERENCEDESCRIPTION]);
+                UA_Array_delete(browseResult->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], currentRefs);
                 currentRefs = 0;
                 browseResult->references = UA_NULL;
                 browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
@@ -221,7 +220,7 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
 
     UA_NodeStore_release(parentNode);
     if(!returnAll)
-        UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_NODEID]);
+        UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
 }
 
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
@@ -231,14 +230,12 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToBrowseSize,
-                                        &UA_TYPES[UA_BROWSERESULT]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+   response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], request->nodesToBrowseSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 
-
     /* ### Begin External Namespaces */
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToBrowseSize);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * request->nodesToBrowseSize);
@@ -279,9 +276,9 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
         return;
     }
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->browsePathsSize, &UA_TYPES[UA_BROWSEPATHRESULT]);
-    if(retval) {
-        response->responseHeader.serviceResult = retval;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSEPATHRESULT], request->browsePathsSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 

+ 1 - 0
src/server/ua_session_manager.h

@@ -1,6 +1,7 @@
 #ifndef UA_SESSION_MANAGER_H_
 #define UA_SESSION_MANAGER_H_
 
+#include "../deps/queue.h"
 #include "ua_server.h"
 #include "ua_util.h"
 #include "ua_session.h"

+ 2 - 11
src/ua_config.h.in

@@ -1,17 +1,8 @@
 /* Buid options and configuration (set by cmake) */
-#define UA_ENCODING_AMOUNT ${UA_ENCODING_AMOUNT}
-#define UA_LOGLEVEL ${UA_LOGLEVEL}
 
-#cmakedefine UA_DEBUG
+#define UA_LOGLEVEL ${UA_LOGLEVEL}
 #cmakedefine UA_MULTITHREADING
 
-/* Visibility */
-#ifdef _MSC_VER
-#define INLINE __inline
-#else
-#define INLINE inline
-#endif
-
 /* Function Export */
 #ifdef _WIN32
 #  ifdef UA_DYNAMIC_LINKING
@@ -32,7 +23,7 @@
 #    endif
 #  endif
 #else
-#  if __GNUC__ >= 4 || __clang__
+#  if __GNUC__ || __clang__
 #    define UA_EXPORT __attribute__ ((visibility ("default")))
 #  else
 #    define UA_EXPORT

+ 5 - 0
src/ua_securechannel.c

@@ -6,6 +6,11 @@
 #include <urcu/uatomic.h>
 #endif
 
+// max message size is 64k
+const UA_ConnectionConfig UA_ConnectionConfig_standard =
+    {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
+     .maxMessageSize = 65536, .maxChunkCount   = 1};
+
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
     UA_MessageSecurityMode_init(&channel->securityMode);
     UA_ChannelSecurityToken_init(&channel->securityToken);

+ 0 - 1
src/ua_securechannel.h

@@ -2,7 +2,6 @@
 #define UA_SECURECHANNEL_H_
 
 #include "ua_types_generated.h"
-#include "ua_transport.h"
 #include "ua_transport_generated.h"
 #include "ua_connection.h"
 

+ 0 - 50
src/ua_transport.c

@@ -1,50 +0,0 @@
-#ifdef UA_DEBUG
-#include <stdio.h>
-#endif
-#include "ua_connection.h"
-#include "ua_transport.h"
-#include "ua_types_macros.h"
-#include "ua_util.h"
-
-// max message size is 64k
-const UA_ConnectionConfig UA_ConnectionConfig_standard =
-    {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
-     .maxMessageSize = 65536, .maxChunkCount   = 1};
-
-
-UA_TYPE_DEFAULT(UA_MessageType)
-UA_UInt32 UA_MessageType_calcSizeBinary(UA_MessageType const *ptr) {
-    return 3 * sizeof(UA_Byte);
-}
-
-UA_StatusCode UA_MessageType_encodeBinary(UA_MessageType const *src, UA_ByteString *dst, UA_UInt32 *offset) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_Byte tmpBuf[3];
-    tmpBuf[0] = (UA_Byte)(((UA_Int32)*src) >> 16);
-    tmpBuf[1] = (UA_Byte)(((UA_Int32)*src) >> 8);
-    tmpBuf[2] = (UA_Byte)((UA_Int32)*src);
-
-    retval |= UA_Byte_encodeBinary(&(tmpBuf[0]), dst, offset);
-    retval |= UA_Byte_encodeBinary(&(tmpBuf[1]), dst, offset);
-    retval |= UA_Byte_encodeBinary(&(tmpBuf[2]), dst, offset);
-    return retval;
-}
-
-UA_StatusCode UA_MessageType_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, UA_MessageType *dst) {
-    if(*offset+3 > (UA_UInt32)src->length)
-        return UA_STATUSCODE_BADDECODINGERROR;
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_Byte tmpBuf[3];
-    retval |= UA_Byte_decodeBinary(src, offset, &(tmpBuf[0])); //messageType to Byte representation
-    retval |= UA_Byte_decodeBinary(src, offset, &(tmpBuf[1]));
-    retval |= UA_Byte_decodeBinary(src, offset, &(tmpBuf[2]));
-    *dst = (UA_MessageType)((UA_Int32)(tmpBuf[0]<<16) + (UA_Int32)(tmpBuf[1]<<8) + (UA_Int32)(tmpBuf[2]));
-    return retval;
-}
-
-#ifdef UA_DEBUG
-void UA_MessageType_print(const UA_MessageType *p, FILE *stream) {
-    const UA_Byte *b = (const UA_Byte *)p;
-    fprintf(stream, "%c%c%c", b[2], b[1], b[0]);
-}
-#endif

+ 0 - 22
src/ua_transport.h

@@ -1,22 +0,0 @@
-#ifndef UA_TRANSPORT_H_
-#define UA_TRANSPORT_H_
-
-#include "ua_types.h"
-#include "ua_types_encoding_binary.h"
-
-/* MessageType */
-typedef UA_Int32 UA_MessageType;
-enum UA_MessageType {
-    UA_MESSAGETYPE_HEL = 0x48454C, // H E L
-    UA_MESSAGETYPE_ACK = 0x41434B, // A C k
-    UA_MESSAGETYPE_ERR = 0x455151, // E R R
-    UA_MESSAGETYPE_OPN = 0x4F504E, // O P N
-    UA_MESSAGETYPE_MSG = 0x4D5347, // M S G
-    UA_MESSAGETYPE_CLO = 0x434C4F  // C L O
-};
-UA_TYPE_PROTOTYPES(UA_MessageType)
-UA_TYPE_BINARY_ENCODING(UA_MessageType)
-
-/* All other transport types are auto-generated from a schema definition. */
-
-#endif /* UA_TRANSPORT_H_ */

Файловите разлики са ограничени, защото са твърде много
+ 485 - 520
src/ua_types.c


Файловите разлики са ограничени, защото са твърде много
+ 858 - 616
src/ua_types_encoding_binary.c


+ 11 - 34
src/ua_types_encoding_binary.h

@@ -30,29 +30,10 @@
  * @{
  */
 
-#define UA_TYPE_CALCSIZEBINARY_AS(TYPE, TYPE_AS)        \
-    UA_UInt32 TYPE##_calcSizeBinary(TYPE const *p) {    \
-        return TYPE_AS##_calcSizeBinary((const TYPE_AS *)p);  \
-    }
-
-#define UA_TYPE_ENCODEBINARY_AS(TYPE, TYPE_AS)                          \
-    UA_StatusCode TYPE##_encodeBinary(TYPE const *src, UA_ByteString *dst, UA_UInt32 *offset) { \
-        return TYPE_AS##_encodeBinary((const TYPE_AS *)src, dst, offset);     \
-    }
-
-#define UA_TYPE_DECODEBINARY_AS(TYPE, TYPE_AS)                          \
-    UA_StatusCode TYPE##_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, TYPE *dst) { \
-        return TYPE_AS##_decodeBinary(src, offset, (TYPE_AS *)dst);     \
-    }
-#define UA_TYPE_BINARY_ENCODING_AS(TYPE, TYPE_AS) \
-    UA_TYPE_CALCSIZEBINARY_AS(TYPE, TYPE_AS)      \
-    UA_TYPE_ENCODEBINARY_AS(TYPE, TYPE_AS)        \
-    UA_TYPE_DECODEBINARY_AS(TYPE, TYPE_AS)
-
 #define UA_TYPE_BINARY_ENCODING(TYPE)                                   \
-    UA_UInt32 TYPE##_calcSizeBinary(TYPE const *p);                     \
-    UA_StatusCode TYPE##_encodeBinary(TYPE const *src, UA_ByteString *dst, UA_UInt32 *offset); \
-    UA_StatusCode TYPE##_decodeBinary(UA_ByteString const *src, UA_UInt32 *offset, TYPE *dst);
+    size_t TYPE##_calcSizeBinary(TYPE const *p);                        \
+    UA_StatusCode TYPE##_encodeBinary(TYPE const *src, UA_ByteString *dst, size_t *offset); \
+    UA_StatusCode TYPE##_decodeBinary(UA_ByteString const *src, size_t *offset, TYPE *dst);
 
 UA_TYPE_BINARY_ENCODING(UA_Boolean)
 UA_TYPE_BINARY_ENCODING(UA_SByte)
@@ -80,19 +61,15 @@ UA_TYPE_BINARY_ENCODING(UA_DataValue)
 UA_TYPE_BINARY_ENCODING(UA_Variant)
 UA_TYPE_BINARY_ENCODING(UA_DiagnosticInfo)
 
-/* Not defined in the standard */
-UA_TYPE_BINARY_ENCODING(UA_InvalidType)
-
-/** Computes the size of an array (incl. length field) in a binary blob. */
-UA_UInt32 UA_Array_calcSizeBinary(UA_Int32 length, const UA_TypeVTable *vt, const void *data);
-
-/** Encodes an array into a binary blob. The array size is printed as an int32 before the actual content. */
-UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 length, const UA_TypeVTable *vt,
-                                    UA_ByteString *dst, UA_UInt32 *offset);
+size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType);
+UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_ByteString *dst, size_t *offset);
+UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst, const UA_DataType *dataType);
 
-/** Decodes an array from a binary blob. The array is allocated automatically before decoding. */
-UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, UA_UInt32 *offset, UA_Int32 length,
-                                    const UA_TypeVTable *vt, void **dst);
+size_t UA_Array_calcSizeBinary(const void *p, UA_Int32 noElements, const UA_DataType *dataType);
+UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 noElements, const UA_DataType *dataType,
+                                    UA_ByteString *dst, size_t *offset);
+UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, size_t *offset, UA_Int32 noElements,
+                                    void **dst, const UA_DataType *dataType);
 
 /// @} /* end of group */
 

+ 0 - 76
src/ua_types_macros.h

@@ -1,76 +0,0 @@
-#ifndef UA_TYPES_MACROS_H_
-#define UA_TYPES_MACROS_H_
-
-/* Macros for type implementations */
-
-#define UA_TYPE_DEFAULT(TYPE)            \
-    UA_TYPE_DELETE_DEFAULT(TYPE)         \
-    UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
-    UA_TYPE_INIT_DEFAULT(TYPE)           \
-    UA_TYPE_NEW_DEFAULT(TYPE)            \
-    UA_TYPE_COPY_DEFAULT(TYPE)           \
-    
-#define UA_TYPE_NEW_DEFAULT(TYPE)                             \
-    TYPE * TYPE##_new() {                                     \
-        TYPE *p = UA_malloc(sizeof(TYPE));                     \
-        if(p) TYPE##_init(p);                                 \
-        return p;                                             \
-    }
-
-#define UA_TYPE_INIT_DEFAULT(TYPE) \
-    void TYPE##_init(TYPE * p) {   \
-        *p = (TYPE)0;              \
-    }
-
-#define UA_TYPE_INIT_AS(TYPE, TYPE_AS) \
-    void TYPE##_init(TYPE * p) {       \
-        TYPE_AS##_init((TYPE_AS *)p);  \
-    }
-
-#define UA_TYPE_DELETE_DEFAULT(TYPE) \
-    void TYPE##_delete(TYPE *p) {    \
-        TYPE##_deleteMembers(p);     \
-        UA_free(p);                  \
-    }
-
-#define UA_TYPE_DELETE_AS(TYPE, TYPE_AS) \
-    void TYPE##_delete(TYPE * p) {       \
-        TYPE_AS##_delete((TYPE_AS *)p);  \
-    }
-
-#define UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
-    void TYPE##_deleteMembers(TYPE * p) { return; }
-
-#define UA_TYPE_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
-    void TYPE##_deleteMembers(TYPE * p) { TYPE_AS##_deleteMembers((TYPE_AS *)p); }
-
-/* Use only when the type has no arrays. Otherwise, implement deep copy */
-#define UA_TYPE_COPY_DEFAULT(TYPE)                             \
-    UA_StatusCode TYPE##_copy(TYPE const *src, TYPE *dst) {    \
-        *dst = *src;                                           \
-        return UA_STATUSCODE_GOOD;                             \
-    }
-
-#define UA_TYPE_COPY_AS(TYPE, TYPE_AS)                         \
-    UA_StatusCode TYPE##_copy(const TYPE *src, TYPE *dst) {    \
-        return TYPE_AS##_copy((const TYPE_AS *)src, (TYPE_AS *)dst); \
-    }
-
-#ifdef UA_DEBUG //print functions only in debug mode
-#define UA_TYPE_PRINT_AS(TYPE, TYPE_AS)                    \
-    void TYPE##_print(const TYPE *p, FILE *stream) {       \
-        TYPE_AS##_print((const TYPE_AS *)p, stream);       \
-    }
-#else
-#define UA_TYPE_PRINT_AS(TYPE, TYPE_AS)
-#endif
-
-#define UA_TYPE_AS(TYPE, TYPE_AS)           \
-    UA_TYPE_NEW_DEFAULT(TYPE)               \
-    UA_TYPE_INIT_AS(TYPE, TYPE_AS)          \
-    UA_TYPE_DELETE_AS(TYPE, TYPE_AS)        \
-    UA_TYPE_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
-    UA_TYPE_COPY_AS(TYPE, TYPE_AS)          \
-    UA_TYPE_PRINT_AS(TYPE, TYPE_AS)
-
-#endif /* UA_TYPES_MACROS_H_ */

+ 7 - 7
src/ua_util.h

@@ -1,35 +1,35 @@
 #ifndef UA_UTIL_H_
 #define UA_UTIL_H_
 
-#ifndef  __USE_POSIX
+#ifndef __USE_POSIX
 #define __USE_POSIX
 #endif
 #include <stdlib.h> // malloc, free
 #include <string.h> // memcpy
 #include <assert.h> // assert
-#include <stddef.h> /* Needed for queue.h */
 
 #ifdef _WIN32
-#  include <malloc.h>
-#  include "queue.h"
+# include <malloc.h>
 #else
-#  include <alloca.h>
-#  include <sys/queue.h>
+# include <alloca.h>
 #endif
 
+
 // subtract from nodeids to get from the encoding to the content
 #define UA_ENCODINGOFFSET_XML 1
 #define UA_ENCODINGOFFSET_BINARY 2
 
 #define UA_assert(ignore) assert(ignore)
 
-/* Memory management. Replace the macros with functions for custom allocators.. */
 #define UA_NULL ((void *)0)
+
+/* Replace the macros with functions for custom allocators if necessary */
 #define UA_free(ptr) free(ptr)
 #define UA_malloc(size) malloc(size)
 #define UA_realloc(ptr, size) realloc(ptr, size)
 #define UA_memcpy(dst, src, size) memcpy(dst, src, size)
 #define UA_memset(ptr, value, size) memset(ptr, value, size)
+
 #ifdef _WIN32
 # define UA_alloca(SIZE) _alloca(SIZE)
 #else

Файловите разлики са ограничени, защото са твърде много
+ 242 - 197
tests/check_builtin.c


+ 46 - 47
tests/check_memory.c

@@ -3,21 +3,18 @@
 #include <stdlib.h>
 
 #include "ua_types.h"
+#include "ua_types_generated.h"
+#include "ua_types_encoding_binary.h"
 #include "ua_util.h"
-#include "ua_namespace_0.h"
 #include "check.h"
 
 START_TEST(newAndEmptyObjectShallBeDeleted) {
 	// given
-	void *obj = UA_TYPES[_i].new();
-	// when
-#ifdef DEBUG //no print functions if not in debug mode
-	UA_TYPES[_i].print(obj, stdout);
-#endif
+	void *obj = UA_new(&UA_TYPES[_i]);
 	// then
 	ck_assert_ptr_ne(obj, UA_NULL);
     // finally
-	UA_TYPES[_i].delete(obj);
+	UA_delete(obj, &UA_TYPES[_i]);
 }
 END_TEST
 
@@ -29,7 +26,7 @@ START_TEST(arrayCopyShallMakeADeepCopy) {
 	a1[2] = (UA_String){3, (UA_Byte*)"ccc"};
 	// when
 	UA_String *a2;
-	UA_Int32   retval = UA_Array_copy((const void *)a1, 3, &UA_TYPES[UA_STRING], (void **)&a2);
+	UA_Int32   retval = UA_Array_copy((const void *)a1, (void **)&a2, &UA_TYPES[UA_TYPES_STRING], 3);
 	// then
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(a1[0].length, 1);
@@ -45,39 +42,38 @@ START_TEST(arrayCopyShallMakeADeepCopy) {
 	ck_assert_int_eq(a1[1].data[0], a2[1].data[0]);
 	ck_assert_int_eq(a1[2].data[0], a2[2].data[0]);
 	// finally
-	UA_Array_delete((void *)a2, 3, &UA_TYPES[UA_STRING]);
+	UA_Array_delete((void *)a2, &UA_TYPES[UA_TYPES_STRING], 3);
 }
 END_TEST
 
 START_TEST(encodeShallYieldDecode) {
 	// given
 	UA_ByteString msg1, msg2;
-	UA_UInt32     pos = 0;
-	void *obj1 = UA_TYPES[_i].new();
-	UA_ByteString_newMembers(&msg1, UA_TYPES[_i].encodings[UA_ENCODING_BINARY].calcSize(obj1));
-	UA_StatusCode retval = UA_TYPES[_i].encodings[UA_ENCODING_BINARY].encode(obj1, &msg1, &pos);
+	size_t pos = 0;
+	void *obj1 = UA_new(&UA_TYPES[_i]);
+	UA_ByteString_newMembers(&msg1, UA_calcSizeBinary(obj1, &UA_TYPES[_i]));
+    UA_StatusCode retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
 	if(retval != UA_STATUSCODE_GOOD) {
-		// this happens, e.g. when we encode a variant (with UA_TYPES[UA_INVALIDTYPE] in the vtable)
-		UA_TYPES[_i].delete(obj1);
+		UA_delete(obj1, &UA_TYPES[_i]);
 		UA_ByteString_deleteMembers(&msg1);
 		return;	
 	}
 
 	// when
-	void *obj2 = UA_TYPES[_i].new();
-	pos = 0; retval = UA_TYPES[_i].encodings[UA_ENCODING_BINARY].decode(&msg1, &pos, obj2);
-	ck_assert_msg(retval == UA_STATUSCODE_GOOD, "messages differ idx=%d,name=%s", _i, UA_TYPES[_i].name);
-	retval = UA_ByteString_newMembers(&msg2, UA_TYPES[_i].encodings[UA_ENCODING_BINARY].calcSize(obj2));
+	void *obj2 = UA_new(&UA_TYPES[_i]);
+	pos = 0; retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
+	ck_assert_msg(retval == UA_STATUSCODE_GOOD, "messages differ idx=%d,nodeid=%i", _i, UA_TYPES_IDS[_i]);
+	retval = UA_ByteString_newMembers(&msg2, UA_calcSizeBinary(obj2, &UA_TYPES[_i]));
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-	pos = 0; retval = UA_TYPES[_i].encodings[UA_ENCODING_BINARY].encode(obj2, &msg2, &pos);
+	pos = 0; retval = UA_encodeBinary(obj2, &UA_TYPES[_i], &msg2, &pos);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
 	// then
-	ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == UA_TRUE, "messages differ idx=%d,name=%s", _i, UA_TYPES[_i].name);
+	ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == UA_TRUE, "messages differ idx=%d,nodeid=%i", _i, UA_TYPES_IDS[_i]);
 
 	// finally
-	UA_TYPES[_i].delete(obj1);
-	UA_TYPES[_i].delete(obj2);
+	UA_delete(obj1, &UA_TYPES[_i]);
+	UA_delete(obj2, &UA_TYPES[_i]);
 	UA_ByteString_deleteMembers(&msg1);
 	UA_ByteString_deleteMembers(&msg2);
 }
@@ -86,21 +82,25 @@ END_TEST
 START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
 	// given
 	UA_ByteString msg1;
-	UA_UInt32 pos;
-	void *obj1 = UA_TYPES[_i].new();
-	UA_ByteString_newMembers(&msg1, UA_TYPES[_i].encodings[0].calcSize(obj1));
-	pos = 0; UA_TYPES[_i].encodings[0].encode(obj1, &msg1, &pos);
-	UA_TYPES[_i].delete(obj1);
+	void *obj1 = UA_new(&UA_TYPES[_i]);
+	size_t pos = 0;
+	UA_ByteString_newMembers(&msg1, UA_calcSizeBinary(obj1, &UA_TYPES[_i]));
+    UA_StatusCode retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
+	UA_delete(obj1, &UA_TYPES[_i]);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ByteString_deleteMembers(&msg1);
+        return; // e.g. variants cannot be encoded after an init without failing (no datatype set)
+    }
 	// when
-	void *obj2 = UA_TYPES[_i].new();
+	void *obj2 = UA_new(&UA_TYPES[_i]);
 	pos = 0;
 	msg1.length = msg1.length / 2;
 	//fprintf(stderr,"testing %s with half buffer\n",UA_TYPES[_i].name);
-	UA_TYPES[_i].encodings[0].decode(&msg1, &pos, obj2);
+	UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
 	//then
 	// finally
 	//fprintf(stderr,"delete %s with half buffer\n",UA_TYPES[_i].name);
-	UA_TYPES[_i].delete(obj2);
+	UA_delete(obj2, &UA_TYPES[_i]);
 	UA_ByteString_deleteMembers(&msg1);
 }
 END_TEST
@@ -129,13 +129,13 @@ START_TEST(decodeScalarBasicTypeFromRandomBufferShallSucceed) {
 			msg1.data[i] = (UA_Byte)random();  // when
 #endif
 		}
-		UA_UInt32 pos = 0;
-		obj1 = UA_TYPES[_i].new();
-		retval |= UA_TYPES[_i].encodings[0].decode(&msg1, &pos, obj1);
+		size_t pos = 0;
+		obj1 = UA_new(&UA_TYPES[_i]);
+		retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i]);
 		//then
-		ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Decoding %s from random buffer", UA_TYPES[_i].name);
+		ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Decoding %d from random buffer", UA_TYPES_IDS[_i]);
 		// finally
-		UA_TYPES[_i].delete(obj1);
+		UA_delete(obj1, &UA_TYPES[_i]);
 	}
 	UA_ByteString_deleteMembers(&msg1);
 }
@@ -163,10 +163,10 @@ START_TEST(decodeComplexTypeFromRandomBufferShallSurvive) {
 			msg1.data[i] = (UA_Byte)random();  // when
 #endif
 		}
-		UA_UInt32 pos = 0;
-		void *obj1 = UA_TYPES[_i].new();
-		retval |= UA_TYPES[_i].encodings[0].decode(&msg1, &pos, obj1);
-		UA_TYPES[_i].delete(obj1);
+		size_t pos = 0;
+		void *obj1 = UA_new(&UA_TYPES[_i]);
+		retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i]);
+		UA_delete(obj1, &UA_TYPES[_i]);
 	}
 
 	// finally
@@ -180,22 +180,21 @@ int main(void) {
 
 	Suite *s  = suite_create("testMemoryHandling");
 	TCase *tc = tcase_create("Empty Objects");
-	tcase_add_loop_test(tc, newAndEmptyObjectShallBeDeleted, UA_BOOLEAN, UA_INVALIDTYPE-1);
+	tcase_add_loop_test(tc, newAndEmptyObjectShallBeDeleted, UA_TYPES_BOOLEAN, UA_TYPES_EVENTNOTIFICATIONLIST);
 	tcase_add_test(tc, arrayCopyShallMakeADeepCopy);
-	tcase_add_loop_test(tc, encodeShallYieldDecode, UA_BOOLEAN, UA_INVALIDTYPE-1);
+	tcase_add_loop_test(tc, encodeShallYieldDecode, UA_TYPES_BOOLEAN, UA_TYPES_EVENTNOTIFICATIONLIST);
 	suite_add_tcase(s, tc);
 	tc = tcase_create("Truncated Buffers");
-	tcase_add_loop_test(tc, decodeShallFailWithTruncatedBufferButSurvive, UA_BOOLEAN, UA_INVALIDTYPE-1);
+	tcase_add_loop_test(tc, decodeShallFailWithTruncatedBufferButSurvive, UA_TYPES_BOOLEAN, UA_TYPES_EVENTNOTIFICATIONLIST);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("Fuzzing with Random Buffers");
-	tcase_add_loop_test(tc, decodeScalarBasicTypeFromRandomBufferShallSucceed, UA_BOOLEAN, UA_DOUBLE);
-	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_STRING, UA_DIAGNOSTICINFO);
-	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_IDTYPE, UA_INVALIDTYPE);
+	tcase_add_loop_test(tc, decodeScalarBasicTypeFromRandomBufferShallSucceed, UA_TYPES_BOOLEAN, UA_TYPES_GUID);
+	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_TYPES_NODEID, UA_TYPES_EVENTNOTIFICATIONLIST);
 	suite_add_tcase(s, tc);
 
 	sr = srunner_create(s);
-	//srunner_set_fork_status(sr, CK_NOFORK);
+	srunner_set_fork_status(sr, CK_NOFORK);
 	srunner_run_all (sr, CK_NORMAL);
 	number_failed += srunner_ntests_failed(sr);
 	srunner_free(sr);

+ 65 - 62
tests/check_nodestore.c

@@ -34,11 +34,12 @@ static UA_Node* createNode(UA_Int16 nsid, UA_Int32 id) {
 
 START_TEST(replaceExistingNode) {
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n1 = createNode(0,2253);
-	UA_NodeStore_insert(ns, &n1, UA_TRUE);
-	const UA_Node* n2 = createNode(0,2253);
-    UA_StatusCode retval = UA_NodeStore_replace(ns, n1, &n2, UA_FALSE);
-    UA_NodeStore_release(n1);
+	UA_Node* n1 = createNode(0,2253);
+    const UA_Node *inserted;
+	UA_NodeStore_insert(ns, n1, &inserted);
+	UA_Node* n2 = createNode(0,2253);
+    UA_StatusCode retval = UA_NodeStore_replace(ns, inserted, n2, UA_NULL);
+    UA_NodeStore_release(inserted);
     
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     
@@ -48,14 +49,14 @@ END_TEST
 
 START_TEST(replaceNonExistingNode) {
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n1 = createNode(0,2253);
+	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n2 = createNode(0,2253);
-    const UA_Node *dummy = n2;
-    UA_StatusCode retval = UA_NodeStore_replace(ns, n1, (const UA_Node **)&dummy, UA_FALSE);
+    UA_StatusCode retval = UA_NodeStore_replace(ns, n1, n2, UA_NULL);
     
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
     
-    UA_Node_delete(n2);
+    UA_VariableNode_delete((UA_VariableNode*)n1);
+    UA_VariableNode_delete((UA_VariableNode*)n2);
 	UA_NodeStore_delete(ns);
 }
 END_TEST
@@ -66,13 +67,14 @@ START_TEST(findNodeInUA_NodeStoreWithSingleEntry) {
 #endif
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n1 = createNode(0,2253);
-	UA_NodeStore_insert(ns, &n1, UA_TRUE);
-	const UA_Node* nr = UA_NodeStore_get(ns,&n1->nodeId);
+    const UA_Node *inserted;
+	UA_Node* n1 = createNode(0,2253);
+	UA_NodeStore_insert(ns, n1, &inserted);
+	const UA_Node* nr = UA_NodeStore_get(ns,&inserted->nodeId);
 	// then
-	ck_assert_ptr_eq((const void*)nr, (const void*)n1);
+	ck_assert_int_eq((uintptr_t)inserted, (uintptr_t)nr);
 	// finally
-	UA_NodeStore_release(n1);
+	UA_NodeStore_release(inserted);
 	UA_NodeStore_release(nr);
 	UA_NodeStore_delete(ns);
 #ifdef UA_MULTITHREADING
@@ -88,16 +90,16 @@ START_TEST(failToFindNodeInOtherUA_NodeStore) {
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 
-	const UA_Node* n1 = createNode(0,2255);
-    UA_NodeStore_insert(ns, (const UA_Node **)&n1, UA_FALSE);
+	UA_Node* n1 = createNode(0,2255);
+    UA_NodeStore_insert(ns, n1, UA_NULL);
 
 	// when
 	UA_Node* n = createNode(1,2255);
 	const UA_Node* nr = UA_NodeStore_get(ns,&n->nodeId);
 	// then
-	ck_assert_ptr_eq((const void*)nr, UA_NULL);
+	ck_assert_int_eq((uintptr_t)nr, 0);
 	// finally
-	UA_Node_delete(n);
+	UA_VariableNode_delete((UA_VariableNode*)n);
 	UA_NodeStore_delete(ns);
 #ifdef UA_MULTITHREADING
 	rcu_unregister_thread();
@@ -111,25 +113,26 @@ START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
 #endif
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, &n1, UA_FALSE);
-	const UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, &n2, UA_FALSE);
-	const UA_Node* n3 = createNode(0,2257);
-    UA_NodeStore_insert(ns, &n3, UA_TRUE);
-	const UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, &n4, UA_FALSE);
-	const UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, &n5, UA_FALSE);
-	const UA_Node* n6 = createNode(0,12);
-    UA_NodeStore_insert(ns, &n6, UA_FALSE);
+	UA_Node* n1 = createNode(0,2253);
+    UA_NodeStore_insert(ns, n1, UA_NULL);
+	UA_Node* n2 = createNode(0,2255);
+    UA_NodeStore_insert(ns, n2, UA_NULL);
+	UA_Node* n3 = createNode(0,2257);
+    const UA_Node *inserted;
+    UA_NodeStore_insert(ns, n3, &inserted);
+	UA_Node* n4 = createNode(0,2200);
+    UA_NodeStore_insert(ns, n4, UA_NULL);
+	UA_Node* n5 = createNode(0,1);
+    UA_NodeStore_insert(ns, n5, UA_NULL);
+	UA_Node* n6 = createNode(0,12);
+    UA_NodeStore_insert(ns, n6, UA_NULL);
 
 	// when
-	const UA_Node* nr = UA_NodeStore_get(ns,&(n3->nodeId));
+	const UA_Node* nr = UA_NodeStore_get(ns,&inserted->nodeId);
 	// then
-	ck_assert_ptr_eq((const void*)nr, (const void*)n3);
+	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)inserted);
 	// finally
-	UA_NodeStore_release(n3);
+	UA_NodeStore_release(inserted);
 	UA_NodeStore_release(nr);
 	UA_NodeStore_delete(ns);
 #ifdef UA_MULTITHREADING
@@ -144,18 +147,18 @@ START_TEST(iterateOverUA_NodeStoreShallNotVisitEmptyNodes) {
 #endif
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, &n1, 0);
-	const UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, &n2, 0);
-	const UA_Node* n3 = createNode(0,2257);
-    UA_NodeStore_insert(ns, &n3, 0);
-	const UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, &n4, 0);
-	const UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, &n5, 0);
-	const UA_Node* n6 = createNode(0,12);
-    UA_NodeStore_insert(ns, &n6, 0);
+	UA_Node* n1 = createNode(0,2253);
+    UA_NodeStore_insert(ns, n1, UA_NULL);
+	UA_Node* n2 = createNode(0,2255);
+    UA_NodeStore_insert(ns, n2, UA_NULL);
+	UA_Node* n3 = createNode(0,2257);
+    UA_NodeStore_insert(ns, n3, UA_NULL);
+	UA_Node* n4 = createNode(0,2200);
+    UA_NodeStore_insert(ns, n4, UA_NULL);
+	UA_Node* n5 = createNode(0,1);
+    UA_NodeStore_insert(ns, n5, UA_NULL);
+	UA_Node* n6 = createNode(0,12);
+    UA_NodeStore_insert(ns, n6, UA_NULL);
 
 	// when
 	zeroCnt = 0;
@@ -178,11 +181,11 @@ START_TEST(findNodeInExpandedNamespace) {
 #endif
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n;
+	UA_Node* n;
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, (const UA_Node **)&n, UA_FALSE);
+        UA_NodeStore_insert(ns, n, UA_NULL);
 	}
 	// when
 	UA_Node *n2 = createNode(0,25);
@@ -205,11 +208,11 @@ START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
 #endif
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n;
+    UA_Node* n;
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, &n, UA_FALSE);
+        UA_NodeStore_insert(ns, n, UA_NULL);
 	}
 	// when
 	zeroCnt = 0;
@@ -232,22 +235,22 @@ START_TEST(failToFindNonExistantNodeInUA_NodeStoreWithSeveralEntries) {
 #endif
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, &n1, UA_FALSE);
-	const UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, &n2, UA_FALSE);
-	const UA_Node* n3 = createNode(0,2257);
-    UA_NodeStore_insert(ns, &n3, UA_FALSE);
-	const UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, &n4, UA_FALSE);
-	const UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, &n5, UA_FALSE);
+	UA_Node* n1 = createNode(0,2253);
+    UA_NodeStore_insert(ns, n1, UA_NULL);
+	UA_Node* n2 = createNode(0,2255);
+    UA_NodeStore_insert(ns, n2, UA_NULL);
+	UA_Node* n3 = createNode(0,2257);
+    UA_NodeStore_insert(ns, n3, UA_NULL);
+	UA_Node* n4 = createNode(0,2200);
+    UA_NodeStore_insert(ns, n4, UA_NULL);
+	UA_Node* n5 = createNode(0,1);
+    UA_NodeStore_insert(ns, n5, UA_NULL);
 	UA_Node* n6 = createNode(0,12); 
 
 	// when
 	const UA_Node* nr = UA_NodeStore_get(ns, &n6->nodeId);
 	// then
-	ck_assert_ptr_eq((const void*)nr, UA_NULL);
+	ck_assert_int_eq((uintptr_t)nr, 0);
 	// finally
 	UA_free((void *)n6);
 	UA_NodeStore_delete(ns);
@@ -297,10 +300,10 @@ START_TEST(profileGetDelete) {
 
 #define N 1000000
 	UA_NodeStore *ns = UA_NodeStore_new();
-	const UA_Node *n;
+	UA_Node *n;
 	for (int i=0; i<N; i++) {
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, (const UA_Node **)&n, UA_FALSE);
+        UA_NodeStore_insert(ns, n, UA_NULL);
 	}
 	clock_t begin, end;
 	begin = clock();

+ 0 - 415
tools/generate_builtin.py

@@ -1,415 +0,0 @@
-from __future__ import print_function
-import sys
-import time
-import platform
-import getpass
-from collections import OrderedDict
-import re
-from lxml import etree
-import inspect
-import argparse
-
-#####################
-# Utility functions #
-#####################
-
-print(sys.argv)
-
-parser = argparse.ArgumentParser()
-parser.add_argument('--export-prototypes', action='store_true', help='make the prototypes (init, delete, copy, ..) of generated types visible for users of the library')
-parser.add_argument('--with-xml', action='store_true', help='generate xml encoding')
-parser.add_argument('--with-json', action='store_true', help='generate json encoding')
-parser.add_argument('--only-nano', action='store_true', help='generate only the types for the nano profile')
-parser.add_argument('--only-needed', action='store_true', help='generate only types needed for compile')
-parser.add_argument('--additional-includes', action='store', help='include additional header files (separated by comma)')
-parser.add_argument('xml', help='path/to/Opc.Ua.Types.bsd')
-parser.add_argument('outfile', help='outfile w/o extension')
-args = parser.parse_args()
-outname = args.outfile.split("/")[-1] 
-inname = args.xml.split("/")[-1]
-        
-ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
-tree = etree.parse(args.xml)
-types = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
-
-fh = open(args.outfile + "_generated.h",'w')
-fc = open(args.outfile + "_generated.c",'w')
-
-# dirty hack. we go up the call frames to access local variables of the calling
-# function. this allows to shorten code and get %()s replaces with less clutter.
-def printh(string):
-    print(string % inspect.currentframe().f_back.f_locals, end='\n', file=fh)
-
-def printc(string):
-    print(string % inspect.currentframe().f_back.f_locals, end='\n', file=fc)
-
-
-# types that are coded manually 
-from type_lists import existing_types
-
-# whitelist for "only needed" profile
-from type_lists import only_needed_types
-
-# some types are omitted (pretend they exist already)
-existing_types.add("NodeIdType")
-
-fixed_size = {"UA_Boolean": 1, "UA_SByte": 1, "UA_Byte": 1, "UA_Int16": 2, "UA_UInt16": 2,
-              "UA_Int32": 4, "UA_UInt32": 4, "UA_Int64": 8, "UA_UInt64": 8, "UA_Float": 4,
-              "UA_Double": 8, "UA_DateTime": 8, "UA_Guid": 16, "UA_StatusCode": 4}
-
-# types we do not want to autogenerate
-def skipType(name):
-    if name in existing_types:
-        return True
-    if "Test" in name: #skip all Test types
-        return True
-    if re.search("NodeId$", name) != None:
-        return True
-    if args.only_needed and not(name in only_needed_types):
-        return True
-    return False
-    
-def stripTypename(tn):
-	return tn[tn.find(":")+1:]
-
-def camlCase2CCase(item):
-	if item in ["Float","Double"]:
-		return "my" + item
-	return item[:1].lower() + item[1:] if item else ''
-
-################################
-# Type Definition and Encoding #
-################################
-
-# are the types we need already in place? if not, postpone.
-def printableStructuredType(element):
-    for child in element:
-        if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
-            typename = stripTypename(child.get("TypeName"))
-            if typename not in existing_types:
-                return False
-    return True
-
-def printPrototypes(name):
-    if args.export_prototypes:
-        printh("UA_TYPE_PROTOTYPES(%(name)s)")
-    else:
-        printh("UA_TYPE_PROTOTYPES_NOEXPORT(%(name)s)")
-    printh("UA_TYPE_BINARY_ENCODING(%(name)s)")
-    if args.with_xml:
-        printh("UA_TYPE_XML_ENCODING(%(name)s)")
-
-def createEnumerated(element):	
-    valuemap = OrderedDict()
-    name = "UA_" + element.get("Name")
-    fixed_size[name] = 4
-    printh("") # newline
-    for child in element:
-        if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
-            printh("/** @brief " + child.text + " */")
-        if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
-            valuemap[name + "_" + child.get("Name")] = child.get("Value")
-    valuemap = OrderedDict(sorted(valuemap.iteritems(), key=lambda (k,v): int(v)))
-    # printh("typedef UA_Int32 " + name + ";")
-    printh("typedef enum { \n\t" +
-           ",\n\t".join(map(lambda (key, value) : key.upper() + " = " + value, valuemap.iteritems())) +
-           "\n} " + name + ";")
-    printPrototypes(name)
-    printc("UA_TYPE_AS(" + name + ", UA_Int32)")
-    printc("UA_TYPE_BINARY_ENCODING_AS(" + name + ", UA_Int32)")
-    if args.with_xml:
-        printh("UA_TYPE_XML_ENCODING(" + name + ")\n")
-        printc('''UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(%(name)s)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(%(name)s)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(%(name)s\n)''')
-
-def createOpaque(element):
-    name = "UA_" + element.get("Name")
-    printh("") # newline
-    for child in element:
-        if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
-            printh("/** @brief " + child.text + " */")
-    printh("typedef UA_ByteString %(name)s;")
-    printPrototypes(name)
-    printc("UA_TYPE_AS(%(name)s, UA_ByteString)")
-    printc("UA_TYPE_BINARY_ENCODING_AS(%(name)s, UA_ByteString)")
-    if args.with_xml:
-        printc('''UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(%(name)s)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(%(name)s)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(%(name)s)\n''')
-
-def createStructured(element):
-    name = "UA_" + element.get("Name")
-
-    # 1) Are there arrays in the type?
-    lengthfields = set()
-    for child in element:
-        if child.get("LengthField"):
-            lengthfields.add(child.get("LengthField"))
-
-    # 2) Store members in membermap (name->type).
-    membermap = OrderedDict()
-    printh("") # newline
-    for child in element:
-        if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
-            printh("/** @brief " + child.text + " */")
-        elif child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
-            if child.get("Name") in lengthfields:
-                continue
-            childname = camlCase2CCase(child.get("Name"))
-            typename = stripTypename(child.get("TypeName"))
-            if child.get("LengthField"):
-                membermap[childname] = "UA_" + typename + "*"
-            else:
-                membermap[childname] = "UA_" + typename
-
-    # fixed size?
-    is_fixed_size = True
-    this_fixed_size = 0
-    for n,t in membermap.iteritems():
-        if t not in fixed_size.keys():
-            is_fixed_size = False
-        else:
-            this_fixed_size += fixed_size[t]
-
-    if is_fixed_size:
-        fixed_size[name] = this_fixed_size
-
-    # 3) Print structure
-    if len(membermap) > 0:
-        printh("typedef struct {")
-        for n,t in membermap.iteritems():
-	    if t.find("*") != -1:
-	        printh("\t" + "UA_Int32 " + n + "Size;")
-            printh("\t%(t)s %(n)s;")
-        printh("} %(name)s;")
-    else:
-        printh("typedef void* %(name)s;")
-        
-    # 3) function prototypes
-    printPrototypes(name)
-
-    # 4) CalcSizeBinary
-    printc('''UA_UInt32 %(name)s_calcSizeBinary(%(name)s const * ptr) {
-    return 0''')
-    if is_fixed_size:
-        printc('''+ %(this_fixed_size)s''')
-    else:
-        for n,t in membermap.iteritems():
-            if t in fixed_size:
-                printc('\t + ' + str(fixed_size[t]) + ' // %(n)s')
-            elif t.find("*") != -1:
-                printc('\t + UA_Array_calcSizeBinary(ptr->%(n)sSize,&UA_TYPES[' +
-                       t[0:t.find("*")].upper() + "],ptr->%(n)s)")
-            else:
-                printc('\t + %(t)s_calcSizeBinary(&ptr->%(n)s)')
-    printc("\t;\n}\n")
-
-    # 5) EncodeBinary
-    printc('''UA_StatusCode %(name)s_encodeBinary(%(name)s const * src, UA_ByteString* dst, UA_UInt32 *offset) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;''')
-    for n,t in membermap.iteritems():
-        if t.find("*") != -1:
-            printc("\tretval |= UA_Array_encodeBinary(src->%(n)s,src->%(n)sSize,&UA_TYPES[" + t[0:t.find("*")].upper() + "],dst,offset);")
-        else:
-            printc('\tretval |= %(t)s_encodeBinary(&src->%(n)s,dst,offset);')
-    printc("\treturn retval;\n}\n")
-
-    # 6) DecodeBinary
-    printc('''UA_StatusCode %(name)s_decodeBinary(UA_ByteString const * src, UA_UInt32 *offset, %(name)s * dst) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    %(name)s_init(dst);''')
-    printc('\t'+name+'_init(dst);')
-    for n,t in membermap.iteritems():
-        if t.find("*") != -1:
-            printc('\tretval |= UA_Int32_decodeBinary(src,offset,&dst->%(n)sSize);')
-            printc('\tif(!retval) { retval |= UA_Array_decodeBinary(src,offset,dst->%(n)sSize,&UA_TYPES[' + t[0:t.find("*")].upper() + '],(void**)&dst->%(n)s); }')
-            printc('\tif(retval) { dst->%(n)sSize = -1; }') # arrays clean up internally. But the size needs to be set here for the eventual deleteMembers.
-        else:
-            printc('\tretval |= %(t)s_decodeBinary(src,offset,&dst->%(n)s);')
-    printc("\tif(retval) %(name)s_deleteMembers(dst);")
-    printc("\treturn retval;\n}\n")
-
-    # 7) Xml
-    if args.with_xml:
-        printc('''UA_TYPE_METHOD_CALCSIZEXML_NOTIMPL(%(name)s)
-UA_TYPE_METHOD_ENCODEXML_NOTIMPL(%(name)s)
-UA_TYPE_METHOD_DECODEXML_NOTIMPL(%(name)s)''')
-    
-    # 8) Delete
-    printc('''void %(name)s_delete(%(name)s *p) {
-	%(name)s_deleteMembers(p);
-	UA_free(p);\n}\n''')
-	
-    # 9) DeleteMembers
-    printc('''void %(name)s_deleteMembers(%(name)s *p) {''')
-    for n,t in membermap.iteritems():
-        if not t in fixed_size: # dynamic size on the wire
-            if t.find("*") != -1:
-		printc("\tUA_Array_delete((void*)p->%(n)s,p->%(n)sSize,&UA_TYPES["+t[0:t.find("*")].upper()+"]);")
-            else:
-		printc('\t%(t)s_deleteMembers(&p->%(n)s);')
-    printc("}\n")
-
-    # 10) Init
-    printc('''void %(name)s_init(%(name)s *p) {
-    if(!p) return;''')
-    for n,t in membermap.iteritems():
-        if t.find("*") != -1:
-            printc('\tp->%(n)sSize = -1;')
-            printc('\tp->%(n)s = UA_NULL;')
-        else:
-            printc('\t%(t)s_init(&p->%(n)s);')
-    printc("}\n")
-
-    # 11) New
-    printc("UA_TYPE_NEW_DEFAULT(%(name)s)")
-
-    # 12) Copy
-    printc('''UA_StatusCode %(name)s_copy(const %(name)s *src,%(name)s *dst) {
-	UA_StatusCode retval = UA_STATUSCODE_GOOD;''')
-    printc("\t%(name)s_init(dst);")
-    for n,t in membermap.iteritems():
-        if t.find("*") != -1:
-            printc('\tdst->%(n)sSize = src->%(n)sSize;')
-            printc("\tretval |= UA_Array_copy(src->%(n)s, src->%(n)sSize,&UA_TYPES[" + t[0:t.find("*")].upper() + "],(void**)&dst->%(n)s);")
-            continue
-        if not t in fixed_size: # there are members of variable size    
-            printc('\tretval |= %(t)s_copy(&src->%(n)s,&dst->%(n)s);')
-            continue
-        printc("\tdst->%(n)s = src->%(n)s;")
-    printc('''\tif(retval)
-    \t%(name)s_deleteMembers(dst);''')
-    printc("\treturn retval;\n}\n")
-
-    # 13) Print
-    printc('''#ifdef UA_DEBUG''') 
-    printc('''void %(name)s_print(const %(name)s *p, FILE *stream) {
-    fprintf(stream, "(%(name)s){");''')
-    for i,(n,t) in enumerate(membermap.iteritems()):
-        if t.find("*") != -1:
-            printc('\tUA_Int32_print(&p->%(n)sSize, stream);')
-            printc("\tUA_Array_print(p->%(n)s, p->%(n)sSize, &UA_TYPES[" + t[0:t.find("*")].upper()+"], stream);")
-        else:
-            printc('\t%(t)s_print(&p->%(n)s,stream);')
-        if i == len(membermap)-1:
-            continue
-	printc('\tfprintf(stream, ",");')
-    printc('''\tfprintf(stream, "}");\n}''')
-    printc('#endif');
-    printc('''\n''')
-
-##########################
-# Header and Boilerplate #
-##########################
-    
-printh('''/**
- * @file %(outname)s_generated.h
- *
- * @brief Autogenerated data types defined in the UA standard
- *
- * Generated from %(inname)s with script ''' + sys.argv[0] + '''
- * on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
- */
-
-#ifndef ''' + outname.upper() + '''_GENERATED_H_
-#define ''' + outname.upper() + '''_GENERATED_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "ua_types.h"
-#include "ua_types_encoding_binary.h"
-
-/**
- * @ingroup types
- *
- * @defgroup ''' + outname + '''_generated Autogenerated ''' + outname + ''' Types
- *
- * @brief Data structures that are autogenerated from an XML-Schema.
- * @{
- */''')
-if args.with_xml:
-	printh('#include "ua_types_encoding_xml.h"')
-if args.additional_includes:
-    for incl in args.additional_includes.split(","):
-        printh("#include \"" + incl + "\"")
-
-printc('''/**
- * @file ''' + outname + '''_generated.c
- *
- * @brief Autogenerated function implementations to manage the data types defined in the UA standard
- *
- * Generated from %(inname)s with script '''+sys.argv[0]+'''
- * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
- */
- 
-#include "%(outname)s_generated.h"
-#include "ua_types_macros.h"
-#include "ua_namespace_0.h"
-#include "ua_util.h"\n''')
-
-##############################
-# Loop over types in the XML #
-##############################
-
-# # plugin handling
-# import os
-# files = [f for f in os.listdir('.') if os.path.isfile(f) and f[-3:] == ".py" and f[:7] == "plugin_"]
-# plugin_types = []
-# packageForType = OrderedDict()
-#
-# for f in files:
-# 	package = f[:-3]
-# 	exec "import " + package
-# 	exec "pluginSetup = " + package + ".setup()"
-# 	if pluginSetup["pluginType"] == "structuredObject":
-# 		plugin_types.append(pluginSetup["tagName"])
-# 		packageForType[pluginSetup["tagName"]] = [package,pluginSetup]
-# 		print("Custom object creation for tag " + pluginSetup["tagName"] + " imported from package " + package)
-
-deferred_types = OrderedDict()
-for element in types:
-	name = element.get("Name")
-	if skipType(name):
-		continue
-	if element.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
-		createEnumerated(element)
-		existing_types.add(name)
-	elif element.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
-		if printableStructuredType(element):
-			createStructured(element)
-			existing_types.add(name)
-		else: # the record contains types that were not yet detailed
-			deferred_types[name] = element
-			continue
-	elif element.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
-		createOpaque(element)
-		existing_types.add(name)
-
-for name, element in deferred_types.iteritems():
-    # if name in plugin_types:
-    #     #execute plugin if registered
-    #     exec "ret = " + packageForType[name][0]+"."+packageForType[name][1]["functionCall"]
-    #     if ret == "default":
-    #         createStructured(element)
-    #         existing_types.add(name)
-    # else:
-    createStructured(element)
-    existing_types.add(name)
-
-#############
-# Finish Up #
-#############
-
-printh('''
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-/// @} /* end of group */''')
-printh('#endif')
-
-fh.close()
-fc.close()

+ 467 - 0
tools/generate_datatypes.py

@@ -0,0 +1,467 @@
+from __future__ import print_function
+import sys
+import time
+import platform
+import getpass
+from collections import OrderedDict
+import re
+from lxml import etree
+import itertools
+import argparse
+
+fixed_size = {"UA_Boolean": 1, "UA_SByte": 1, "UA_Byte": 1, "UA_Int16": 2, "UA_UInt16": 2,
+              "UA_Int32": 4, "UA_UInt32": 4, "UA_Int64": 8, "UA_UInt64": 8, "UA_Float": 4,
+              "UA_Double": 8, "UA_DateTime": 8, "UA_Guid": 16, "UA_StatusCode": 4}
+
+zero_copy = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_Int32", "UA_UInt32",
+             "UA_Int64", "UA_UInt64", "UA_Float", "UA_Double", "UA_DateTime", "UA_StatusCode"]
+
+# The order of the builtin-types is not as in the standard. We put all the
+# fixed_size types in the front, so they can be distinguished by a simple geq
+# comparison. That's ok, since we use the type-index only internally!!
+builtin_types = ["UA_Boolean", "UA_SByte", "UA_Byte", # 1 byte
+                 "UA_Int16", "UA_UInt16", # 2 bytes
+                 "UA_Int32", "UA_UInt32",  "UA_StatusCode", "UA_Float", # 4 byte
+                 "UA_Int64", "UA_UInt64", "UA_Double", "UA_DateTime", # 8 byte
+                 "UA_Guid", "UA_NodeId", "UA_ExpandedNodeId", "UA_QualifiedName", "UA_LocalizedText", "UA_ExtensionObject", "UA_DataValue", "UA_Variant", "UA_DiagnosticInfo", # fancy types
+                 "UA_String", "UA_ByteString", "UA_XmlElement" # strings (handled as structured types with a single array entry)
+]
+
+excluded_types = ["UA_NodeIdType", "UA_InstanceNode", "UA_TypeNode", "UA_Node", "UA_ObjectNode",
+                  "UA_ObjectTypeNode", "UA_VariableNode", "UA_VariableTypeNode", "UA_ReferenceTypeNode",
+                  "UA_MethodNode", "UA_ViewNode", "UA_DataTypeNode", "UA_ServerDiagnosticsSummaryDataType",
+                  "UA_SamplingIntervalDiagnosticsDataType", "UA_SessionSecurityDiagnosticsDataType",
+                  "UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
+
+class TypeDescription(object):
+    def __init__(self, name, nodeid, namespaceid):
+        self.name = name # without the UA_ prefix
+        self.nodeid = nodeid
+        self.namespaceid = namespaceid
+
+def parseTypeDescriptions(filename, namespaceid):
+    definitions = {}
+    f = open(filename[0])
+    input_str = f.read()
+    f.close()
+    input_str = input_str.replace('\r','')
+    rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
+    for index, row in enumerate(rows):
+        if len(row) < 3:
+            continue
+        if row[2] != "DataType":
+            continue
+        if row[0] == "BaseDataType":
+            definitions["UA_Variant"] = TypeDescription(row[0], row[1], namespaceid)
+        elif row[0] == "Structure":
+            definitions["UA_ExtensionObject"] = TypeDescription(row[0], row[1], namespaceid)
+        else:
+            definitions["UA_" + row[0]] = TypeDescription(row[0], row[1], namespaceid)
+    return definitions
+
+class BuiltinType(object):
+    "Generic type without members. Used for builtin types."
+    def __init__(self, name, description = ""):
+        self.name = name
+        self.description = description
+
+    def fixed_size(self):
+        return self.name in fixed_size
+
+    def mem_size(self):
+        return fixed_size[self.name]
+
+    def zero_copy(self):
+        return self.name in zero_copy
+
+    def typedef_c(self):
+        pass
+
+    def typelayout_c(self, namespace_0, outname):
+        return "{.memSize = sizeof(" + self.name + "), " + \
+            ".namespaceZero = UA_TRUE, " + \
+            ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
+            ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
+            ", .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + "," + \
+            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, " + \
+            ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
+
+class EnumerationType(object):
+    def __init__(self, name, description = "", elements = OrderedDict()):
+        self.name = name
+        self.description = description
+        self.elements = elements # maps a name to an integer value
+
+    def append_enum(name, value):
+        self.elements[name] = value
+
+    def fixed_size(self):
+        return True
+
+    def mem_size(self):
+        return 4
+
+    def zero_copy(self):
+        return True
+
+    def typedef_c(self):
+        return "typedef enum { \n    " + \
+            ",\n    ".join(map(lambda (key,value) : key.upper() + " = " + value,self.elements.iteritems())) + \
+            "\n} " + self.name + ";"
+
+    def typelayout_c(self, namespace_0, outname):
+        return "{.memSize = sizeof(" + self.name + "), " +\
+            ".namespaceZero = " + ("UA_TRUE" if namespace_0 else "UA_FALSE") + \
+            ", .fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
+            ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32," + \
+            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
+
+    def functions_c(self, typeTableName):
+        return '''#define %s_new (%s*)UA_Int32_new
+#define %s_init(p) UA_Int32_init((UA_Int32*)p)
+#define %s_delete(p) UA_Int32_delete((UA_Int32*)p)
+#define %s_deleteMembers(p) UA_Int32_deleteMembers((UA_Int32*)p)
+#define %s_copy(src, dst) UA_Int32_copy((const UA_Int32*)src, (UA_Int32*)dst)
+#define %s_calcSizeBinary(p) UA_Int32_calcSizeBinary((UA_Int32*)p)
+#define %s_encodeBinary(src, dst, offset) UA_Int32_encodeBinary((UA_Int32*)src, dst, offset)
+#define %s_decodeBinary(src, offset, dst) UA_Int32_decodeBinary(src, offset, (UA_Int32*)dst)''' % tuple(itertools.repeat(self.name, 9))
+
+class OpaqueType(object):
+    def __init__(self, name, description = ""):
+        self.name = name
+        self.description = description
+
+    def fixed_size(self):
+        return False
+
+    def zero_copy(self):
+        return False
+
+    def typedef_c(self):
+        return "typedef UA_ByteString " + self.name + ";"
+
+    def typelayout_c(self, namespace_0, outname):
+        return "{.memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+            ".namespaceZero = " + ("UA_TRUE" if namespace_0 else "UA_FALSE") + \
+            ", .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTESTRING," + \
+            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
+
+    def functions_c(self, typeTableName):
+        return '''#define %s_new UA_ByteString_new
+#define %s_init UA_ByteString_init
+#define %s_delete UA_ByteString_delete
+#define %s_deleteMembers UA_ByteString_deleteMembers
+#define %s_copy UA_ByteString_copy
+#define %s_calcSizeBinary UA_ByteString_calcSizeBinary
+#define %s_encodeBinary UA_ByteString_encodeBinary
+#define %s_decodeBinary UA_ByteString_decodeBinary''' % tuple(itertools.repeat(self.name, 8))
+
+class StructMember(object):
+    def __init__(self, name, memberType, isArray):
+        self.name = name
+        self.memberType = memberType
+        self.isArray = isArray
+
+class StructType(object):
+    def __init__(self, name, description, members = OrderedDict()):
+        self.name = name
+        self.description = description
+        self.members = members # maps a name to a member definition
+
+    def fixed_size(self):
+        for m in self.members.values():
+            if m.isArray or not m.memberType.fixed_size():
+                return False
+        return True
+
+    def mem_size(self):
+        total = 0
+        for m in self.members.values():
+            if m.isArray:
+                raise Exception("Arrays have no fixed size!")
+            else:
+                total += m.memberType.mem_size()
+        return total
+
+    def zero_copy(self):
+        for m in self.members.values():
+            if m.isArray or not m.memberType.zero_copy():
+                return False
+        return True
+
+    def typedef_c(self):
+        if len(self.members) == 0:
+            return "typedef void * " + self.name + ";"
+        returnstr =  "typedef struct {\n"
+        for name, member in self.members.iteritems():
+            if member.isArray:
+                returnstr += "    UA_Int32 " + name + "Size;\n"
+                returnstr += "    " + member.memberType.name + " *" +name + ";\n"
+            else:
+                returnstr += "    " + member.memberType.name + " " +name + ";\n"
+        return returnstr + "} " + self.name + ";"
+
+    def typelayout_c(self, namespace_0, outname):
+        layout = "{.memSize = sizeof(" + self.name + "), "+ \
+                 ".namespaceZero = " + ("UA_TRUE" if namespace_0 else "UA_FALSE") + \
+                 ", .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
+                 ", .zeroCopyable = " + ("sizeof(" + self.name + ") == " + str(self.mem_size()) if self.zero_copy() \
+                                         else "UA_FALSE") + \
+                 ", .typeIndex = " + outname.upper() + "_" + self.name[3:].upper() + \
+                 ", .membersSize = " + str(len(self.members)) + ","
+        if len(self.members) > 0:
+            layout += "\n\t.members={"
+            for index, member in enumerate(self.members.values()):
+                layout += "\n\t{" + \
+                          ".memberTypeIndex = " + ("UA_TYPES_" + member.memberType.name[3:].upper() if args.namespace_id == 0 or member.memberType.name in existing_types else \
+                                                   outname.upper() + "_" + member.memberType.name[3:].upper()) + ", " + \
+                          ".namespaceZero = "+ \
+                          ("UA_TRUE, " if args.namespace_id == 0 or member.memberType.name in existing_types else "UA_FALSE, ") + \
+                          ".padding = "
+
+                before_endpos = "0"
+                thispos = "offsetof(%s, %s)" % (self.name, member.name)
+                if index > 0:
+                    before = self.members.values()[index-1]
+                    before_endpos = "(offsetof(%s, %s)" % (self.name, before.name)
+                    if before.isArray:
+                        before_endpos += " + sizeof(void*))"
+                    else:
+                        before_endpos += " + sizeof(%s))" % before.memberType.name
+            
+                if member.isArray:
+                    # the first two bytes are padding for the length index, the last three for the pointer
+                    length_pos = "offsetof(%s, %sSize)" % (self.name, member.name)
+                    if index != 0:
+                        layout += "((%s - %s) << 3) + " % (length_pos, before_endpos)
+                    layout += "(%s - sizeof(UA_Int32) - %s)" % (thispos, length_pos)
+                else:
+                    layout += "%s - %s" % (thispos, before_endpos)
+                layout += ", .isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
+            layout += "}"
+        return layout + "}"
+
+    def functions_c(self, typeTableName):
+        return '''#define %s_new() UA_new(%s)
+#define %s_init(p) UA_init(p, %s)
+#define %s_delete(p) UA_delete(p, %s)
+#define %s_deleteMembers(p) UA_deleteMembers(p, %s)
+#define %s_copy(src, dst) UA_copy(src, dst, %s)
+#define %s_calcSizeBinary(p) UA_calcSizeBinary(p, %s)
+#define %s_encodeBinary(src, dst, offset) UA_encodeBinary(src, %s, dst, offset)
+#define %s_decodeBinary(src, offset, dst) UA_decodeBinary(src, offset, dst, %s)''' % \
+    tuple(itertools.chain(*itertools.repeat([self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 8)))
+
+def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
+    '''Returns an ordered dict that maps names to types. The order is such that
+       every type depends only on known types. '''
+    ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
+    tree = etree.parse(xmlDescription)
+    typeSnippets = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
+    types = OrderedDict(existing_types.items())
+
+    # types we do not want to autogenerate
+    def skipType(name):
+        if name in builtin_types:
+            return True
+        if name in excluded_types:
+            return True
+        if "Test" in name: # skip all test types
+            return True
+        if re.search("NodeId$", name) != None:
+            return True
+        return False
+
+    def stripTypename(tn):
+        return tn[tn.find(":")+1:]
+
+    def camlCase2CCase(item):
+        "Member names begin with a lower case character"
+        return item[:1].lower() + item[1:] if item else ''
+
+    def typeReady(element):
+        "Do we have the member types yet?"
+        for child in element:
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
+                if stripTypename(child.get("TypeName")) not in types:
+                    return False
+        return True
+
+    def parseEnumeration(typeXml):	
+        name = "UA_" + typeXml.get("Name")
+        description = ""
+        elements = OrderedDict()
+        for child in typeXml:
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
+                description = child.text
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedValue":
+                elements[name + "_" + child.get("Name")] = child.get("Value")
+        return EnumerationType(name, description, elements)
+
+    def parseOpaque(typeXml):
+        name = "UA_" + typeXml.get("Name")
+        description = ""
+        for child in typeXml:
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
+                description = child.text
+        return OpaqueType(name, description)
+
+    def parseStructured(typeXml):
+        "Returns None if we miss member descriptions"
+        name = "UA_" + typeXml.get("Name")
+        description = ""
+        for child in typeXml:
+            if child.tag == "{http://opcfoundation.org/BinarySchema/}Documentation":
+                description = child.text
+        # ignore lengthfields, just tag the array-members as an array
+        lengthfields = []
+        for child in typeXml:
+            if child.get("LengthField"):
+                lengthfields.append(child.get("LengthField"))
+        members = OrderedDict()
+        for child in typeXml:
+            if not child.tag == "{http://opcfoundation.org/BinarySchema/}Field":
+                continue
+            if child.get("Name") in lengthfields:
+                continue
+            memberTypeName = "UA_" + stripTypename(child.get("TypeName"))
+            if not memberTypeName in types:
+                return None
+            memberType = types[memberTypeName]
+            memberName = camlCase2CCase(child.get("Name"))
+            isArray = True if child.get("LengthField") else False
+            members[memberName] = StructMember(memberName, memberType, isArray)
+        return StructType(name, description, members)
+
+    finished = False
+    while(not finished):
+        finished = True
+        for typeXml in typeSnippets:
+            name = "UA_" + typeXml.get("Name")
+            if name in types or skipType(name):
+                continue
+            if typeXml.tag == "{http://opcfoundation.org/BinarySchema/}EnumeratedType":
+                t = parseEnumeration(typeXml)
+                types[t.name] = t
+            elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}OpaqueType":
+                t = parseOpaque(typeXml)
+                types[t.name] = t
+            elif typeXml.tag == "{http://opcfoundation.org/BinarySchema/}StructuredType":
+                t = parseStructured(typeXml)
+                if t == None:
+                    finished = False
+                else:
+                    types[t.name] = t
+
+    # remove the existing types
+    for k in existing_types.keys():
+        types.pop(k)
+    return types
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--ns0-types-xml', nargs=1, help='xml-definition of the ns0 types that are assumed to already exist')
+parser.add_argument('--typedescriptions', nargs=1, help='csv file with type descriptions')
+parser.add_argument('namespace_id', type=int, help='the id of the target namespace')
+parser.add_argument('types_xml', help='path/to/Opc.Ua.Types.bsd')
+parser.add_argument('outfile', help='output file w/o extension')
+
+args = parser.parse_args()
+outname = args.outfile.split("/")[-1] 
+inname = args.types_xml.split("/")[-1]
+existing_types = OrderedDict()
+if args.namespace_id == 0 or args.ns0_types_xml:
+    existing_types = OrderedDict([(t, BuiltinType(t)) for t in builtin_types])
+if args.ns0_types_xml:
+    OrderedDict(existing_types.items() + parseTypeDefinitions(args.ns0_types_xml[0], existing_types).items())
+types = parseTypeDefinitions(args.types_xml, existing_types)
+if args.namespace_id == 0:
+    types = OrderedDict(existing_types.items() + types.items())
+
+typedescriptions = {}
+if args.typedescriptions:
+    typedescriptions = parseTypeDescriptions(args.typedescriptions, args.namespace_id)
+
+fh = open(args.outfile + "_generated.h",'w')
+fc = open(args.outfile + "_generated.c",'w')
+def printh(string):
+    print(string, end='\n', file=fh)
+def printc(string):
+    print(string, end='\n', file=fc)
+
+printh('''/**
+* @file ''' + outname + '''_generated.h
+*
+* @brief Autogenerated data types
+*
+* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
+* on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
+*/
+
+#ifndef ''' + outname.upper() + '''_GENERATED_H_
+#define ''' + outname.upper() + '''_GENERATED_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_types.h" '''
+ + ('\n#include "ua_types_generated.h"\n' if args.namespace_id != 0 else '') + '''
+
+/**
+* @ingroup types
+*
+* @defgroup ''' + outname + '''_generated Autogenerated ''' + outname + ''' Types
+*
+* @brief Data structures that are autogenerated from an XML-Schema.
+*
+* @{
+*/
+''')
+printh("#define " + outname.upper() + "_COUNT %s\n" % (str(len(types))))
+printh("extern UA_EXPORT const UA_DataType *" + outname.upper() + ";\n")
+printh("extern UA_EXPORT const UA_UInt32 *" + outname.upper() + "_IDS;\n")
+
+i = 0
+for t in types.itervalues():
+    if type(t) != BuiltinType:
+        printh("")
+        if t.description != "":
+            printh("/** @brief " + t.description + " */")
+        printh(t.typedef_c())
+    printh("#define " + outname.upper() + "_" + t.name[3:].upper() + " " + str(i))
+    if type(t) != BuiltinType:
+        printh(t.functions_c(outname.upper()))
+    i += 1
+
+printh('''
+/// @} /* end of group */\n
+#ifdef __cplusplus
+} // extern "C"
+#endif\n
+#endif''')
+
+printc('''/**
+* @file ''' + outname + '''_generated.c
+*
+* @brief Autogenerated data types
+*
+* Generated from ''' + inname + ''' with script ''' + sys.argv[0] + '''
+* on host ''' + platform.uname()[1] + ''' by user ''' + getpass.getuser() + ''' at ''' + time.strftime("%Y-%m-%d %I:%M:%S") + '''
+*/\n
+#include "stddef.h"
+#include "ua_types.h"
+#include "''' + outname + '''_generated.h"\n
+const UA_DataType *''' + outname.upper() + ''' = (UA_DataType[]){''')
+for t in types.itervalues():
+    printc("")
+    printc("/* " + t.name + " */")
+    printc(t.typelayout_c(args.namespace_id == 0, outname) + ",")
+printc("};\n")
+if args.typedescriptions:
+    printc('const UA_UInt32 *' + outname.upper() + '_IDS = (UA_UInt32[]){')
+    for t in types.itervalues():
+        print(str(typedescriptions[t.name].nodeid) + ", ", end='', file=fc)
+    printc("};")
+
+fh.close()
+fc.close()

+ 0 - 237
tools/generate_namespace.py

@@ -1,237 +0,0 @@
-from __future__ import print_function
-import inspect
-import sys
-import platform
-import getpass
-import time
-import re
-import argparse
-
-parser = argparse.ArgumentParser()
-parser.add_argument('--with-xml', action='store_true', help='generate xml encoding')
-parser.add_argument('--with-json', action='store_true', help='generate json encoding')
-parser.add_argument('--only-needed', action='store_true', help='generate only types needed for compile')
-parser.add_argument('nodeids', help='path/to/NodeIds.csv')
-parser.add_argument('outfile', help='outfile w/o extension')
-args = parser.parse_args()
-
-# whitelist for "only needed" profile
-from type_lists import only_needed_types
-
-# types that are to be excluded
-exclude_types = set(["Number", "Integer", "UInteger", "Enumeration", "Image", "ImageBMP",
-                     "ImageGIF", "ImageJPG", "ImagePNG", "References", "BaseVariableType",
-                     "BaseDataVariableType", "PropertyType", "DataTypeDescriptionType",
-                     "DataTypeDictionaryType", "NamingRuleType", "IntegerId", "Counter",
-                     "Duration", "NumericRange", "Time", "Date", "UtcTime", "LocaleId",
-                     "UserTokenType", "ApplicationType", "ApplicationInstanceCertificate",
-                     "ServerVendorCapabilityType", "ServerStatusType",
-                     "ServerDiagnosticsSummaryType", "SamplingIntervalDiagnosticsArrayType",
-                     "SamplingIntervalDiagnosticsType", "SubscriptionDiagnosticsArrayType",
-                     "SubscriptionDiagnosticsType", "SessionDiagnosticsArrayType",
-                     "SessionDiagnosticsVariableType", "SessionSecurityDiagnosticsArrayType",
-                     "SessionSecurityDiagnosticsType", "DataItemType", "AnalogItemType",
-                     "DiscreteItemType", "TwoStateDiscreteType", "MultiStateDiscreteType",
-                     "ProgramDiagnosticType", "StateVariableType", "FiniteStateVariableType",
-                     "TransitionVariableType", "FiniteTransitionVariableType", "BuildInfoType",
-                     "TwoStateVariableType", "ConditionVariableType",
-                     "MultiStateValueDiscreteType", "OptionSetType", "ArrayItemType",
-                     "YArrayItemType", "XYArrayItemType", "ImageItemType", "CubeItemType",
-                     "NDimensionArrayItemType"])
-
-fixed_size = ['UA_DeadbandType', 'UA_DataChangeTrigger', 'UA_Guid', 'UA_ApplicationType',
-              'UA_ComplexNumberType', 'UA_EnumeratedTestType', 'UA_BrowseResultMask',
-              'UA_TimeZoneDataType', 'UA_NodeClass', 'UA_IdType', 'UA_ServiceCounterDataType',
-              'UA_Float', 'UA_ModelChangeStructureVerbMask', 'UA_EndpointConfiguration',
-              'UA_NodeAttributesMask', 'UA_DataChangeFilter', 'UA_StatusCode',
-              'UA_MonitoringFilterResult', 'UA_OpenFileMode', 'UA_SecurityTokenRequestType',
-              'UA_ServerDiagnosticsSummaryDataType', 'UA_ElementOperand',
-              'UA_AggregateConfiguration', 'UA_UInt64', 'UA_FilterOperator',
-              'UA_ReadRawModifiedDetails', 'UA_ServerState', 'UA_FilterOperand',
-              'UA_SubscriptionAcknowledgement', 'UA_AttributeWriteMask', 'UA_SByte', 'UA_Int32',
-              'UA_Range', 'UA_Byte', 'UA_TimestampsToReturn', 'UA_UserTokenType', 'UA_Int16',
-              'UA_XVType', 'UA_AggregateFilterResult', 'UA_Boolean', 'UA_MessageSecurityMode',
-              'UA_AxisScaleEnumeration', 'UA_PerformUpdateType', 'UA_UInt16',
-              'UA_NotificationData', 'UA_DoubleComplexNumberType', 'UA_HistoryUpdateType',
-              'UA_MonitoringFilter', 'UA_NodeIdType', 'UA_BrowseDirection',
-              'UA_SamplingIntervalDiagnosticsDataType', 'UA_UInt32', 'UA_ChannelSecurityToken',
-              'UA_RedundancySupport', 'UA_MonitoringMode', 'UA_HistoryReadDetails',
-              'UA_ExceptionDeviationFormat', 'UA_ComplianceLevel', 'UA_DateTime', 'UA_Int64',
-              'UA_Double']
-
-def useDataType(row):
-    if row[0] == "" or row[0] in exclude_types:
-        return False
-    if row[2] != "DataType":
-        return False
-    if "Test" in row[0]:
-        return False
-    if args.only_needed and not(row[0] in only_needed_types):
-        return False
-    return True
-
-type_names = [] # the names of the datattypes for which we create a vtable entry
-def useOtherType(row):
-    if row[0] in type_names or row[0] == "":
-        return False
-    if row[0].startswith("Audit"):
-        return False
-    if row[0].startswith("Program"):
-        return False
-    if row[0].startswith("Condition"):
-        return False
-    if row[0].startswith("Refresh"):
-        return False
-    if row[0].startswith("OpcUa_"):
-        return False
-    if row[0].startswith("SessionsDiagnosticsSummaryType_"):
-        return False
-    if "Type_" in row[0]:
-        return False
-    if "_Encoding_Default" in row[0]:
-        return False
-    return True
-
-f = open(args.nodeids)
-input_str = f.read() + "\nInvalidType,0,DataType" + "\nHasModelParent,50,ReferenceType"
-f.close()
-input_str = input_str.replace('\r','')
-rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
-for index, row in enumerate(rows):
-    if row[0] == "BaseDataType":
-    	rows[index]= ("Variant", row[1], row[2])
-    elif row[0] == "Structure":
-    	rows[index] = ("ExtensionObject", row[1], row[2])
-
-fh = open(args.outfile + ".h",'w')
-fc = open(args.outfile + ".c",'w')
-def printh(string):
-    print(string % inspect.currentframe().f_back.f_locals, end='\n', file=fh)
-
-def printc(string):
-    print(string % inspect.currentframe().f_back.f_locals, end='\n', file=fc)
-
-printh('''/**********************************************************
- * '''+args.outfile+'''.hgen -- do not modify
- **********************************************************
- * Generated from '''+args.nodeids+''' with script '''+sys.argv[0]+'''
- * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+
-       time.strftime("%Y-%m-%d %I:%M:%S")+'''
- **********************************************************/\n 
-#ifndef ''' + args.outfile.upper().split("/")[-1] + '''_H_
-#define ''' + args.outfile.upper().split("/")[-1] + '''_H_\n
-#include "ua_types.h"  // definition of UA_VTable and basic UA_Types
-#include "ua_types_generated.h"\n
-/**
- * @brief maps namespace zero nodeId to index into UA_VTable
- *
- * @param[in] id The namespace zero nodeId
- *
- * @retval UA_ERR_INVALID_VALUE whenever ns0Id could not be mapped
- * @retval the corresponding index into UA_VTable
- */
-
-UA_UInt32 UA_ns0ToVTableIndex(const UA_NodeId *id);\n
-extern const UA_TypeVTable UA_EXPORT *UA_TYPES;
-extern const UA_NodeId UA_EXPORT *UA_NODEIDS;
-extern const UA_ExpandedNodeId UA_EXPORT *UA_EXPANDEDNODEIDS;
-
-/** The entries of UA_TYPES can be accessed with the following indices */ ''')
-
-printc('''/**********************************************************
- * '''+args.outfile.split("/")[-1]+'''.cgen -- do not modify
- **********************************************************
- * Generated from '''+args.nodeids+''' with script '''+sys.argv[0]+'''
- * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser() +
-       ''' at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
- **********************************************************/\n
-#include "''' + args.outfile.split("/")[-1] + '''.h"\n
-#include "ua_util.h"
-UA_UInt32 UA_ns0ToVTableIndex(const UA_NodeId *id) {
-	UA_Int32 retval = 0; // InvalidType
-        if(id->namespaceIndex != 0) return retval;
-	switch (id->identifier.numeric) {''')
-
-i = 0
-for index, row in enumerate(rows):
-    if not useDataType(row):
-        continue
-    type_names.append(row[0])
-    name = "UA_" + row[0]
-    printh("#define "+name.upper()+" "+str(i))
-    printh('#define '+name.upper()+'_NS0 '+row[1])
-    printc('\tcase '+row[1]+': retval='+name.upper()+'; break; //'+row[2])
-    i = i+1
-printc('''\t}\n\treturn retval;\n}\n''');
-
-printh('\n#define SIZE_UA_VTABLE '+str(i));
-printh("") # newline
-
-printh("/* Now all the non-datatype nodeids */")
-for row in rows:
-    if not useOtherType(row):
-        continue
-    name = "UA_" + row[0]
-    printh("#define "+name.upper()+" "+str(i))
-    printh('#define '+name.upper()+'_NS0 '+row[1])
-    i=i+1
-
-printc('''const UA_TypeVTable *UA_TYPES = (UA_TypeVTable[]){''')
-for row in rows:
-    if row[0] not in type_names:
-        continue
-    name = "UA_" + row[0]
-    printc("\t{.typeId={.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric=" + row[1] + "}" + 
-           ",\n.name=(UA_Byte*)&\"%(name)s\"" +
-           ",\n.new=(void *(*)(void))%(name)s_new" +
-           ",\n.init=(void(*)(void *))%(name)s_init"+
-           ",\n.copy=(UA_StatusCode(*)(void const * ,void*))%(name)s_copy" +
-           ",\n.delete=(void(*)(void *))%(name)s_delete" +
-           ",\n.deleteMembers=(void(*)(void *))%(name)s_deleteMembers" +
-           ",\n#ifdef UA_DEBUG //FIXME: seems to be okay atm, however a pointer to a noop function would be more safe" + 
-           "\n.print=(void(*)(const void *, FILE *))%(name)s_print," +
-           "\n#endif" + 
-           "\n.memSize=" + ("sizeof(%(name)s)" if (name != "UA_InvalidType") else "0") +
-           ",\n.dynMembers=" + ("UA_FALSE" if (name in fixed_size) else "UA_TRUE") +
-           ",\n.encodings={{.calcSize=(UA_UInt32(*)(const void*))%(name)s_calcSizeBinary" +
-           ",\n.encode=(UA_StatusCode(*)(const void*,UA_ByteString*,UA_UInt32*))%(name)s_encodeBinary" +
-           ",\n.decode=(UA_StatusCode(*)(const UA_ByteString*,UA_UInt32*,void*))%(name)s_decodeBinary}" +
-           (",\n{.calcSize=(UA_Int32(*)(const void*))%(name)s_calcSizeXml" +
-            ",\n.encode=(UA_StatusCode(*)(const void*,UA_ByteString*,UA_UInt32*))%(name)s_encodeXml" +
-            ",\n.decode=(UA_StatusCode(*)(const UA_ByteString*,UA_UInt32*,void*))%(name)s_decodeXml}" if (args.with_xml) else "") +
-           "}},")
-
-printc('};\n')
-
-# make the nodeids available as well
-printc('''const UA_NodeId *UA_NODEIDS = (UA_NodeId[]){''')
-for row in rows:
-    if not row[0] in type_names:
-        continue
-    printc("\t{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = " + row[1] + "},")
-
-for row in rows:
-    if not useOtherType(row):
-        continue
-    printc("\t{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = " + row[1] + "},")
-printc('};\n')
-
-# and generate expanded nodeids
-printc('''const UA_ExpandedNodeId *UA_EXPANDEDNODEIDS = (UA_ExpandedNodeId[]){''')
-for row in rows:
-    if not row[0] in type_names:
-        continue
-    printc("\t{.nodeId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = " + row[1] +
-           "}, .namespaceUri = {.length = -1, .data = UA_NULL}, .serverIndex = 0},")
-
-for row in rows:
-    if not useOtherType(row):
-        continue
-    printc("\t{.nodeId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = " + row[1] +
-           "}, .namespaceUri = {.length = -1, .data = UA_NULL}, .serverIndex = 0},")
-printc('};')
-
-printh('\n#endif /* OPCUA_NAMESPACE_0_H_ */')
-
-fh.close()
-fc.close()

+ 62 - 0
tools/generate_nodeids.py

@@ -0,0 +1,62 @@
+from __future__ import print_function
+import inspect
+import sys
+import platform
+import getpass
+import time
+import re
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('nodeids', help='path/to/NodeIds.csv')
+parser.add_argument('outfile', help='outfile w/o extension')
+args = parser.parse_args()
+
+def useNodeId(row):
+    if row[0] == "":
+        return False
+    if "Test" in row[0]:
+        return False
+    if row[0].startswith("OpcUa_"):
+        return False
+    if row[0].startswith("SessionsDiagnosticsSummaryType_"):
+        return False
+    if "Type_" in row[0]:
+        return False
+    if "_Encoding_Default" in row[0]:
+        return False
+    return True
+
+f = open(args.nodeids)
+input_str = f.read() + "\nHasModelParent,50,ReferenceType"
+f.close()
+input_str = input_str.replace('\r','')
+rows = map(lambda x:tuple(x.split(',')), input_str.split('\n'))
+for index, row in enumerate(rows):
+    if row[0] == "BaseDataType":
+    	rows[index]= ("Variant", row[1], row[2])
+    elif row[0] == "Structure":
+    	rows[index] = ("ExtensionObject", row[1], row[2])
+
+fh = open(args.outfile + ".h",'w')
+def printh(string):
+    print(string, end='\n', file=fh)
+
+printh('''/**********************************************************
+ * '''+args.outfile+'''.hgen -- do not modify
+ **********************************************************
+ * Generated from '''+args.nodeids+''' with script '''+sys.argv[0]+'''
+ * on host '''+platform.uname()[1]+''' by user '''+getpass.getuser()+''' at '''+
+       time.strftime("%Y-%m-%d %I:%M:%S")+'''
+ **********************************************************/\n 
+#ifndef ''' + args.outfile.upper().split("/")[-1] + '''_H_
+#define ''' + args.outfile.upper().split("/")[-1] + '''_H_
+''')
+
+for row in rows:
+    if useNodeId(row):
+        printh("#define UA_NS0ID_%s %s // %s" % (row[0].upper(), row[1], row[2]))
+
+printh('\n#endif /* ' + args.outfile.upper().split("/")[-1] + '_H_ */')
+
+fh.close()

+ 0 - 13
tools/plugin_Node.py

@@ -1,13 +0,0 @@
-from __future__ import print_function
-
-def setup():
-	config = dict()
-	config["pluginType"] = "structuredObject";
-	config["tagName"] = "Node";
-	config["functionCall"] = "createElement(element, fc, fh)"
-	return config
-
-def createElement(element, fc, fh):
-	print("/* Hello from plugin */", end='\n', file=fc)
-	#return "default" to execute the default createElement
-	return "default"

+ 10 - 2
tools/schema/Custom.Opc.Ua.Transport.bsd

@@ -11,10 +11,18 @@
 
 <!-- Transport types begin  -->
 
+  <opc:EnumeratedType Name="MessageTypeAndFinal" LengthInBits="32">
+    <opc:Documentation>Message Type and whether the message contains the final chunk</opc:Documentation>
+    <opc:EnumeratedValue Name="ACKF" Value="1179337537" />
+    <opc:EnumeratedValue Name="CLOF" Value="1179601987" />
+    <opc:EnumeratedValue Name="HELF" Value="1179403592" />
+    <opc:EnumeratedValue Name="MSGF" Value="1179079501" />
+    <opc:EnumeratedValue Name="OPNF" Value="1179537487" />
+  </opc:EnumeratedType>
+
    <opc:StructuredType Name="TcpMessageHeader">
     <opc:Documentation>TCP Header</opc:Documentation>
-    <opc:Field Name="MessageType" TypeName="opc:MessageType" /> <!-- The MessageType type is custom and implemented by hand -->
-    <opc:Field Name="IsFinal" TypeName="opc:Byte" />
+    <opc:Field Name="MessageTypeAndFinal" TypeName="opc:UInt32" />
     <opc:Field Name="MessageSize" TypeName="opc:UInt32" />
   </opc:StructuredType>
   

+ 0 - 26
tools/type_lists.py

@@ -1,26 +0,0 @@
-existing_types = set(["Boolean", "SByte", "Byte", "Int16", "UInt16", "Int32", "UInt32",
-                      "Int64", "UInt64", "Float", "Double", "String", "DateTime", "Guid",
-                      "ByteString", "XmlElement", "NodeId", "ExpandedNodeId", "StatusCode", 
-                      "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue",
-                      "Variant", "DiagnosticInfo"])
-                      
-only_needed_types = set([	"InvalidType", "Node", "NodeClass", "ReferenceNode", "ApplicationDescription", "ApplicationType",
-							"ChannelSecurityToken", "OpenSecureChannelRequest", "OpenSecureChannelResponse", 
-							"CloseSecureChannelRequest", "CloseSecureChannelResponse", "RequestHeader", "ResponseHeader",
-							"SecurityTokenRequestType", "MessageSecurityMode", "CloseSessionResponse", "CloseSessionRquest",
-							"ActivateSessionRequest", "ActivateSessionResponse", "SignatureData", "SignedSoftwareCertificate",
-							"CreateSessionResponse", "CreateSessionRequest", "EndpointDescription", "UserTokenPolicy", "UserTokenType",
-							"GetEndpointsRequest", "GetEndpointsResponse", "PublishRequest", "PublishResponse", "SetPublishingModeResponse",
-							"SubscriptionAcknowledgement", "NotificationMessage", "ExtensionObject", "Structure",
-							"ReadRequest", "ReadResponse", "ReadValueId", "TimestampsToReturn", "WriteRequest", "WriteResponse",
-							"WriteValue", "SetPublishingModeRequest", "CreateMonitoredItemsResponse", "MonitoredItemCreateResult",
-							"CreateMonitoredItemsRequest", "MonitoredItemCreateRequest", "MonitoringMode", "MonitoringParameters",
-							"TranslateBrowsePathsToNodeIdsRequest", "TranslateBrowsePathsToNodeIdsResponse", "BrowsePath", "BrowsePathResult",
-							"RelativePath", "BrowsePathTarget", "RelativePathElement", "CreateSubscriptionRequest", "CreateSubscriptionResponse",
-							"BrowseResponse", "BrowseResult", "ReferenceDescription", "BrowseRequest", "ViewDescription", "BrowseDescription",
-							"BrowseDirection", "CloseSessionRequest", "AddNodesRequest", "AddNodesResponse", "AddNodesItem", "AddNodesResult",
-							"DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse", "AddReferencesItem","DeleteReferencesItem", "VariableNode",
-							"MethodNode", "VariableTypeNode", "ViewNode", "ReferenceTypeNode", "BrowseResultMask", "ServerState", "ServerStatusDataType",
-							"BuildInfo", "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "VariableAttributes","ObjectAttributes","NodeAttributes","ReferenceTypeAttributes", "ViewAttributes", "ObjectTypeAttributes", "NodeAttributesMask","DeleteNodesItem",
-							"DeleteNodesRequest", "DeleteNodesResponse", "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse"])
-only_needed_types = only_needed_types.union(existing_types)