Parcourir la source

Merge branch 'master' into client

Conflicts:
	CMakeLists.txt
	examples/networklayer_tcp.c
	examples/networklayer_tcp.h
	src/server/ua_server.c
	src/ua_util.h
Stasik0 il y a 10 ans
Parent
commit
d93f4e33f9
70 fichiers modifiés avec 3475 ajouts et 2107 suppressions
  1. 85 51
      .travis.yml
  2. 170 101
      CMakeLists.txt
  3. 10 13
      README.md
  4. 39 0
      bindings/CMakeLists.txt
  5. 45 0
      bindings/open62541.i
  6. 6 0
      cmake/Toolchain-gcc-m32.cmake
  7. 4 0
      cmake/Toolchain-mingw32.cmake
  8. 12 0
      cmake/Toolchain-rpi.cmake
  9. 12 0
      cmake/Toolchain-rpi64.cmake
  10. 9 4
      examples/client.c
  11. 11 0
      examples/client_proper.c
  12. 1 1
      examples/client_stateless.c
  13. 7 15
      examples/logger_stdout.c
  14. 8 3
      examples/logger_stdout.h
  15. 47 22
      examples/networklayer_tcp.c
  16. 7 3
      examples/networklayer_tcp.h
  17. 10 8
      examples/networklayer_udp.c
  18. 6 2
      examples/networklayer_udp.h
  19. 21 19
      examples/server.c
  20. 8 11
      examples/server.cpp
  21. 211 90
      examples/server_datasource.c
  22. 7 6
      examples/server_udp.c
  23. 1 0
      include/ua_client.h
  24. 27 22
      include/ua_log.h
  25. 40 8
      include/ua_server.h
  26. 217 220
      include/ua_statuscodes.h
  27. 57 52
      include/ua_types.h
  28. 5 4
      ports/WAGO-750-860.patch
  29. 5 0
      src/client/ua_client.c
  30. 0 11
      src/ongoing/wrappers/Makefile.am
  31. 0 20
      src/ongoing/wrappers/lua/Makefile.am
  32. 0 2
      src/ongoing/wrappers/open62541.h
  33. 0 9
      src/ongoing/wrappers/open62541.i
  34. 0 18
      src/ongoing/wrappers/python/Makefile.am
  35. 10 4
      src/server/ua_nodes.c
  36. 13 7
      src/server/ua_nodes.h
  37. 4 1
      src/server/ua_nodestore.c
  38. 4 7
      src/server/ua_nodestore_concurrent.c
  39. 12 12
      src/server/ua_securechannel_manager.c
  40. 1 2
      src/server/ua_securechannel_manager.h
  41. 459 176
      src/server/ua_server.c
  42. 60 30
      src/server/ua_server_addressspace.c
  43. 208 198
      src/server/ua_server_binary.c
  44. 15 10
      src/server/ua_server_internal.h
  45. 90 24
      src/server/ua_server_worker.c
  46. 10 1
      src/server/ua_services.h
  47. 348 165
      src/server/ua_services_attribute.c
  48. 30 1
      src/server/ua_services_discovery.c
  49. 33 38
      src/server/ua_services_nodemanagement.c
  50. 22 17
      src/server/ua_services_session.c
  51. 296 172
      src/server/ua_services_view.c
  52. 9 7
      src/server/ua_session_manager.c
  53. 2 3
      src/server/ua_session_manager.h
  54. 8 7
      src/ua_config.h.in
  55. 2 6
      src/ua_securechannel.c
  56. 2 2
      src/ua_securechannel.h
  57. 1 5
      src/ua_session.c
  58. 186 129
      src/ua_types.c
  59. 215 252
      src/ua_types_encoding_binary.c
  60. 55 3
      src/ua_util.h
  61. 9 4
      tests/CMakeLists.txt
  62. 75 62
      tests/check_builtin.c
  63. 8 8
      tests/check_memory.c
  64. 2 2
      tools/.coverity.sh
  65. 2 2
      tools/.deployDoxygen.sh
  66. 89 0
      tools/amalgamate.py
  67. 4 0
      tools/certs/create_self-signed.py
  68. 5 1
      tools/certs/localhost.cnf
  69. 98 29
      tools/generate_datatypes.py
  70. 0 5
      tools/generate_nodeids.py

+ 85 - 51
.travis.yml

@@ -3,10 +3,8 @@ compiler:
 - gcc
 env:
   global:
-   #this is the encrypted GITAUTH
-   - secure: "nSunY54Wp5HkQCHHbKwlwpbaKyqRVIu/0EnhaoJSwhM1wqerQV/E5d/2JelO9/tZgbungAO7wk/fjutRMVc7d378RTIPwS8vHpvZfEoGhCFsLoTOlqESzsZFBup2H5t1lpQ23jRHDOxlLdJy2lz5U+zd1YnYgDXqdDFjegsIYdo="
-   # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
-   - secure: "ehswgymGXPM3UINhOOnfSByMnrRNTixeT2vEV+z3kXy3WHew/O1yt9GxaYGrUhJPg4+5chAQgjYmezO1x3/CUKFgeHQUmVTFWEzfy1kL1JVjO+ufYyJDnbY+x3OmyNmMYcef2J5MAuUS2C1KFvIxtLsljVK+gpe4LcylkCIF/3Y="
+  - secure: nSunY54Wp5HkQCHHbKwlwpbaKyqRVIu/0EnhaoJSwhM1wqerQV/E5d/2JelO9/tZgbungAO7wk/fjutRMVc7d378RTIPwS8vHpvZfEoGhCFsLoTOlqESzsZFBup2H5t1lpQ23jRHDOxlLdJy2lz5U+zd1YnYgDXqdDFjegsIYdo=
+  - secure: ehswgymGXPM3UINhOOnfSByMnrRNTixeT2vEV+z3kXy3WHew/O1yt9GxaYGrUhJPg4+5chAQgjYmezO1x3/CUKFgeHQUmVTFWEzfy1kL1JVjO+ufYyJDnbY+x3OmyNmMYcef2J5MAuUS2C1KFvIxtLsljVK+gpe4LcylkCIF/3Y=
 addons:
   coverity_scan:
     project:
@@ -17,51 +15,87 @@ addons:
     build_command: make
     branch_pattern: coverity_scan
 before_install:
-   - sudo apt-get install binutils-mingw-w64-i686 gcc-mingw-w64-i686
-   - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
-   - sudo add-apt-repository ppa:kalakris/cmake -y
-   - sudo apt-get update -qq
-   - sudo apt-get install -qq gcc-4.8
-   - sudo apt-get install -qq --no-install-recommends build-essential cmake python-lxml graphviz doxygen wget
-   - wget http://security.ubuntu.com/ubuntu/pool/main/c/check/check_0.9.10-6ubuntu3_amd64.deb
-   - sudo dpkg -i check_0.9.10-6ubuntu3_amd64.deb
-   - wget https://launchpad.net/ubuntu/+source/liburcu/0.8.5-1ubuntu1/+build/6513813/+files/liburcu2_0.8.5-1ubuntu1_amd64.deb
-   - wget https://launchpad.net/ubuntu/+source/liburcu/0.8.5-1ubuntu1/+build/6513813/+files/liburcu-dev_0.8.5-1ubuntu1_amd64.deb
-   - sudo dpkg -i liburcu2_0.8.5-1ubuntu1_amd64.deb
-   - sudo dpkg -i liburcu-dev_0.8.5-1ubuntu1_amd64.deb
-   - sudo pip install cpp-coveralls
-   - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20
-   - sudo update-alternatives --config gcc
-script: 
-   - echo "Checking the applicability of patches"
-   - ./tools/.checkPorts.sh
-   - echo "Testing builds"
-   - mkdir -p build
-   - cd build
-   - echo "Cross compile build for MinGW"
-   - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DEXAMPLESERVER=ON ..
-   - make
-   - cd .. && rm build -rf && mkdir -p build && cd build
-   - echo "Compile multithreaded version"
-   - cmake -DMULTITHREADING=ON -DEXAMPLESERVER=ON ..
-   - make
-   - cd .. && rm build -rf && mkdir -p build && cd build
-   - echo "Only needed profile"
-   - cmake -DTYPES_ONLY_NEEDED=ON ..
-   - make
-   - cd .. && rm build -rf && mkdir -p build && cd build
-   - echo "Production build"
-   - cmake -DGENERATE_DOCUMENTATION=ON .. 
-   - make
-   - echo "Generate documentation"
-   - make doc
-   - echo "Debug build and unit tests (64 bit)"
-   - make clean
-   - cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_UNIT_TESTS=ON -DENABLE_COVERAGE=ON .. 
-   - make && make test
-   - coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../
-   - cd ..
-
+- sudo apt-get install binutils-mingw-w64-i686 gcc-mingw-w64-i686
+- sudo add-apt-repository ppa:kalakris/cmake -y
+- sudo apt-get update -qq
+- sudo apt-get install -qq --no-install-recommends build-essential cmake python-lxml gcc-multilib graphviz doxygen wget zip
+- wget http://security.ubuntu.com/ubuntu/pool/main/c/check/check_0.9.10-6ubuntu3_amd64.deb
+- sudo dpkg -i check_0.9.10-6ubuntu3_amd64.deb
+- wget https://launchpad.net/ubuntu/+source/liburcu/0.8.5-1ubuntu1/+build/6513813/+files/liburcu2_0.8.5-1ubuntu1_amd64.deb
+- wget https://launchpad.net/ubuntu/+source/liburcu/0.8.5-1ubuntu1/+build/6513813/+files/liburcu-dev_0.8.5-1ubuntu1_amd64.deb
+- sudo dpkg -i liburcu2_0.8.5-1ubuntu1_amd64.deb
+- sudo dpkg -i liburcu-dev_0.8.5-1ubuntu1_amd64.deb
+- sudo pip install cpp-coveralls
+script:
+- echo "Checking the applicability of patches"
+- # ./tools/.checkPorts.sh
+- echo "Testing builds"
+- mkdir -p build
+- cd build
+- echo "Cross compile release build for MinGW"
+- cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
+- make -j
+- cp ../README.md .
+- zip open62541-win32.zip README.md exampleServer_datasource.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
+- cp open62541-win32.zip ..
+- cd .. && rm build -rf && mkdir -p build && cd build
+- echo "Cross compile release build for 32-bit linux"
+- cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-gcc-m32.cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
+- make -j
+- tar -pczf open62541-linux32.tar.gz ../README.md exampleServer_datasource libopen62541.so open62541.h open62541.c
+- cp open62541-linux32.tar.gz ..
+- cd .. && rm build -rf && mkdir -p build && cd build
+- echo "Compile release build for 64-bit linux"
+- cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
+- make -j
+- tar -pczf open62541-linux64.tar.gz ../README.md exampleServer_datasource libopen62541.so open62541.h open62541.c
+- cp open62541-linux64.tar.gz ..
+- cd .. && rm build -rf && mkdir -p build && cd build
+- echo "Upgrade to gcc 4.8"
+- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
+- sudo apt-get update -qq
+- sudo apt-get install -qq gcc-4.8
+- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20
+- sudo update-alternatives --config gcc
+- echo "Compile multithreaded version"
+- cmake -DENABLE_MULTITHREADING=ON -DBUILD_EXAMPLESERVER=ON ..
+- make -j
+- cd .. && rm build -rf && mkdir -p build && cd build
+- echo "Documentation build"
+- cmake -DEXTENSION_STATELESS=ON -DBUILD_DOCUMENTATION=ON ..
+- make -j
+- echo "Generate documentation"
+- make -j doc
+- echo "Debug build and unit tests (64 bit)"
+- make clean
+- cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_UNIT_TESTS=ON -DENABLE_COVERAGE=ON ..
+- make -j && make test
+- coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../
+- cd ..
 after_success:
-   - ./tools/.deployDoxygen.sh
-   - ./tools/.coverity.sh
+- ./tools/.deployDoxygen.sh
+- ./tools/.coverity.sh
+before_deploy:
+- rm build -rf && mkdir -p build && cd build
+- echo "Cross compile release build for Raspberry Pi"
+- cd ~
+- git clone https://github.com/raspberrypi/tools
+- cd -
+- export PATH=$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/
+- cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-rpi64.cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON ..
+- make -j
+- tar -pczf open62541-raspberrypi.tar.gz ../README.md exampleServer_datasource libopen62541.so open62541.h open62541.c
+- cp open62541-raspberrypi.tar.gz ..
+- cd ..
+deploy:
+  provider: releases
+  api_key:
+    secure: PKCoA7MBRtHloIbNF4Qj5LQyCafjekfVeFXlMBd9KmC0ynNuef+D7nn38f/jo25/b0Ii7r+hgslkQPezbKyEqo2zcCB8Pn8TWau2hbzKM/dUCPoN90HVaQcRjUi8P2Y+QkouwyPWSujBL35/X5QiAntRotCSbZx4fkyiN8cU95o=
+  file: 
+    - open62541-win32.zip
+    - open62541-linux32.tar.gz
+    - open62541-linux64.tar.gz
+    - open62541-raspberrypi.tar.gz
+  skip_cleanup: true
+  on:
+    tags: true

+ 170 - 101
CMakeLists.txt

@@ -1,15 +1,18 @@
 cmake_minimum_required(VERSION 2.8.8)
-# set(CMAKE_VERBOSE_MAKEFILE on )
+# set(CMAKE_VERBOSE_MAKEFILE on)
 
 project(open62541 C)
 set(open62541_VERSION_MAJOR 0)
 set(open62541_VERSION_MINOR 0)
 set(open62541_VERSION_PATCH 0)
+add_definitions(-DOPEN62541_VERSION_MAJOR=${open62541_VERSION_MAJOR})
+add_definitions(-DOPEN62541_VERSION_MINOR=${open62541_VERSION_MINOR})
+add_definitions(-DOPEN62541_VERSION_PATCH=${open62541_VERSION_PATCH})
 
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
 
 # Set default build type.
-if (NOT CMAKE_BUILD_TYPE)
+if(NOT CMAKE_BUILD_TYPE)
     message(STATUS "CMAKE_BUILD_TYPE not given; setting to 'RelWithDebInfo'.")
     set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build." FORCE)
 endif()
@@ -18,7 +21,7 @@ endif()
 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
+                -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wconversion -Wshadow 
                 -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -ffunction-sections -fdata-sections)
     if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
         add_definitions(-Wformat-nonliteral)
@@ -32,49 +35,93 @@ add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat
 	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 generated_headers "${PROJECT_BINARY_DIR}/src_generated/*.h")
-set(lib_sources src/ua_types.c
-                src/ua_types_encoding_binary.c
+# build the main library
+set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_statuscodes.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_types.h
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_connection.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_log.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_server.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_client.h)
+set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
+                     ${PROJECT_SOURCE_DIR}/deps/queue.h
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_securechannel.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_session.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
+                     ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.h
+                     ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.h
+                     ${PROJECT_SOURCE_DIR}/src/server/ua_session_manager.h
+                     ${PROJECT_SOURCE_DIR}/src/server/ua_securechannel_manager.h
+                     ${PROJECT_SOURCE_DIR}/src/server/ua_server_internal.h
+                     ${PROJECT_SOURCE_DIR}/src/server/ua_services.h)
+set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
+                ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.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_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} )
+                ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
+                ${PROJECT_SOURCE_DIR}/src/ua_session.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
+				${PROJECT_SOURCE_DIR}/src/server/ua_server_addressspace.c
+				${PROJECT_SOURCE_DIR}/src/server/ua_server_binary.c
+				${PROJECT_SOURCE_DIR}/src/server/ua_nodes.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_server_worker.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_securechannel_manager.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_session_manager.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_discovery.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_securechannel.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_session.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_attribute.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_nodemanagement.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
+                ${PROJECT_SOURCE_DIR}/src/client/ua_client.c)
+                ##TODO: make client stuff optional
+
+## generate code from xml definitions
+file(MAKE_DIRECTORY "${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_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_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)
+
+## logging
+set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")
 
 ## multithreading
-option(MULTITHREADING "Enable multithreading" OFF)
-if(MULTITHREADING)
-    set(UA_MULTITHREADING ON)
+option(ENABLE_MULTITHREADING "Enable multithreading" OFF)
+if(ENABLE_MULTITHREADING)
+    add_definitions(-DUA_MULTITHREADING)
     find_package(Threads REQUIRED)
-    list(APPEND lib_sources src/server/ua_nodestore_concurrent.c)
+    list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_concurrent.c)
 else()
-    list(APPEND lib_sources src/server/ua_nodestore.c)
+    list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.c)
 endif()
 
+## set the precompiler flags
+configure_file("src/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
+
 ## extensions
 option(EXTENSION_UDP "Enable udp extension" OFF)
 if(EXTENSION_UDP)
-	set(EXTENSION_STATELESS ON)
+	add_definitions(-DEXTENSION_STATELESS)
 	message(STATUS "Extensions: enabling udp")
 	add_definitions(-DEXTENSION_UDP)
 endif()
@@ -85,16 +132,42 @@ if(EXTENSION_STATELESS)
 	add_definitions(-DEXTENSION_STATELESS)
 endif()
 
-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
-target_compile_definitions(open62541-objects PUBLIC UA_DYNAMIC_LINKING)
+option(BUILD_DEMO_NODESET "Create a demo node for every built-in datatype" OFF)
+if(BUILD_DEMO_NODESET)
+	message(STATUS "Enabling demo nodeset")
+	add_definitions(-DDEMO_NODESET)
+endif()
+
+if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
+    ## build amalgamated source files
+    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c
+                   PRE_BUILD
+                   COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.h ${exported_headers}
+                   COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
+                                  ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${exported_headers} ${internal_headers}
+                           ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources})
+
+    add_library(open62541-object OBJECT ${PROJECT_BINARY_DIR}/open62541.c)
+    add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
+else()
+    add_definitions(-DNOT_AMALGATED)
+    add_library(open62541-object OBJECT ${lib_sources} ${internal_headers} ${exported_headers})
+    include_directories(${PROJECT_SOURCE_DIR}/include)
+    include_directories(${PROJECT_SOURCE_DIR}/deps)
+    include_directories(${PROJECT_SOURCE_DIR}/src)
+    include_directories(${PROJECT_BINARY_DIR}/src_generated)
+endif()
 
-## logging
-set(UA_LOGLEVEL 400 CACHE STRING "Level at which logs shall be reported")
 
-## coverage
+# build language bindings for the library
+option(ENABLE_BINDING_LUA "Build Lua bindings" OFF)
+option(ENABLE_BINDING_PYTHON "Build Python bindings" OFF)
+if(ENABLE_BINDING_LUA OR ENABLE_BINDING_PYTHON)
+    add_subdirectory(bindings)
+endif()
+
+# coverage
 option(ENABLE_COVERAGE "Enable gcov coverage" OFF)
 if(ENABLE_COVERAGE)
     message(STATUS "Enabling gcov support")
@@ -104,90 +177,86 @@ if(ENABLE_COVERAGE)
     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
 endif()
 
-# set the precompiler flags
-configure_file("src/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
-
-# 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_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_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)
-	message(STATUS "Extensions: enabling 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/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)
-    add_executable(exampleServer examples/server.c examples/networklayer_tcp.c examples/logger_stdout.c ${exported_headers} ${generated_headers})
-    target_link_libraries(exampleServer open62541)
+option(BUILD_EXAMPLESERVER "Build the example server" OFF)
+if(BUILD_EXAMPLESERVER)
+    add_executable(exampleServer examples/server.c $<TARGET_OBJECTS:open62541-object> examples/networklayer_tcp.c examples/logger_stdout.c)
+    add_executable(exampleServer_datasource examples/server_datasource.c $<TARGET_OBJECTS:open62541-object> examples/networklayer_tcp.c examples/logger_stdout.c)
+    target_include_directories(exampleServer PRIVATE ${PROJECT_BINARY_DIR})
+    target_include_directories(exampleServer_datasource PRIVATE ${PROJECT_BINARY_DIR})
     if(WIN32)
         target_link_libraries(exampleServer ws2_32)
+        target_link_libraries(exampleServer_datasource ws2_32)
     else()
         target_link_libraries(exampleServer rt)
+        target_link_libraries(exampleServer_datasource rt)
     endif()
-    if(MULTITHREADING)
+    if(ENABLE_MULTITHREADING)
         target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
+        target_link_libraries(exampleServer_datasource urcu-cds urcu urcu-common pthread)
     endif()
+    if((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
+    	add_custom_command(TARGET exampleServer POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleServer>)
+		add_custom_command(TARGET exampleServer_datasource POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleServer_datasource>)
+	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)
+    add_custom_target(selfsigned ALL DEPENDS ${PROJECT_BINARY_DIR}/localhost.der ${PROJECT_BINARY_DIR}/ca.crt)
+endif()
+
+# build example client
+option(BUILD_EXAMPLECLIENT "Build a test client" OFF)
+if(BUILD_EXAMPLECLIENT)
+	message(STATUS "Extensions: enabling client")
+	add_definitions( -DBENCHMARK=1 )
+	add_executable(exampleClient $<TARGET_OBJECTS:open62541-object> examples/client.c)
+	add_executable(exampleClient_proper $<TARGET_OBJECTS:open62541-object> examples/client_proper.c)
+    target_include_directories(exampleClient PRIVATE ${PROJECT_BINARY_DIR})
+    if(ENABLE_MULTITHREADING)
+        target_link_libraries(exampleClient urcu-cds urcu urcu-common pthread)
+    endif()
+    if(WIN32)
+        target_link_libraries(exampleClient ws2_32)
+        target_link_libraries(exampleClient_proper ws2_32)
+    else()
+        target_link_libraries(exampleClient rt)
+        target_link_libraries(exampleClient_proper rt)
+    endif()
+    if ((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
+    	add_custom_command(TARGET exampleClient POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient>)
+	    add_custom_command(TARGET exampleClient_proper POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:exampleClient>)
+	endif()
+    if(EXTENSION_STATELESS)
+        add_executable(statelessClient ${PROJECT_BINARY_DIR}/open62541.c examples/client_stateless.c)
+        target_include_directories(statelessClient PRIVATE ${PROJECT_BINARY_DIR})
+        if(ENABLE_MULTITHREADING)
+            target_link_libraries(statelessClient urcu-cds urcu urcu-common pthread)
+        endif()
+        if ((CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") AND (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release"))
+    	add_custom_command(TARGET statelessClient POST_BUILD COMMAND ${CMAKE_STRIP} $<TARGET_FILE:statelessClient>)
+		endif()
+    endif()
 endif()
 
 # build unit tests
-option(ENABLE_UNIT_TESTS "Run unit tests after building" OFF)
-if(ENABLE_UNIT_TESTS)
+option(BUILD_UNIT_TESTS "Run unit tests after building" OFF)
+if(BUILD_UNIT_TESTS)
     enable_testing()
     add_subdirectory(tests)
 endif()
 
 # build documentation
-option(GENERATE_DOCUMENTATION "Generate doxygen documentation" OFF)
-if(GENERATE_DOCUMENTATION)
+option(BUILD_DOCUMENTATION "Generate doxygen documentation" OFF)
+if(BUILD_DOCUMENTATION)
     find_package(Doxygen)
         if(NOT DOXYGEN_FOUND)
             message(FATAL_ERROR "Doxygen is not installed or not properly configured")
@@ -197,4 +266,4 @@ if(GENERATE_DOCUMENTATION)
                       ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
                       WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
                       COMMENT "Generating API documentation with Doxygen")
-endif()
+endif()

+ 10 - 13
README.md

@@ -1,9 +1,9 @@
 open62541
 =========
 
-open62541 (http://open62541.org) is an open-source implementation of OPC UA (OPC Unified Architecture). open62541 is a C-based library that contains all the necessary tools to set up a dedicated OPC UA server or to integrate OPC UA-based communication into existing applications. An example server implementation can be found in the /examples directory or further down on this page.
+open62541 (http://open62541.org) is an open source and free implementation of OPC UA (OPC Unified Architecture). open62541 is a C-based library that contains all the necessary tools to set up a dedicated OPC UA server or to integrate OPC UA-based communication into existing applications (linking with C++ projects [is possible](examples/server.cpp)). An example server implementation can be found in the [/examples](examples/) directory or further down on this page.
 
-open62541 is licensed under the LGPL + static linking exception. That means **open62541 can be freely used also in commercial projects**, although changes to the open62541 library itself need to be released under the same license. The server and client implementations in the /examples directory are in the public domain (CC0 license). They can be used under any license and changes don't have to be published.
+open62541 is licensed under the LGPL + static linking exception. That means **open62541 can be freely used also in commercial projects**, although changes to the open62541 library itself need to be released under the same license. The server and client implementations in the [/examples](examples/) directory are in the public domain (CC0 license). They can be used under any license and changes don't have to be published.
 
 [![Ohloh Project Status](https://www.ohloh.net/p/open62541/widgets/project_thin_badge.gif)](https://www.ohloh.net/p/open62541)
 [![Build Status](https://travis-ci.org/acplt/open62541.png?branch=master)](https://travis-ci.org/acplt/open62541)
@@ -20,7 +20,7 @@ For discussion and help, you can use
 - the [bugtracker](https://github.com/acplt/open62541/issues)
 
 ### Contribute to open62541
-As an open source project, we invite new contributors to help improving open6241. If you are a developer, your bugfixes and new features are very welcome. Note that there are ways to contribute even without deep knowledge of the project or the UA standard:
+As an open source project, we invite new contributors to help improving open62541. If you are a developer, your bugfixes and new features are very welcome. Note that there are ways to contribute even without deep knowledge of the project or the UA standard:
 - [Report bugs](https://github.com/acplt/open62541/issues)
 - Improve the [documentation](http://open62541.org/doc)
 - Work on issues marked as "[easy hacks](https://github.com/acplt/open62541/labels/easy%20hack)"
@@ -54,19 +54,16 @@ int main(int argc, char** argv) {
     UA_Server_addNetworkLayer(server, nl);
 
     /* add a variable node */
-    UA_Int32 *myInteger = UA_Int32_new();
-    *myInteger = 42;
     UA_Variant *myIntegerVariant = UA_Variant_new();
-    UA_Variant_setValue(myIntegerVariant, myInteger, UA_TYPES_INT32);
+    UA_Int32 myInteger = 42;
+    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[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));
+    UA_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
+    UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
+                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
 
     /* run the server loop */
     UA_StatusCode retval = UA_Server_run(server, WORKER_THREADS, &running);

+ 39 - 0
bindings/CMakeLists.txt

@@ -0,0 +1,39 @@
+FIND_PACKAGE(SWIG REQUIRED)
+INCLUDE(UseSWIG)
+
+if(ENABLE_BINDING_LUA)
+    FIND_PACKAGE(Lua51)
+    file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/lua)
+    add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/lua/lua_wrap.c 
+                        COMMAND ${SWIG_EXECUTABLE} -lua
+                        -I${PROJECT_SOURCE_DIR}/include
+                        -o ${PROJECT_BINARY_DIR}/lua/lua_wrap.c
+                        ${PROJECT_SOURCE_DIR}/bindings/open62541.i
+                        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/open62541.i)
+    add_library(open62541-lua SHARED ${PROJECT_BINARY_DIR}/lua/lua_wrap.c)
+    set_target_properties(open62541-lua PROPERTIES COMPILE_FLAGS "-Wno-error")
+    target_include_directories(open62541-lua PUBLIC ${LUA_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/include
+                                                    ${PROJECT_BINARY_DIR}/src_generated)
+    target_link_libraries(open62541-lua open62541-static)
+    set_target_properties(open62541-lua PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lua
+                                                   OUTPUT_NAME open62541 PREFIX "")
+endif()
+
+if(ENABLE_BINDING_PYTHON)
+    FIND_PACKAGE(PythonLibs)
+    file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/python)
+    add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/python/python_wrap.c 
+                        COMMAND ${SWIG_EXECUTABLE} -python
+                        -I${PROJECT_SOURCE_DIR}/include
+                        -o ${PROJECT_BINARY_DIR}/python/python_wrap.c
+                        ${PROJECT_SOURCE_DIR}/bindings/open62541.i
+                        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/open62541.i)
+    add_library(open62541-python SHARED ${PROJECT_BINARY_DIR}/python/python_wrap.c)
+    set_target_properties(open62541-python PROPERTIES COMPILE_FLAGS "-Wno-error")
+    target_include_directories(open62541-python PUBLIC ${PYTHON_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/include
+                                                       ${PROJECT_BINARY_DIR}/src_generated)
+    target_link_libraries(open62541-python open62541-static)
+    set_target_properties(open62541-python PROPERTIES
+                                           LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/python
+                                           OUTPUT_NAME _open62541 PREFIX "")
+endif()

+ 45 - 0
bindings/open62541.i

@@ -0,0 +1,45 @@
+%module open62541
+%{
+#include "ua_types.h"
+#include "ua_server.h"
+%}
+
+%define UA_TYPE_HANDLING_FUNCTIONS_SWIG(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);
+%enddef
+
+%define UA_EXPORT
+%enddef
+
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Boolean)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_SByte)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Byte)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Int16)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_UInt16)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Int32)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_UInt32)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Int64)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_UInt64)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Float)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Double)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_String)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_DateTime)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Guid)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_ByteString)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_XmlElement)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_NodeId)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_ExpandedNodeId)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_StatusCode)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_QualifiedName)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_LocalizedText)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_ExtensionObject)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_DataValue)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_Variant)
+UA_TYPE_HANDLING_FUNCTIONS_SWIG(UA_DiagnosticInfo)
+
+%include "ua_types.h"
+%include "ua_server.h"

+ 6 - 0
cmake/Toolchain-gcc-m32.cmake

@@ -0,0 +1,6 @@
+# the name of the target operating system
+set(CMAKE_SYSTEM_NAME Linux)
+
+# which compilers to use for C and C++
+set(CMAKE_C_COMPILER gcc -m32)
+set(CMAKE_CXX_COMPILER g++ -m32)

+ 4 - 0
cmake/Toolchain-mingw32.cmake

@@ -8,6 +8,7 @@ set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-libgcc")
 # environment.
 if(EXISTS /usr/i686-w64-mingw32)
 # First look in standard location as used by Debian/Ubuntu/etc.
+set(CMAKE_STRIP i686-w64-mingw32-strip)
 set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
 set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
 set(CMAKE_RC_COMPILER i686-w64-mingw32-windres)
@@ -15,6 +16,7 @@ set(CMAKE_AR:FILEPATH /usr/bin/i686-w64-mingw32-ar)
 set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
 elseif(EXISTS /usr/i586-mingw32msvc)
 # First look in standard location as used by Debian/Ubuntu/etc.
+set(CMAKE_STRIP i586-mingw32msvc-strip)
 set(CMAKE_C_COMPILER i586-mingw32msvc-gcc)
 set(CMAKE_CXX_COMPILER i586-mingw32msvc-g++)
 set(CMAKE_RC_COMPILER i586-mingw32msvc-windres)
@@ -24,6 +26,7 @@ elseif(EXISTS /opt/mingw)
 # It downloads and builds MinGW and most of the dependencies for you.
 # You can use the toolchain file generated by MXE called `mxe-conf.cmake'
 # or you can use this file by adjusting the above and following paths.
+set(CMAKE_STRIP /opt/mingw/usr/bin/i686-pc-mingw32-strip)
 set(CMAKE_C_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-gcc)
 set(CMAKE_CXX_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-g++)
 set(CMAKE_RC_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-windres)
@@ -31,6 +34,7 @@ set(CMAKE_FIND_ROOT_PATH /opt/mingw/usr/i686-pc-mingw32)
 else()
 # Else fill in local path which the user will likely adjust.
 # This is the location assumed by <http://www.libsdl.org/extras/win32/cross/>
+set(CMAKE_STRIP /usr/local/cross-tools/bin/i386-mingw32-strip)
 set(CMAKE_C_COMPILER /usr/local/cross-tools/bin/i386-mingw32-gcc)
 set(CMAKE_CXX_COMPILER /usr/local/cross-tools/bin/i386-mingw32-g++)
 set(CMAKE_RC_COMPILER /usr/local/cross-tools/bin/i386-mingw32-windres)

+ 12 - 0
cmake/Toolchain-rpi.cmake

@@ -0,0 +1,12 @@
+# -- How to cross compile for Raspberry Pi (on a 32bit host) -- 
+# 1) get the toolchain
+# cd ~
+# git clone https://github.com/raspberrypi/tools
+# 2) export path to one of the compilers
+# export PATH=$PATH:~/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/
+# 3) use this toolchain file 
+# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-rpi.cmake -DEXAMPLESERVER=ON ..
+# make
+set(CMAKE_C_COMPILER arm-bcm2708hardfp-linux-gnueabi-gcc)
+set(CMAKE_CXX_COMPILER arm-bcm2708hardfp-linux-gnueabi-g++)
+set(CMAKE_STRIP arm-bcm2708hardfp-linux-gnueabi-strip)

+ 12 - 0
cmake/Toolchain-rpi64.cmake

@@ -0,0 +1,12 @@
+# -- How to cross compile for Raspberry Pi (on a 64bit host) -- 
+# 1) get the toolchain
+# cd ~
+# git clone https://github.com/raspberrypi/tools
+# 2) export path to one of the compilers
+# export PATH=$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/
+# 3) use this toolchain file 
+# cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-rpi64.cmake -DEXAMPLESERVER=ON ..
+# make
+set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
+set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
+set(CMAKE_STRIP arm-linux-gnueabihf-strip)

+ 9 - 4
examples/client.c

@@ -10,9 +10,14 @@
 #include <arpa/inet.h> //inet_addr
 #include <unistd.h> // for close
 #include <stdlib.h> // pulls in declaration of malloc, free
-#include "ua_transport_generated.h"
-#include "ua_types_encoding_binary.h"
-#include "ua_util.h"
+
+#ifdef NOT_AMALGATED
+    #include "ua_transport_generated.h"
+    #include "ua_types_encoding_binary.h"
+    #include "ua_util.h"
+#else
+    #include "open62541.h"
+#endif
 
 typedef struct ConnectionInfo {
 	UA_Int32 socket;
@@ -580,4 +585,4 @@ int main(int argc, char *argv[]) {
     UA_free(timeDiffs);
 
 	return 0;
-}
+}

+ 11 - 0
examples/client_proper.c

@@ -0,0 +1,11 @@
+#ifdef NOT_AMALGATED
+    #include "ua_types.h"
+    #include "ua_client.h"
+#else
+    #include "open62541.h"
+#endif
+
+int main(int argc, char *argv[]) {
+	UA_Client *client = UA_Client_new();
+	free(client);
+}

+ 1 - 1
examples/client_stateless.c

@@ -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_TYPES_READVALUEID]);
+	req.nodesToRead= UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], 1);
 	req.nodesToReadSize = 1;
 
 	UA_ReadValueId_init(&(req.nodesToRead[0]));

+ 7 - 15
examples/logger_stdout.c

@@ -4,29 +4,21 @@
  */
 
 #include <stdio.h>
-#include <stdarg.h>
-
 #include "logger_stdout.h"
-#include "ua_types.h"
 
 static void print_time(void) {
 	UA_DateTime now = UA_DateTime_now();
 	UA_ByteString str;
 	UA_DateTime_toString(now, &str);
-	printf("\"%.*s\"}", str.length, str.data);
+	printf("%.27s", str.data); //a bit hacky way not to display nanoseconds
 	UA_ByteString_deleteMembers(&str);
 }
 
 #define LOG_FUNCTION(LEVEL) \
-	static void log_##LEVEL(UA_LoggerCategory category, const char *msg, ...) { \
-		va_list args;												   \
-		puts("##LEVEL - ");											   \
-		print_time();												   \
-		puts(" - ");												   \
-		va_start(args, msg);										   \
-		vprintf(msg, args);											   \
-		puts("\n");													   \
-		va_end(args);												   \
+	static void log_##LEVEL(UA_LoggerCategory category, const char *msg) { \
+        printf("[");                                                    \
+		print_time();                                                   \
+        printf("] " #LEVEL "/%s\t%s\n", UA_LoggerCategoryNames[category], msg); \
 	}
 
 LOG_FUNCTION(trace)
@@ -36,8 +28,8 @@ LOG_FUNCTION(warning)
 LOG_FUNCTION(error)
 LOG_FUNCTION(fatal)
 
-void Logger_Stdout_init(UA_Logger *logger) {
-	*logger = (UA_Logger){
+UA_Logger Logger_Stdout_new(void) {
+	return (UA_Logger){
 		.log_trace = log_trace,
 		.log_debug = log_debug,
 		.log_info = log_info,

+ 8 - 3
examples/logger_stdout.h

@@ -6,9 +6,14 @@
 #ifndef LOGGER_STDOUT_H_
 #define LOGGER_STDOUT_H_
 
-#include "ua_log.h"
+#ifdef NOT_AMALGATED
+    #include "ua_types.h"
+    #include "ua_log.h"
+#else
+    #include "open62541.h"
+#endif
 
 /** Initialises the logger for the current thread. */
-void Logger_Stdout_init(UA_Logger *logger);
+UA_Logger Logger_Stdout_new(void);
 
-#endif /* LOGGER_STDOUT_H_ */
+#endif /* LOGGER_STDOUT_H_ */

+ 47 - 22
examples/networklayer_tcp.c

@@ -17,6 +17,7 @@
 #include <netinet/tcp.h>
 #include <sys/socketvar.h>
 #include <sys/ioctl.h>
+#define __USE_BSD
 #include <unistd.h> // read, write, close
 #include <arpa/inet.h>
 #define CLOSESOCKET(S) close(S)
@@ -25,6 +26,7 @@
 #include <stdio.h>
 #include <errno.h> // errno, EINTR
 #include <fcntl.h> // fcntl
+#include <string.h> // memset
 
 #include "networklayer_tcp.h" // UA_MULTITHREADING is defined in here
 
@@ -32,8 +34,12 @@
 #include <urcu/uatomic.h>
 #endif
 
-/* Forwarded as a (UA_Connection) and used for callbacks back into the
-   networklayer */
+
+
+struct ServerNetworklayer_TCP;
+
+/* Forwarded to the server as a (UA_Connection) and used for callbacks back into
+   the networklayer */
 typedef struct {
 	UA_Connection connection;
 	UA_Int32 sockfd;
@@ -56,7 +62,7 @@ typedef struct {
 #endif
 } ConnectionLink;
 
-typedef struct {
+typedef struct ServerNetworkLayerTCP {
 	UA_ConnectionConfig conf;
 	fd_set fdset;
 #ifdef _WIN32
@@ -69,6 +75,7 @@ typedef struct {
     UA_UInt16 conLinksSize;
     ConnectionLink *conLinks;
     UA_UInt32 port;
+    UA_String discoveryUrl;
     /* We remove the connection links only in the main thread. Attach
        to-be-deleted links with atomic operations */
     struct deleteLink {
@@ -78,6 +85,7 @@ typedef struct {
 		UA_Int32 sockfd;
 #endif
         struct deleteLink *next;
+
     } *deleteLinkList;
 } ServerNetworkLayerTCP;
 
@@ -138,10 +146,10 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
 	return UA_STATUSCODE_GOOD;
 }
 
-// Takes the linked list of closed connections and returns the work for the server loop
-static UA_UInt32 batchDeleteLinks(ServerNetworkLayerTCP *layer, UA_WorkItem **returnWork) {
-    UA_WorkItem *work = malloc(sizeof(UA_WorkItem)*layer->conLinksSize);
-	if (!work) {
+/* Removes all connections from the network layer. Returns the work items to close them properly. */
+static UA_UInt32 removeAllConnections(ServerNetworkLayerTCP *layer, UA_WorkItem **returnWork) {
+    UA_WorkItem *work;
+	if (layer->conLinksSize <= 0 || !(work = malloc(sizeof(UA_WorkItem)*layer->conLinksSize))) {
 		*returnWork = NULL;
 		return 0;
 	}
@@ -198,12 +206,12 @@ void closeConnection(TCPConnection *handle) {
 }
 #else
 void closeConnection(TCPConnection *handle) {
+    if(handle->connection.state == UA_CONNECTION_CLOSING)
+        return;
+
 	struct deleteLink *d = malloc(sizeof(struct deleteLink));
 	if(!d)
 		return;
-
-    if(handle->connection.state == UA_CONNECTION_CLOSING)
-        return;
     handle->connection.state = UA_CONNECTION_CLOSING;
 
     UA_Connection_detachSecureChannel(&handle->connection);
@@ -223,6 +231,7 @@ void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf) {
 	UA_UInt32 total_len = 0, nWritten = 0;
 #ifdef _WIN32
 	LPWSABUF buf = _alloca(gather_buf.stringsSize * sizeof(WSABUF));
+	memset(buf, 0, sizeof(gather_buf.stringsSize * sizeof(WSABUF)));
 	int result = 0;
 	for(UA_UInt32 i = 0; i<gather_buf.stringsSize; i++) {
 		buf[i].buf = (char*)gather_buf.strings[i].data;
@@ -241,14 +250,16 @@ void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf) {
 	}
 #else
 	struct iovec iov[gather_buf.stringsSize];
+	memset(iov, 0, sizeof(struct iovec)*gather_buf.stringsSize);
 	for(UA_UInt32 i=0;i<gather_buf.stringsSize;i++) {
-		iov[i] = (struct iovec) {.iov_base = gather_buf.strings[i].data,
-                                 .iov_len = gather_buf.strings[i].length};
+		iov[i].iov_base = gather_buf.strings[i].data;
+		iov[i].iov_len = gather_buf.strings[i].length;
 		total_len += gather_buf.strings[i].length;
 	}
-	struct msghdr message = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = iov,
-							 .msg_iovlen = gather_buf.stringsSize, .msg_control = NULL,
-							 .msg_controllen = 0, .msg_flags = 0};
+	struct msghdr message;
+	memset(&message, 0, sizeof(message));
+	message.msg_iov = iov;
+	message.msg_iovlen = gather_buf.stringsSize;
 	while (nWritten < total_len) {
 		UA_Int32 n = 0;
 		do {
@@ -259,7 +270,7 @@ void writeCallback(TCPConnection *handle, UA_ByteStringArray gather_buf) {
 #endif
 }
 
-static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer) {
+static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger *logger) {
 #ifdef _WIN32
 	WORD wVersionRequested;
 	WSADATA wsaData;
@@ -298,16 +309,16 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer) {
 
 	setNonBlocking(layer->serversockfd);
 	listen(layer->serversockfd, MAXBACKLOG);
-    printf("Listening for TCP connections on %s:%d\n",
-           inet_ntoa(serv_addr.sin_addr),
-           ntohs(serv_addr.sin_port));
+    char msg[256];
+    sprintf(msg, "Listening on %.*s\n", layer->discoveryUrl.length, layer->discoveryUrl.data);
+    UA_LOG_INFO((*logger), UA_LOGGERCATEGORY_SERVER, msg);
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_WorkItem **workItems,
                                         UA_UInt16 timeout) {
     UA_WorkItem *items = (void*)0;
-    UA_Int32 itemsCount = batchDeleteLinks(layer, &items);
+    UA_Int32 itemsCount = removeAllConnections(layer, &items);
     setFDSet(layer);
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
@@ -343,8 +354,13 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
 			if(!buf.data)
 				break;
 		}
+        
+#ifdef _WIN32
         buf.length = recv(layer->conLinks[i].sockfd, (char *)buf.data,
                           layer->conf.recvBufferSize, 0);
+#else
+        buf.length = read(layer->conLinks[i].sockfd, buf.data, layer->conf.recvBufferSize);
+#endif
         if (buf.length <= 0) {
             closeConnection(layer->conLinks[i].connection); // work is returned in the next iteration
         } else {
@@ -373,10 +389,14 @@ static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP * layer, UA_Wor
 #ifdef _WIN32
 	WSACleanup();
 #endif
-    return batchDeleteLinks(layer, workItems);
+    return removeAllConnections(layer, workItems);
 }
 
 static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
+	UA_String_deleteMembers(&layer->discoveryUrl);
+	for(UA_Int32 i=0;i<layer->conLinksSize;++i){
+		free(layer->conLinks[i].connection);
+	}
 	free(layer->conLinks);
 	free(layer);
 }
@@ -388,13 +408,18 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UIn
 	tcplayer->conLinks = NULL;
     tcplayer->port = port;
     tcplayer->deleteLinkList = (void*)0;
+    char hostname[256];
+    gethostname(hostname, 255);
+    UA_String_copyprintf("opc.tcp://%s:%d", &tcplayer->discoveryUrl, hostname, port);
 
     UA_ServerNetworkLayer nl;
     nl.nlHandle = tcplayer;
-    nl.start = (UA_StatusCode (*)(void*))ServerNetworkLayerTCP_start;
+    nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))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.discoveryUrl = &tcplayer->discoveryUrl;
+
     return nl;
 }
 

+ 7 - 3
examples/networklayer_tcp.h

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

+ 10 - 8
examples/networklayer_udp.c

@@ -117,7 +117,7 @@ void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
 	}
 
 
-	struct sockaddr_in *sin = UA_NULL;
+	struct sockaddr_in *sin = NULL;
 	if (handle->from.sa_family == AF_INET) {
         
 #if defined(__GNUC__) || defined(__clang__)
@@ -150,7 +150,7 @@ void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_buf) {
 #endif
 }
 
-static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer) {
+static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer, UA_Logger *logger) {
 #ifdef _WIN32
 	WORD wVersionRequested;
 	WSADATA wsaData;
@@ -188,16 +188,17 @@ static UA_StatusCode ServerNetworkLayerUDP_start(ServerNetworkLayerUDP *layer) {
 	}
 
 	setNonBlocking(layer->serversockfd);
-
-    printf("Listening for UDP connections on %s:%d\n",
-           inet_ntoa(serv_addr.sin_addr),
-           ntohs(serv_addr.sin_port));
+    char msg[256];
+    sprintf(msg, "Listening for UDP connections on %s:%d",
+            inet_ntoa(serv_addr.sin_addr),
+            ntohs(serv_addr.sin_port));
+    UA_LOG_INFO((*logger), UA_LOGGERCATEGORY_SERVER, msg);
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_WorkItem **workItems,
                                         UA_UInt16 timeout) {
-    UA_WorkItem *items = UA_NULL;
+    UA_WorkItem *items = NULL;
     setFDSet(layer);
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize = select(layer->serversockfd+1, &layer->fdset, NULL, NULL, &tmptv);
@@ -243,7 +244,7 @@ static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_W
             c->fromlen = sendsize;
             c->connection.state = UA_CONNECTION_OPENING;
             c->connection.localConf = layer->conf;
-            c->connection.channel = UA_NULL;
+            c->connection.channel = NULL;
             c->connection.close = (void (*)(void*))closeConnectionUDP;
             c->connection.write = (void (*)(void*, UA_ByteStringArray))writeCallbackUDP;
 
@@ -287,5 +288,6 @@ UA_ServerNetworkLayer ServerNetworkLayerUDP_new(UA_ConnectionConfig conf, UA_UIn
     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;
+    nl.discoveryUrl = NULL;
     return nl;
 }

+ 6 - 2
examples/networklayer_udp.h

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

+ 21 - 19
examples/server.c

@@ -3,21 +3,24 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
 #include <time.h>
-#include "ua_types.h"
-
 #include <stdio.h>
 #include <stdlib.h> 
 #include <signal.h>
 #include <errno.h> // errno, EINTR
 
-// provided by the open62541 lib
-#include "ua_server.h"
+#ifdef NOT_AMALGATED
+    #include "ua_types.h"
+    #include "ua_server.h"
+#else
+    #include "open62541.h"
+#endif
 
 // provided by the user, implementations available in the /examples folder
 #include "logger_stdout.h"
 #include "networklayer_tcp.h"
 
 UA_Boolean running = 1;
+UA_Logger logger;
 
 static void stopHandler(int sign) {
     printf("Received Ctrl-C\n");
@@ -25,7 +28,6 @@ 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
@@ -51,13 +53,15 @@ static UA_ByteString loadCertificate(void) {
 }
 
 static void testCallback(UA_Server *server, void *data) {
-       printf("testcallback\n");
+    logger.log_info(UA_LOGGERCATEGORY_USERLAND, "testcallback");
 }
 
 int main(int argc, char** argv) {
 	signal(SIGINT, stopHandler); /* catches ctrl-c */
 
 	UA_Server *server = UA_Server_new();
+    logger = Logger_Stdout_new();
+    UA_Server_setLogger(server, logger);
     UA_Server_setServerCertificate(server, loadCertificate());
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 
@@ -65,18 +69,16 @@ int main(int argc, char** argv) {
     UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL); // call every 2 sec
 
 	// 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_Int32 myInteger = 42;
+    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[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));
-
-    // add node with a callback to the userspace
-    
+    UA_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
+    UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
+                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
     
 #ifdef BENCHMARK
     UA_UInt32 nodeCount = 500;
@@ -85,13 +87,13 @@ int main(int argc, char** argv) {
         UA_Int32 *data = UA_Int32_new();
         *data = 42;
         UA_Variant *variant = UA_Variant_new();
-        UA_Variant_setValue(variant, data, UA_TYPES_INT32);
+        UA_Variant_setScalar(variant, data, &UA_TYPES[UA_TYPES_INT32]);
         UA_QualifiedName *nodeName = UA_QualifiedName_new();
         sprintf(str,"%d",i);
         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));
+        UA_Server_addVariableNode(server, variant, *nodeName, UA_NODEID_NULL,
+                                  UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
     }
 #endif
 

+ 8 - 11
examples/server.cpp

@@ -28,20 +28,17 @@ 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;
+	// add a variable node to the adresspace
     UA_Variant *myIntegerVariant = UA_Variant_new();
-    UA_Variant_setValue(myIntegerVariant, myInteger, UA_TYPES_INT32);
+    UA_Int32 myInteger = 42;
+    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_QualifiedName myIntegerName;
     UA_QUALIFIEDNAME_ASSIGN(myIntegerName, "the answer");
-    UA_NodeId 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_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
+    UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
+                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
 
     UA_Boolean running = UA_TRUE;
     UA_StatusCode retval = UA_Server_run(server, 1, &running);

+ 211 - 90
examples/server_datasource.c

@@ -2,135 +2,256 @@
  * 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"
+#ifdef NOT_AMALGATED
+    #include "ua_types.h"
+    #include "ua_server.h"
+#else
+    #include "open62541.h"
+#endif
 
+#include <time.h>
 #include <stdio.h>
 #include <stdlib.h> 
 #include <signal.h>
 #define __USE_XOPEN2K
+#ifdef UA_MULTITHREADING
 #include <pthread.h>
-
-// provided by the open62541 lib
-#include "ua_server.h"
+#endif
 
 // provided by the user, implementations available in the /examples folder
 #include "logger_stdout.h"
 #include "networklayer_tcp.h"
 
+/****************************/
+/* Server-related variables */
+/****************************/
+
+UA_Boolean running = 1;
+UA_Logger logger;
+
 /*************************/
 /* 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 UA_StatusCode readTimeData(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+	UA_DateTime *currentTime = UA_DateTime_new();
+	if(!currentTime)
+		return UA_STATUSCODE_BADOUTOFMEMORY;
+	*currentTime = UA_DateTime_now();
+	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
+	value->value.arrayLength = -1;
+	value->value.dataPtr = currentTime;
+	value->value.arrayDimensionsSize = -1;
+	value->value.arrayDimensions = NULL;
+	value->hasVariant = UA_TRUE;
+	if(sourceTimeStamp) {
+		value->hasSourceTimestamp = UA_TRUE;
+		value->sourceTimestamp = *currentTime;
+	}
+	return UA_STATUSCODE_GOOD;
 }
 
-static void releaseTimeData(const void *handle, UA_VariantData *data) {
-    UA_DateTime_delete((UA_DateTime*)data->dataPtr);
+static void releaseTimeData(const void *handle, UA_DataValue *value) {
+	UA_DateTime_delete((UA_DateTime*)value->value.dataPtr);
 }
 
-static UA_StatusCode writeTimeData(const void *handle, const UA_VariantData *data) {
-    return UA_STATUSCODE_BADINTERNALERROR;
-}
+/*****************************/
+/* Read-only CPU temperature */
+/*      Only on Linux        */
+/*****************************/
+FILE* temperatureFile = NULL;
+static UA_StatusCode readTemperature(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+	UA_Double* currentTemperature = UA_Double_new();
+
+	if(!currentTemperature)
+		return UA_STATUSCODE_BADOUTOFMEMORY;
 
-/**************************/
-/* Read/write data source */
-/**************************/
-UA_Int32 deviceStatus = 0;
-pthread_rwlock_t deviceStatusLock;
+	fseek(temperatureFile, 0, SEEK_SET);
 
-static void printDeviceStatus(UA_Server *server, void *data) {
-    printf("Device Status: %i\n", deviceStatus);
+	if(fscanf(temperatureFile, "%lf", currentTemperature) != 1){
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "Can not parse temperature");
+		exit(1);
+	}
+
+	*currentTemperature /= 1000.0;
+
+	value->value.type = &UA_TYPES[UA_TYPES_DOUBLE];
+	value->value.arrayLength = -1;
+	value->value.dataPtr = currentTemperature;
+	value->value.arrayDimensionsSize = -1;
+	value->value.arrayDimensions = NULL;
+	value->hasVariant = UA_TRUE;
+	return UA_STATUSCODE_GOOD;
+}
+
+static void releaseTemperature(const void *handle, UA_DataValue *value) {
+	UA_Double_delete((UA_Double*)value->value.dataPtr);
 }
 
-static UA_StatusCode readDeviceStatus(const void *handle, UA_VariantData *data) {
-    /* In order to reduce blocking time, we could alloc memory for every read
+/*************************/
+/* Read-write status led */
+/*************************/
+#ifdef UA_MULTITHREADING
+pthread_rwlock_t writeLock;
+#endif
+FILE* triggerFile = NULL;
+FILE* ledFile = NULL;
+UA_Boolean ledStatus = 0;
+
+static UA_StatusCode readLedStatus(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+	/* 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;
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_rdlock(&writeLock);
+#endif
+	value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
+	value->value.arrayLength = -1;
+	value->value.dataPtr = &ledStatus;
+	value->value.arrayDimensionsSize = -1;
+	value->value.arrayDimensions = NULL;
+	value->hasVariant = UA_TRUE;
+	if(sourceTimeStamp) {
+		value->sourceTimestamp = UA_DateTime_now();
+		value->hasSourceTimestamp = UA_TRUE;
+	}
+	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
+static void releaseLedStatus(const void *handle, UA_DataValue *value) {
+	/* 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);
+	value->value.arrayLength = -1;
+	value->value.dataPtr = NULL;
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_unlock(&writeLock);
+#endif
 }
 
-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;
+static UA_StatusCode writeLedStatus(const void *handle, const UA_Variant *data) {
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_wrlock(&writeLock);
+#endif
+	if(data->dataPtr)
+		ledStatus = *(UA_Boolean*)data->dataPtr;
+
+	if(triggerFile)
+		fseek(triggerFile, 0, SEEK_SET);
+
+	if(ledFile){
+		if(ledStatus == 1){
+			fprintf(ledFile, "%s", "1");
+		} else {
+			fprintf(ledFile, "%s", "0");
+		}
+		fflush(ledFile);
+	}
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_unlock(&writeLock);
+#endif
+	return UA_STATUSCODE_GOOD;
 }
 
-UA_Boolean running = 1;
+static void printLedStatus(UA_Server *server, void *data) {
+	UA_LOG_INFO(logger, UA_LOGGERCATEGORY_SERVER, ledStatus ? "LED is on" : "LED is off");
+}
 
 static void stopHandler(int sign) {
-    printf("Received Ctrl-C\n");
+	printf("Received Ctrl-C\n");
 	running = 0;
 }
 
 int main(int argc, char** argv) {
 	signal(SIGINT, stopHandler); /* catches ctrl-c */
-    pthread_rwlock_init(&deviceStatusLock, 0);
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_init(&writeLock, 0);
+#endif
 
 	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);
+	logger = Logger_Stdout_new();
+	UA_Server_setLogger(server, logger);
+	UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+
+	// print the status every 2 sec
+	UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
+			.work.methodCall = {.method = printLedStatus, .data = NULL} };
+	UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL);
+
+	// add node with the datetime data source
+	UA_DataSource dateDataSource = (UA_DataSource)
+        {.handle = NULL,
+		.read = readTimeData,
+		.release = releaseTimeData,
+		.write = NULL};
+	UA_QualifiedName dateName;
+	UA_QUALIFIEDNAME_ASSIGN(dateName, "current time");
+	UA_Server_addDataSourceVariableNode(server, dateDataSource, dateName, UA_NODEID_NULL,
+                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+	if(!(temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))){
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Linux specific] Can not open temperature file, no temperature node will be added");
+	} else {
+		// add node with the datetime data source
+		UA_DataSource temperatureDataSource = (UA_DataSource)
+    	    {.handle = NULL,
+			.read = readTemperature,
+			.release = releaseTemperature,
+			.write = NULL};
+		UA_QualifiedName ledName;
+		UA_QUALIFIEDNAME_ASSIGN(ledName, "cpu temperature");
+		UA_Server_addDataSourceVariableNode(server, temperatureDataSource, ledName, UA_NODEID_NULL, 
+                                            UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                            UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+	}
+
+	if (	!(triggerFile = fopen("/sys/class/leds/led0/trigger", "w"))
+		|| 	!(ledFile = fopen("/sys/class/leds/led0/brightness", "w"))) {
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Raspberry Pi specific] Can not open trigger or LED file (try to run server with sudo if on a Raspberry PI)");
+		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "An LED node will be added but no physical LED will be operated");
+	} else {
+		//setting led mode to manual
+		fprintf(triggerFile, "%s", "none");
+		fflush(triggerFile);
+
+		//turning off led initially
+		fprintf(ledFile, "%s", "1");
+		fflush(ledFile);
+	}
+
+	// add node with the LED status data source
+	UA_DataSource ledStatusDataSource = (UA_DataSource)
+   		{.handle = NULL,
+		.read = readLedStatus,
+		.release = releaseLedStatus,
+		.write = writeLedStatus};
+	UA_QualifiedName statusName;
+	UA_QUALIFIEDNAME_ASSIGN(statusName, "status LED");
+	UA_Server_addDataSourceVariableNode(server, ledStatusDataSource, statusName, UA_NODEID_NULL,
+                                        UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+	//start server
+	UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
+
+	//ctrl-c received -> clean up
 	UA_Server_delete(server);
-    pthread_rwlock_destroy(&deviceStatusLock);
+
+	if(temperatureFile)
+		fclose(temperatureFile);
+
+	if(triggerFile){
+		fseek(triggerFile, 0, SEEK_SET);
+		//setting led mode to default
+		fprintf(triggerFile, "%s", "mmc0");
+		fclose(triggerFile);
+	}
+
+	if(ledFile){
+		fclose(ledFile);
+	}
+
+#ifdef UA_MULTITHREADING
+	pthread_rwlock_destroy(&writeLock);
+#endif
 
 	return retval;
-}
+}

+ 7 - 6
examples/server_udp.c

@@ -30,15 +30,16 @@ int main(int argc, char** argv) {
     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_Int32 myInteger = 42;
+    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[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_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
+    UA_NodeId parentNodeId = UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
+                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
 	UA_Server_delete(server);

+ 1 - 0
include/ua_client.h

@@ -19,6 +19,7 @@ struct UA_Client;
 typedef struct UA_Client UA_Client;
 
 UA_Client UA_EXPORT * UA_Client_new(void);
+void UA_Client_delete(UA_Client* client);
 
 UA_StatusCode UA_EXPORT UA_Client_connect(UA_Client *c, UA_ConnectionConfig conf,
                                           UA_ClientNetworkLayer networkLayer, char *endpointUrl);

+ 27 - 22
include/ua_log.h

@@ -28,60 +28,65 @@ extern "C" {
  * @defgroup logging Logging
  *
  * @brief Custom logging solutions can be "plugged in" with this interface
+ *
+ * @{
  */
 
 typedef enum UA_LoggerCategory {
-    UA_LOGGINGCATEGORY_CONNECTION,
-    UA_LOGGINGCATEGORY_SESSION,
-    UA_LOGGINGCATEGORY_SUBSCRIPTION,
-    UA_LOGGINGCATEGORY_SERVER
+    UA_LOGGERCATEGORY_COMMUNICATION,
+    UA_LOGGERCATEGORY_SERVER,
+    UA_LOGGERCATEGORY_USERLAND
 } UA_LoggerCategory;
 
+extern UA_EXPORT const char *UA_LoggerCategoryNames[3];
+
 typedef struct UA_Logger {
-    void (*log_trace)(UA_LoggerCategory category, const char *msg, ...);
-    void (*log_debug)(UA_LoggerCategory category, const char *msg, ...);
-    void (*log_info)(UA_LoggerCategory category, const char *msg, ...);
-    void (*log_warning)(UA_LoggerCategory category, const char *msg, ...);
-    void (*log_error)(UA_LoggerCategory category, const char *msg, ...);
-    void (*log_fatal)(UA_LoggerCategory category, const char *msg, ...);
+    void (*log_trace)(UA_LoggerCategory category, const char *msg);
+    void (*log_debug)(UA_LoggerCategory category, const char *msg);
+    void (*log_info)(UA_LoggerCategory category, const char *msg);
+    void (*log_warning)(UA_LoggerCategory category, const char *msg);
+    void (*log_error)(UA_LoggerCategory category, const char *msg);
+    void (*log_fatal)(UA_LoggerCategory category, const char *msg);
 } UA_Logger;
 
 #if UA_LOGLEVEL <= 100
-#define UA_LOG_TRACE(CATEGORY, MSG, ...) do { logger.log_trace(CATEGORY, MSG, __VA_ARGS__); } while(0)
+#define UA_LOG_TRACE(LOGGER, CATEGORY, MSG) do { if(LOGGER.log_trace) LOGGER.log_trace(CATEGORY, MSG); } while(0)
 #else
-#define UA_LOG_TRACE(CATEGORY, MSG, ...) do {} while(0)
+#define UA_LOG_TRACE(LOGGER, CATEGORY, MSG) do {} while(0)
 #endif
 
 #if UA_LOGLEVEL <= 200
-#define UA_LOG_DEBUG(CATEGORY, MSG, ...) do { logger.log_debug(CATEGORY, MSG, __VA_ARGS__); } while(0)
+#define UA_LOG_DEBUG(LOGGER, CATEGORY, MSG) do { if(LOGGER.log_debug) LOGGER.log_debug(CATEGORY, MSG); } while(0)
 #else
-#define UA_LOG_DEBUG(CATEGORY, MSG, ...) do {} while(0)
+#define UA_LOG_DEBUG(LOGGER, CATEGORY, MSG) do {} while(0)
 #endif
 
 #if UA_LOGLEVEL <= 300
-#define UA_LOG_INFO(CATEGORY, MSG, ...) do { logger.log_info(CATEGORY, MSG, __VA_ARGS__); } while(0)
+#define UA_LOG_INFO(LOGGER, CATEGORY, MSG) do { if(LOGGER.log_info) LOGGER.log_info(CATEGORY, MSG); } while(0)
 #else
-#define UA_LOG_INFO(CATEGORY, MSG, ...) do {} while(0)
+#define UA_LOG_INFO(LOGGER, CATEGORY, MSG) do {} while(0)
 #endif
 
 #if UA_LOGLEVEL <= 400
-#define UA_LOG_WARNING(CATEGORY, MSG, ...) do { logger.log_warning(CATEGORY, MSG, __VA_ARGS__); } while(0)
+#define UA_LOG_WARNING(LOGGER, CATEGORY, MSG) do { if(LOGGER.log_warning) LOGGER.log_warning(CATEGORY, MSG); } while(0)
 #else
-#define UA_LOG_WARNING(CATEGORY, MSG, ...) do {} while(0)
+#define UA_LOG_WARNING(LOGGER, CATEGORY, MSG) do {} while(0)
 #endif
 
 #if UA_LOGLEVEL <= 500
-#define UA_LOG_ERROR(CATEGORY, MSG, ...) do { logger.log_error(CATEGORY, MSG, __VA_ARGS__); } while(0)
+#define UA_LOG_ERROR(LOGGER, CATEGORY, MSG) do { if(LOGGER.log_error) LOGGER.log_error(CATEGORY, MSG); } while(0)
 #else
-#define UA_LOG_ERROR(CATEGORY, MSG, ...) do {} while(0)
+#define UA_LOG_ERROR(LOGGER, CATEGORY, MSG) do {} while(0)
 #endif
 
 #if UA_LOGLEVEL <= 600
-#define UA_LOG_FATAL(CATEGORY, MSG, ...) do { logger.log_fatal(CATEGORY, MSG, __VA_ARGS__); } while(0)
+#define UA_LOG_FATAL(LOGGER, CATEGORY, MSG) do { if(LOGGER.log_fatal) LOGGER.log_fatal(CATEGORY, MSG); } while(0)
 #else
-#define UA_LOG_FATAL(CATEGORY, MSG, ...) do {} while(0)
+#define UA_LOG_FATAL(LOGGER, CATEGORY, MSG) do {} while(0)
 #endif
 
+/** @} */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 40 - 8
include/ua_server.h

@@ -39,6 +39,9 @@ UA_Server UA_EXPORT * UA_Server_new(void);
 void UA_EXPORT UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate);
 void UA_EXPORT UA_Server_delete(UA_Server *server);
 
+/** Sets the logger used by the server */
+void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
+
 /**
  * Runs the main loop of the server. In each iteration, this calls into the
  * networklayers to see if work have arrived and checks if timed events need to
@@ -55,12 +58,35 @@ 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);
 
+/** @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. 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.
+ *
+ * It is expected that the read and release callbacks are implemented. The write
+ * callback can be set to null.
+ **/
+typedef struct {
+    const void *handle;
+    UA_StatusCode (*read)(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value);
+    void (*release)(const void *handle, UA_DataValue *value);
+    UA_StatusCode (*write)(const void *handle, const UA_Variant *data);
+} UA_DataSource;
+
 /** Add a reference to the server's address space */
 UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item);
 
-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);
+UA_StatusCode UA_EXPORT
+UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_QualifiedName browseName, 
+                          UA_NodeId nodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId);
+
+UA_StatusCode UA_EXPORT
+UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
+                                    const UA_QualifiedName browseName, UA_NodeId nodeId,
+                                    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId);
 
 /** Work that is run in the main loop (singlethreaded) or dispatched to a worker
     thread. */
@@ -122,7 +148,7 @@ UA_StatusCode UA_EXPORT UA_Server_addRepeatedWorkItem(UA_Server *server, const U
                                                       UA_UInt32 interval, UA_Guid *resultWorkGuid);
 
 /** Remove timed or repeated work */
-UA_Boolean UA_EXPORT UA_Server_removeWorkItem(UA_Server *server, UA_Guid workId);
+/* UA_Boolean UA_EXPORT UA_Server_removeWorkItem(UA_Server *server, UA_Guid workId); */
 
 /**
  * Interface to the binary network layers. This structure is returned from the
@@ -139,7 +165,7 @@ typedef struct {
      *
      * @return Returns UA_STATUSCODE_GOOD or an error code.
      */
-    UA_StatusCode (*start)(void *nlHandle);
+    UA_StatusCode (*start)(void *nlHandle, UA_Logger *logger);
     
     /**
      * Gets called from the main server loop and returns the work that
@@ -166,8 +192,14 @@ typedef struct {
      */
     UA_Int32 (*stop)(void *nlhandle, UA_WorkItem **workItems);
 
-    /** Deletes the network layer. Call only after a successfull shutdown. */
+    /** Deletes the network layer. Call only after a successful shutdown. */
     void (*free)(void *nlhandle);
+
+    /**
+     * String containing the discovery URL that will be add to the server's list
+     * contains the protocol the host and the port of the layer
+     */
+    UA_String* discoveryUrl;
 } UA_ServerNetworkLayer;
 
 /**
@@ -244,8 +276,8 @@ typedef struct UA_ExternalNodeStore {
 	UA_ExternalNodeStore_delete destroy;
 } UA_ExternalNodeStore;
 
-UA_StatusCode UA_EXPORT
-UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, const UA_String *url, UA_ExternalNodeStore *nodeStore);
+/* UA_StatusCode UA_EXPORT */
+/* UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, const UA_String *url, UA_ExternalNodeStore *nodeStore); */
 
 /** @} */
 

+ 217 - 220
include/ua_statuscodes.h

@@ -1,227 +1,224 @@
-/* This file shall only be included in ua_types.h */
-#ifdef UA_TYPES_H_
 #ifndef OPCUA_STATUSCODES_H_
 #define OPCUA_STATUSCODES_H_
 
 enum UA_StatusCode {
-	UA_STATUSCODE_GOOD = (UA_Int32) 0x00,
-	UA_STATUSCODE_BADUNEXPECTEDERROR = (UA_Int32) 0x80010000, // An unexpected error occurred.
-	UA_STATUSCODE_BADINTERNALERROR = (UA_Int32) 0x80020000, // An internal error occurred as a result of a programming or configuration error.
-	UA_STATUSCODE_BADOUTOFMEMORY = (UA_Int32) 0x80030000, // Not enough memory to complete the operation.
-	UA_STATUSCODE_BADRESOURCEUNAVAILABLE = (UA_Int32) 0x80040000, // An operating system resource is not available.
-	UA_STATUSCODE_BADCOMMUNICATIONERROR = (UA_Int32) 0x80050000, // A low level communication error occurred.
-	UA_STATUSCODE_BADENCODINGERROR = (UA_Int32) 0x80060000, // Encoding halted because of invalid data in the objects being serialized.
-	UA_STATUSCODE_BADDECODINGERROR = (UA_Int32) 0x80070000, // Decoding halted because of invalid data in the stream.
-	UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED = (UA_Int32) 0x80080000, // The message encoding/decoding limits imposed by the stack have been exceeded.
-	UA_STATUSCODE_BADREQUESTTOOLARGE = (UA_Int32) 0x80b80000, // The request message size exceeds limits set by the server.
-	UA_STATUSCODE_BADRESPONSETOOLARGE = (UA_Int32) 0x80b90000, // The response message size exceeds limits set by the client.
-	UA_STATUSCODE_BADUNKNOWNRESPONSE = (UA_Int32) 0x80090000, // An unrecognized response was received from the server.
-	UA_STATUSCODE_BADTIMEOUT = (UA_Int32) 0x800a0000, // The operation timed out.
-	UA_STATUSCODE_BADSERVICEUNSUPPORTED = (UA_Int32) 0x800b0000, // The server does not support the requested service.
-	UA_STATUSCODE_BADSHUTDOWN = (UA_Int32) 0x800c0000, // The operation was cancelled because the application is shutting down.
-	UA_STATUSCODE_BADSERVERNOTCONNECTED = (UA_Int32) 0x800d0000, // The operation could not complete because the client is not connected to the server.
-	UA_STATUSCODE_BADSERVERHALTED = (UA_Int32) 0x800e0000, // The server has stopped and cannot process any requests.
-	UA_STATUSCODE_BADNOTHINGTODO = (UA_Int32) 0x800f0000, // There was nothing to do because the client passed a list of operations with no elements.
-	UA_STATUSCODE_BADTOOMANYOPERATIONS = (UA_Int32) 0x80100000, // The request could not be processed because it specified too many operations.
-	UA_STATUSCODE_BADTOOMANYMONITOREDITEMS = (UA_Int32) 0x80db0000, // The request could not be processed because there are too many monitored items in the subscription.
-	UA_STATUSCODE_BADDATATYPEIDUNKNOWN = (UA_Int32) 0x80110000, // The extension object cannot be (de)serialized because the data type id is not recognized.
-	UA_STATUSCODE_BADCERTIFICATEINVALID = (UA_Int32) 0x80120000, // The certificate provided as a parameter is not valid.
-	UA_STATUSCODE_BADSECURITYCHECKSFAILED = (UA_Int32) 0x80130000, // An error occurred verifying security.
-	UA_STATUSCODE_BADCERTIFICATETIMEINVALID = (UA_Int32) 0x80140000, // The Certificate has expired or is not yet valid.
-	UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID = (UA_Int32) 0x80150000, // An Issuer Certificate has expired or is not yet valid.
-	UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID = (UA_Int32) 0x80160000, // The HostName used to connect to a Server does not match a HostName in the Certificate.
-	UA_STATUSCODE_BADCERTIFICATEURIINVALID = (UA_Int32) 0x80170000, // The URI specified in the ApplicationDescription does not match the URI in the Certificate.
-	UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED = (UA_Int32) 0x80180000, // The Certificate may not be used for the requested operation.
-	UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED = (UA_Int32) 0x80190000, // The Issuer Certificate may not be used for the requested operation.
-	UA_STATUSCODE_BADCERTIFICATEUNTRUSTED = (UA_Int32) 0x801a0000, // The Certificate is not trusted.
-	UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN = (UA_Int32) 0x801b0000, // It was not possible to determine if the Certificate has been revoked.
-	UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN = (UA_Int32) 0x801c0000, // It was not possible to determine if the Issuer Certificate has been revoked.
-	UA_STATUSCODE_BADCERTIFICATEREVOKED = (UA_Int32) 0x801d0000, // The Certificate has been revoked.
-	UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED = (UA_Int32) 0x801e0000, // The Issuer Certificate has been revoked.
-	UA_STATUSCODE_BADUSERACCESSDENIED = (UA_Int32) 0x801f0000, // User does not have permission to perform the requested operation.
-	UA_STATUSCODE_BADIDENTITYTOKENINVALID = (UA_Int32) 0x80200000, // The user identity token is not valid.
-	UA_STATUSCODE_BADIDENTITYTOKENREJECTED = (UA_Int32) 0x80210000, // The user identity token is valid but the server has rejected it.
-	UA_STATUSCODE_BADSECURECHANNELIDINVALID = (UA_Int32) 0x80220000, // The specified secure channel is no longer valid.
-	UA_STATUSCODE_BADINVALIDTIMESTAMP = (UA_Int32) 0x80230000, // The timestamp is outside the range allowed by the server.
-	UA_STATUSCODE_BADNONCEINVALID = (UA_Int32) 0x80240000, // The nonce does appear to be not a random value or it is not the correct length.
-	UA_STATUSCODE_BADSESSIONIDINVALID = (UA_Int32) 0x80250000, // The session id is not valid.
-	UA_STATUSCODE_BADSESSIONCLOSED = (UA_Int32) 0x80260000, // The session was closed by the client.
-	UA_STATUSCODE_BADSESSIONNOTACTIVATED = (UA_Int32) 0x80270000, // The session cannot be used because ActivateSession has not been called.
-	UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID = (UA_Int32) 0x80280000, // The subscription id is not valid.
-	UA_STATUSCODE_BADREQUESTHEADERINVALID = (UA_Int32) 0x802a0000, // The header for the request is missing or invalid.
-	UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID = (UA_Int32) 0x802b0000, // The timestamps to return parameter is invalid.
-	UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT = (UA_Int32) 0x802c0000, // The request was cancelled by the client.
-	UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED = (UA_Int32) 0x002d0000, // The subscription was transferred to another session.
-	UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY = (UA_Int32) 0x002e0000, // The processing will complete asynchronously.
-	UA_STATUSCODE_GOODOVERLOAD = (UA_Int32) 0x002f0000, // Sampling has slowed down due to resource limitations.
-	UA_STATUSCODE_GOODCLAMPED = (UA_Int32) 0x00300000, // The value written was accepted but was clamped.
-	UA_STATUSCODE_BADNOCOMMUNICATION = (UA_Int32) 0x80310000, // Communication with the data source is defined, but not established, and there is no last known value available.
-	UA_STATUSCODE_BADWAITINGFORINITIALDATA = (UA_Int32) 0x80320000, // Waiting for the server to obtain values from the underlying data source.
-	UA_STATUSCODE_BADNODEIDINVALID = (UA_Int32) 0x80330000, // The syntax of the node id is not valid.
-	UA_STATUSCODE_BADNODEIDUNKNOWN = (UA_Int32) 0x80340000, // The node id refers to a node that does not exist in the server address space.
-	UA_STATUSCODE_BADATTRIBUTEIDINVALID = (UA_Int32) 0x80350000, // The attribute is not supported for the specified Node.
-	UA_STATUSCODE_BADINDEXRANGEINVALID = (UA_Int32) 0x80360000, // The syntax of the index range parameter is invalid.
-	UA_STATUSCODE_BADINDEXRANGENODATA = (UA_Int32) 0x80370000, // No data exists within the range of indexes specified.
-	UA_STATUSCODE_BADDATAENCODINGINVALID = (UA_Int32) 0x80380000, // The data encoding is invalid.
-	UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED = (UA_Int32) 0x80390000, // The server does not support the requested data encoding for the node.
-	UA_STATUSCODE_BADNOTREADABLE = (UA_Int32) 0x803a0000, // The access level does not allow reading or subscribing to the Node.
-	UA_STATUSCODE_BADNOTWRITABLE = (UA_Int32) 0x803b0000, // The access level does not allow writing to the Node.
-	UA_STATUSCODE_BADOUTOFRANGE = (UA_Int32) 0x803c0000, // The value was out of range.
-	UA_STATUSCODE_BADNOTSUPPORTED = (UA_Int32) 0x803d0000, // The requested operation is not supported.
-	UA_STATUSCODE_BADNOTFOUND = (UA_Int32) 0x803e0000, // A requested item was not found or a search operation ended without success.
-	UA_STATUSCODE_BADOBJECTDELETED = (UA_Int32) 0x803f0000, // The object cannot be used because it has been deleted.
-	UA_STATUSCODE_BADNOTIMPLEMENTED = (UA_Int32) 0x80400000, // Requested operation is not implemented.
-	UA_STATUSCODE_BADMONITORINGMODEINVALID = (UA_Int32) 0x80410000, // The monitoring mode is invalid.
-	UA_STATUSCODE_BADMONITOREDITEMIDINVALID = (UA_Int32) 0x80420000, // The monitoring item id does not refer to a valid monitored item.
-	UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID = (UA_Int32) 0x80430000, // The monitored item filter parameter is not valid.
-	UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED = (UA_Int32) 0x80440000, // The server does not support the requested monitored item filter.
-	UA_STATUSCODE_BADFILTERNOTALLOWED = (UA_Int32) 0x80450000, // A monitoring filter cannot be used in combination with the attribute specified.
-	UA_STATUSCODE_BADSTRUCTUREMISSING = (UA_Int32) 0x80460000, // A mandatory structured parameter was missing or null.
-	UA_STATUSCODE_BADEVENTFILTERINVALID = (UA_Int32) 0x80470000, // The event filter is not valid.
-	UA_STATUSCODE_BADCONTENTFILTERINVALID = (UA_Int32) 0x80480000, // The content filter is not valid.
-	UA_STATUSCODE_BADFILTEROPERATORINVALID = (UA_Int32) 0x80c10000, // An unregognized operator was provided in a filter.
-	UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED = (UA_Int32) 0x80c20000, // A valid operator was provided, but the server does not provide support for this filter operator.
-	UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH = (UA_Int32) 0x80c30000, // The number of operands provided for the filter operator was less then expected for the operand provided.
-	UA_STATUSCODE_BADFILTEROPERANDINVALID = (UA_Int32) 0x80490000, // The operand used in a content filter is not valid.
-	UA_STATUSCODE_BADFILTERELEMENTINVALID = (UA_Int32) 0x80c40000, // The referenced element is not a valid element in the content filter.
-	UA_STATUSCODE_BADFILTERLITERALINVALID = (UA_Int32) 0x80c50000, // The referenced literal is not a valid value.
-	UA_STATUSCODE_BADCONTINUATIONPOINTINVALID = (UA_Int32) 0x804a0000, // The continuation point provide is longer valid.
-	UA_STATUSCODE_BADNOCONTINUATIONPOINTS = (UA_Int32) 0x804b0000, // The operation could not be processed because all continuation points have been allocated.
-	UA_STATUSCODE_BADREFERENCETYPEIDINVALID = (UA_Int32) 0x804c0000, // The operation could not be processed because all continuation points have been allocated.
-	UA_STATUSCODE_BADBROWSEDIRECTIONINVALID = (UA_Int32) 0x804d0000, // The browse direction is not valid.
-	UA_STATUSCODE_BADNODENOTINVIEW = (UA_Int32) 0x804e0000, // The node is not part of the view.
-	UA_STATUSCODE_BADSERVERURIINVALID = (UA_Int32) 0x804f0000, // The ServerUri is not a valid URI.
-	UA_STATUSCODE_BADSERVERNAMEMISSING = (UA_Int32) 0x80500000, // No ServerName was specified.
-	UA_STATUSCODE_BADDISCOVERYURLMISSING = (UA_Int32) 0x80510000, // No DiscoveryUrl was specified.
-	UA_STATUSCODE_BADSEMPAHOREFILEMISSING = (UA_Int32) 0x80520000, // The semaphore file specified by the client is not valid.
-	UA_STATUSCODE_BADREQUESTTYPEINVALID = (UA_Int32) 0x80530000, // The security token request type is not valid.
-	UA_STATUSCODE_BADSECURITYMODEREJECTED = (UA_Int32) 0x80540000, // The security mode does not meet the requirements set by the Server.
-	UA_STATUSCODE_BADSECURITYPOLICYREJECTED = (UA_Int32) 0x80550000, // The security policy does not meet the requirements set by the Server.
-	UA_STATUSCODE_BADTOOMANYSESSIONS = (UA_Int32) 0x80560000, // The server has reached its maximum number of sessions.
-	UA_STATUSCODE_BADUSERSIGNATUREINVALID = (UA_Int32) 0x80570000, // The user token signature is missing or invalid.
-	UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID = (UA_Int32) 0x80580000, // The signature generated with the client certificate is missing or invalid.
-	UA_STATUSCODE_BADNOVALIDCERTIFICATES = (UA_Int32) 0x80590000, // The client did not provide at least one software certificate that is valid and meets the profile requirements for the server.
-	UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED = (UA_Int32) 0x80c60000, // The Server does not support changing the user identity assigned to the session.
-	UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST = (UA_Int32) 0x805a0000, // The request was cancelled by the client with the Cancel service.
-	UA_STATUSCODE_BADPARENTNODEIDINVALID = (UA_Int32) 0x805b0000, // The parent node id does not to refer to a valid node.
-	UA_STATUSCODE_BADREFERENCENOTALLOWED = (UA_Int32) 0x805c0000, // The reference could not be created because it violates constraints imposed by the data model.
-	UA_STATUSCODE_BADNODEIDREJECTED = (UA_Int32) 0x805d0000, // The requested node id was reject because it was either invalid or server does not allow node ids to be specified by the client.
-	UA_STATUSCODE_BADNODEIDEXISTS = (UA_Int32) 0x805e0000, // The requested node id is already used by another node.
-	UA_STATUSCODE_BADNODECLASSINVALID = (UA_Int32) 0x805f0000, // The node class is not valid.
-	UA_STATUSCODE_BADBROWSENAMEINVALID = (UA_Int32) 0x80600000, // The browse name is invalid.
-	UA_STATUSCODE_BADBROWSENAMEDUPLICATED = (UA_Int32) 0x80610000, // The browse name is not unique among nodes that share the same relationship with the parent.
-	UA_STATUSCODE_BADNODEATTRIBUTESINVALID = (UA_Int32) 0x80620000, // The node attributes are not valid for the node class.
-	UA_STATUSCODE_BADTYPEDEFINITIONINVALID = (UA_Int32) 0x80630000, // The type definition node id does not reference an appropriate type node.
-	UA_STATUSCODE_BADSOURCENODEIDINVALID = (UA_Int32) 0x80640000, // The source node id does not reference a valid node.
-	UA_STATUSCODE_BADTARGETNODEIDINVALID = (UA_Int32) 0x80650000, // The target node id does not reference a valid node.
-	UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED = (UA_Int32) 0x80660000, // The reference type between the nodes is already defined.
-	UA_STATUSCODE_BADINVALIDSELFREFERENCE = (UA_Int32) 0x80670000, // The server does not allow this type of self reference on this node.
-	UA_STATUSCODE_BADREFERENCELOCALONLY = (UA_Int32) 0x80680000, // The reference type is not valid for a reference to a remote server.
-	UA_STATUSCODE_BADNODELETERIGHTS = (UA_Int32) 0x80690000, // The server will not allow the node to be deleted.
-	UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED = (UA_Int32) 0x40bc0000, // The server was not able to delete all target references.
-	UA_STATUSCODE_BADSERVERINDEXINVALID = (UA_Int32) 0x806a0000, // The server index is not valid.
-	UA_STATUSCODE_BADVIEWIDUNKNOWN = (UA_Int32) 0x806b0000, // The view id does not refer to a valid view node.
-	UA_STATUSCODE_BADVIEWTIMESTAMPINVALID = (UA_Int32) 0x80c90000, // The view timestamp is not available or not supported.
-	UA_STATUSCODE_BADVIEWPARAMETERMISMATCH = (UA_Int32) 0x80ca0000, // The view parameters are not consistent with each other.
-	UA_STATUSCODE_BADVIEWVERSIONINVALID = (UA_Int32) 0x80cb0000, // The view version is not available or not supported.
-	UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE = (UA_Int32) 0x40c00000, // The list of references may not be complete because the underlying system is not available.
-	UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE = (UA_Int32) 0x00ba0000, // The server should have followed a reference to a node in a remote server but did not. The result set may be incomplete.
-	UA_STATUSCODE_BADNOTTYPEDEFINITION = (UA_Int32) 0x80c80000, // The provided Nodeid was not a type definition nodeid.
-	UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER = (UA_Int32) 0x406c0000, // One of the references to follow in the relative path references to a node in the address space in another server.
-	UA_STATUSCODE_BADTOOMANYMATCHES = (UA_Int32) 0x806d0000, // The requested operation has too many matches to return.
-	UA_STATUSCODE_BADQUERYTOOCOMPLEX = (UA_Int32) 0x806e0000, // The requested operation requires too many resources in the server.
-	UA_STATUSCODE_BADNOMATCH = (UA_Int32) 0x806f0000, // The requested operation has no match to return.
-	UA_STATUSCODE_BADMAXAGEINVALID = (UA_Int32) 0x80700000, // The max age parameter is invalid.
-	UA_STATUSCODE_BADHISTORYOPERATIONINVALID = (UA_Int32) 0x80710000, // The history details parameter is not valid.
-	UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED = (UA_Int32) 0x80720000, // The server does not support the requested operation.
-	UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT = (UA_Int32) 0x80bd0000, // The defined timestamp to return was invalid.
-	UA_STATUSCODE_BADWRITENOTSUPPORTED = (UA_Int32) 0x80730000, // The server not does support writing the combination of value, status and timestamps provided.
-	UA_STATUSCODE_BADTYPEMISMATCH = (UA_Int32) 0x80740000, // The value supplied for the attribute is not of the same type as the attribute's value.
-	UA_STATUSCODE_BADMETHODINVALID = (UA_Int32) 0x80750000, // The method id does not refer to a method for the specified object.
-	UA_STATUSCODE_BADARGUMENTSMISSING = (UA_Int32) 0x80760000, // The client did not specify all of the input arguments for the method.
-	UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS = (UA_Int32) 0x80770000, // The server has reached its  maximum number of subscriptions.
-	UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS = (UA_Int32) 0x80780000, // The server has reached the maximum number of queued publish requests.
-	UA_STATUSCODE_BADNOSUBSCRIPTION = (UA_Int32) 0x80790000, // There is no subscription available for this session.
-	UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN = (UA_Int32) 0x807a0000, // The sequence number is unknown to the server.
-	UA_STATUSCODE_BADMESSAGENOTAVAILABLE = (UA_Int32) 0x807b0000, // The requested notification message is no longer available.
-	UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE = (UA_Int32) 0x807c0000, // The Client of the current Session does not support one or more Profiles that are necessary for the Subscription.
-	UA_STATUSCODE_BADSTATENOTACTIVE = (UA_Int32) 0x80bf0000, // The sub-state machine is not currently active.
-	UA_STATUSCODE_BADTCPSERVERTOOBUSY = (UA_Int32) 0x807d0000, // The server cannot process the request because it is too busy.
-	UA_STATUSCODE_BADTCPMESSAGETYPEINVALID = (UA_Int32) 0x807e0000, // The type of the message specified in the header invalid.
-	UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN = (UA_Int32) 0x807f0000, // The SecureChannelId and/or TokenId are not currently in use.
-	UA_STATUSCODE_BADTCPMESSAGETOOLARGE = (UA_Int32) 0x80800000, // The size of the message specified in the header is too large.
-	UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES = (UA_Int32) 0x80810000, // There are not enough resources to process the request.
-	UA_STATUSCODE_BADTCPINTERNALERROR = (UA_Int32) 0x80820000, // An internal error occurred.
-	UA_STATUSCODE_BADTCPENDPOINTURLINVALID = (UA_Int32) 0x80830000, // The Server does not recognize the QueryString specified.
-	UA_STATUSCODE_BADREQUESTINTERRUPTED = (UA_Int32) 0x80840000, // The request could not be sent because of a network interruption.
-	UA_STATUSCODE_BADREQUESTTIMEOUT = (UA_Int32) 0x80850000, // Timeout occurred while processing the request.
-	UA_STATUSCODE_BADSECURECHANNELCLOSED = (UA_Int32) 0x80860000, // The secure channel has been closed.
-	UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN = (UA_Int32) 0x80870000, // The token has expired or is not recognized.
-	UA_STATUSCODE_BADSEQUENCENUMBERINVALID = (UA_Int32) 0x80880000, // The sequence number is not valid.
-	UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED = (UA_Int32) 0x80be0000, // The applications do not have compatible protocol versions.
-	UA_STATUSCODE_BADCONFIGURATIONERROR = (UA_Int32) 0x80890000, // There is a problem with the configuration that affects the usefulness of the value.
-	UA_STATUSCODE_BADNOTCONNECTED = (UA_Int32) 0x808a0000, // The variable should receive its value from another variable, but has never been configured to do so.
-	UA_STATUSCODE_BADDEVICEFAILURE = (UA_Int32) 0x808b0000, // There has been a failure in the device/data source that generates the value that has affected the value.
-	UA_STATUSCODE_BADSENSORFAILURE = (UA_Int32) 0x808c0000, // There has been a failure in the sensor from which the value is derived by the device/data source.
-	UA_STATUSCODE_BADOUTOFSERVICE = (UA_Int32) 0x808d0000, // The source of the data is not operational.
-	UA_STATUSCODE_BADDEADBANDFILTERINVALID = (UA_Int32) 0x808e0000, // The deadband filter is not valid.
-	UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE = (UA_Int32) 0x408f0000, // Communication to the data source has failed. The variable value is the last value that had a good quality.
-	UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE = (UA_Int32) 0x40900000, // Whatever was updating this value has stopped doing so.
-	UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE = (UA_Int32) 0x40910000, // The value is an operational value that was manually overwritten.
-	UA_STATUSCODE_UNCERTAININITIALVALUE = (UA_Int32) 0x40920000, // The value is an initial value for a variable that normally receives its value from another variable.
-	UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE = (UA_Int32) 0x40930000, // The value is at one of the sensor limits.
-	UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED = (UA_Int32) 0x40940000, // The value is outside of the range of values defined for this parameter.
-	UA_STATUSCODE_UNCERTAINSUBNORMAL = (UA_Int32) 0x40950000, // The value is derived from multiple sources and has less than the required number of Good sources.
-	UA_STATUSCODE_GOODLOCALOVERRIDE = (UA_Int32) 0x00960000, // The value has been overridden.
-	UA_STATUSCODE_BADREFRESHINPROGRESS = (UA_Int32) 0x80970000, // This Condition refresh failed, a Condition refresh operation is already in progress.
-	UA_STATUSCODE_BADCONDITIONALREADYDISABLED = (UA_Int32) 0x80980000, // This condition has already been disabled.
-	UA_STATUSCODE_BADCONDITIONALREADYENABLED = (UA_Int32) 0x80cc0000, // This condition has already been enabled.
-	UA_STATUSCODE_BADCONDITIONDISABLED = (UA_Int32) 0x80990000, // Property not available, this condition is disabled.
-	UA_STATUSCODE_BADEVENTIDUNKNOWN = (UA_Int32) 0x809a0000, // The specified event id is not recognized.
-	UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE = (UA_Int32) 0x80bb0000, // The event cannot be acknowledged.
-	UA_STATUSCODE_BADDIALOGNOTACTIVE = (UA_Int32) 0x80cd0000, // The dialog condition is not active.
-	UA_STATUSCODE_BADDIALOGRESPONSEINVALID = (UA_Int32) 0x80ce0000, // The response is not valid for the dialog.
-	UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED = (UA_Int32) 0x80cf0000, // The condition branch has already been acknowledged.
-	UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED = (UA_Int32) 0x80d00000, // The condition branch has already been confirmed.
-	UA_STATUSCODE_BADCONDITIONALREADYSHELVED = (UA_Int32) 0x80d10000, // The condition has already been shelved.
-	UA_STATUSCODE_BADCONDITIONNOTSHELVED = (UA_Int32) 0x80d20000, // The condition is not currently shelved.
-	UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE = (UA_Int32) 0x80d30000, // The shelving time not within an acceptable range.
-	UA_STATUSCODE_BADNODATA = (UA_Int32) 0x809b0000, // No data exists for the requested time range or event filter.
-	UA_STATUSCODE_BADBOUNDNOTFOUND = (UA_Int32) 0x80d70000, // No data found to provide upper or lower bound value.
-	UA_STATUSCODE_BADBOUNDNOTSUPPORTED = (UA_Int32) 0x80d80000, // The server cannot retrieve a bound for the variable.
-	UA_STATUSCODE_BADDATALOST = (UA_Int32) 0x809d0000, // Data is missing due to collection started/stopped/lost.
-	UA_STATUSCODE_BADDATAUNAVAILABLE = (UA_Int32) 0x809e0000, // Expected data is unavailable for the requested time range due to an un-mounted volume, an off-line archive or tape, or similar reason for temporary unavailability.
-	UA_STATUSCODE_BADENTRYEXISTS = (UA_Int32) 0x809f0000, // The data or event was not successfully inserted because a matching entry exists.
-	UA_STATUSCODE_BADNOENTRYEXISTS = (UA_Int32) 0x80a00000, // The data or event was not successfully updated because no matching entry exists.
-	UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED = (UA_Int32) 0x80a10000, // The client requested history using a timestamp format the server does not support (i.e requested ServerTimestamp when server only supports SourceTimestamp).
-	UA_STATUSCODE_GOODENTRYINSERTED = (UA_Int32) 0x00a20000, // The data or event was successfully inserted into the historical database.
-	UA_STATUSCODE_GOODENTRYREPLACED = (UA_Int32) 0x00a30000, // The data or event field was successfully replaced in the historical database.
-	UA_STATUSCODE_UNCERTAINDATASUBNORMAL = (UA_Int32) 0x40a40000, // The value is derived from multiple values and has less than the required number of Good values.
-	UA_STATUSCODE_GOODNODATA = (UA_Int32) 0x00a50000, // No data exists for the requested time range or event filter.
-	UA_STATUSCODE_GOODMOREDATA = (UA_Int32) 0x00a60000, // The data or event field was successfully replaced in the historical database.
-	UA_STATUSCODE_BADAGGREGATELISTMISMATCH = (UA_Int32) 0x80d40000, // The requested number of Aggregates does not match the requested number of NodeIds.
-	UA_STATUSCODE_BADAGGREGATENOTSUPPORTED = (UA_Int32) 0x80d50000, // The requested Aggregate is not support by the server.
-	UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS = (UA_Int32) 0x80d60000, // The aggregate value could not be derived due to invalid data inputs.
-	UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED = (UA_Int32) 0x80da0000, // The aggregate configuration is not valid for specified node.
-	UA_STATUSCODE_GOODDATAIGNORED = (UA_Int32) 0x00d90000, // The request pecifies fields which are not valid for the EventType or cannot be saved by the historian.
-	UA_STATUSCODE_GOODCOMMUNICATIONEVENT = (UA_Int32) 0x00a70000, // The communication layer has raised an event.
-	UA_STATUSCODE_GOODSHUTDOWNEVENT = (UA_Int32) 0x00a80000, // The system is shutting down.
-	UA_STATUSCODE_GOODCALLAGAIN = (UA_Int32) 0x00a90000, // The operation is not finished and needs to be called again.
-	UA_STATUSCODE_GOODNONCRITICALTIMEOUT = (UA_Int32) 0x00aa0000, // A non-critical timeout occurred.
-	UA_STATUSCODE_BADINVALIDARGUMENT = (UA_Int32) 0x80ab0000, // One or more arguments are invalid.
-	UA_STATUSCODE_BADCONNECTIONREJECTED = (UA_Int32) 0x80ac0000, // Could not establish a network connection to remote server.
-	UA_STATUSCODE_BADDISCONNECT = (UA_Int32) 0x80ad0000, // The server has disconnected from the client.
-	UA_STATUSCODE_BADCONNECTIONCLOSED = (UA_Int32) 0x80ae0000, // The network connection has been closed.
-	UA_STATUSCODE_BADINVALIDSTATE = (UA_Int32) 0x80af0000, // The operation cannot be completed because the object is closed, uninitialized or in some other invalid state.
-	UA_STATUSCODE_BADENDOFSTREAM = (UA_Int32) 0x80b00000, // Cannot move beyond end of the stream.
-	UA_STATUSCODE_BADNODATAAVAILABLE = (UA_Int32) 0x80b10000, // No data is currently available for reading from a non-blocking stream.
-	UA_STATUSCODE_BADWAITINGFORRESPONSE = (UA_Int32) 0x80b20000, // The asynchronous operation is waiting for a response.
-	UA_STATUSCODE_BADOPERATIONABANDONED = (UA_Int32) 0x80b30000, // The asynchronous operation was abandoned by the caller.
-	UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK = (UA_Int32) 0x80b40000, // The stream did not return all data requested (possibly because it is a non-blocking stream).
-	UA_STATUSCODE_BADWOULDBLOCK = (UA_Int32) 0x80b50000, // Non blocking behaviour is required and the operation would block.
-	UA_STATUSCODE_BADSYNTAXERROR = (UA_Int32) 0x80b60000, // A value had an invalid syntax.
-	UA_STATUSCODE_BADMAXCONNECTIONSREACHED = (UA_Int32) 0x80b70000 // The operation could not be finished because all available connections are in use.
+	UA_STATUSCODE_GOOD = 0x00,
+	UA_STATUSCODE_BADUNEXPECTEDERROR = 0x80010000, // An unexpected error occurred.
+	UA_STATUSCODE_BADINTERNALERROR = 0x80020000, // An internal error occurred as a result of a programming or configuration error.
+	UA_STATUSCODE_BADOUTOFMEMORY = 0x80030000, // Not enough memory to complete the operation.
+	UA_STATUSCODE_BADRESOURCEUNAVAILABLE = 0x80040000, // An operating system resource is not available.
+	UA_STATUSCODE_BADCOMMUNICATIONERROR = 0x80050000, // A low level communication error occurred.
+	UA_STATUSCODE_BADENCODINGERROR = 0x80060000, // Encoding halted because of invalid data in the objects being serialized.
+	UA_STATUSCODE_BADDECODINGERROR = 0x80070000, // Decoding halted because of invalid data in the stream.
+	UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED = 0x80080000, // The message encoding/decoding limits imposed by the stack have been exceeded.
+	UA_STATUSCODE_BADREQUESTTOOLARGE = 0x80b80000, // The request message size exceeds limits set by the server.
+	UA_STATUSCODE_BADRESPONSETOOLARGE = 0x80b90000, // The response message size exceeds limits set by the client.
+	UA_STATUSCODE_BADUNKNOWNRESPONSE = 0x80090000, // An unrecognized response was received from the server.
+	UA_STATUSCODE_BADTIMEOUT = 0x800a0000, // The operation timed out.
+	UA_STATUSCODE_BADSERVICEUNSUPPORTED = 0x800b0000, // The server does not support the requested service.
+	UA_STATUSCODE_BADSHUTDOWN = 0x800c0000, // The operation was cancelled because the application is shutting down.
+	UA_STATUSCODE_BADSERVERNOTCONNECTED = 0x800d0000, // The operation could not complete because the client is not connected to the server.
+	UA_STATUSCODE_BADSERVERHALTED = 0x800e0000, // The server has stopped and cannot process any requests.
+	UA_STATUSCODE_BADNOTHINGTODO = 0x800f0000, // There was nothing to do because the client passed a list of operations with no elements.
+	UA_STATUSCODE_BADTOOMANYOPERATIONS = 0x80100000, // The request could not be processed because it specified too many operations.
+	UA_STATUSCODE_BADTOOMANYMONITOREDITEMS = 0x80db0000, // The request could not be processed because there are too many monitored items in the subscription.
+	UA_STATUSCODE_BADDATATYPEIDUNKNOWN = 0x80110000, // The extension object cannot be (de)serialized because the data type id is not recognized.
+	UA_STATUSCODE_BADCERTIFICATEINVALID = 0x80120000, // The certificate provided as a parameter is not valid.
+	UA_STATUSCODE_BADSECURITYCHECKSFAILED = 0x80130000, // An error occurred verifying security.
+	UA_STATUSCODE_BADCERTIFICATETIMEINVALID = 0x80140000, // The Certificate has expired or is not yet valid.
+	UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID = 0x80150000, // An Issuer Certificate has expired or is not yet valid.
+	UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID = 0x80160000, // The HostName used to connect to a Server does not match a HostName in the Certificate.
+	UA_STATUSCODE_BADCERTIFICATEURIINVALID = 0x80170000, // The URI specified in the ApplicationDescription does not match the URI in the Certificate.
+	UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED = 0x80180000, // The Certificate may not be used for the requested operation.
+	UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED = 0x80190000, // The Issuer Certificate may not be used for the requested operation.
+	UA_STATUSCODE_BADCERTIFICATEUNTRUSTED = 0x801a0000, // The Certificate is not trusted.
+	UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN = 0x801b0000, // It was not possible to determine if the Certificate has been revoked.
+	UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN = 0x801c0000, // It was not possible to determine if the Issuer Certificate has been revoked.
+	UA_STATUSCODE_BADCERTIFICATEREVOKED = 0x801d0000, // The Certificate has been revoked.
+	UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED = 0x801e0000, // The Issuer Certificate has been revoked.
+	UA_STATUSCODE_BADUSERACCESSDENIED = 0x801f0000, // User does not have permission to perform the requested operation.
+	UA_STATUSCODE_BADIDENTITYTOKENINVALID = 0x80200000, // The user identity token is not valid.
+	UA_STATUSCODE_BADIDENTITYTOKENREJECTED = 0x80210000, // The user identity token is valid but the server has rejected it.
+	UA_STATUSCODE_BADSECURECHANNELIDINVALID = 0x80220000, // The specified secure channel is no longer valid.
+	UA_STATUSCODE_BADINVALIDTIMESTAMP = 0x80230000, // The timestamp is outside the range allowed by the server.
+	UA_STATUSCODE_BADNONCEINVALID = 0x80240000, // The nonce does appear to be not a random value or it is not the correct length.
+	UA_STATUSCODE_BADSESSIONIDINVALID = 0x80250000, // The session id is not valid.
+	UA_STATUSCODE_BADSESSIONCLOSED = 0x80260000, // The session was closed by the client.
+	UA_STATUSCODE_BADSESSIONNOTACTIVATED = 0x80270000, // The session cannot be used because ActivateSession has not been called.
+	UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID = 0x80280000, // The subscription id is not valid.
+	UA_STATUSCODE_BADREQUESTHEADERINVALID = 0x802a0000, // The header for the request is missing or invalid.
+	UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID = 0x802b0000, // The timestamps to return parameter is invalid.
+	UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT = 0x802c0000, // The request was cancelled by the client.
+	UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED = 0x002d0000, // The subscription was transferred to another session.
+	UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY = 0x002e0000, // The processing will complete asynchronously.
+	UA_STATUSCODE_GOODOVERLOAD = 0x002f0000, // Sampling has slowed down due to resource limitations.
+	UA_STATUSCODE_GOODCLAMPED = 0x00300000, // The value written was accepted but was clamped.
+	UA_STATUSCODE_BADNOCOMMUNICATION = 0x80310000, // Communication with the data source is defined, but not established, and there is no last known value available.
+	UA_STATUSCODE_BADWAITINGFORINITIALDATA = 0x80320000, // Waiting for the server to obtain values from the underlying data source.
+	UA_STATUSCODE_BADNODEIDINVALID = 0x80330000, // The syntax of the node id is not valid.
+	UA_STATUSCODE_BADNODEIDUNKNOWN = 0x80340000, // The node id refers to a node that does not exist in the server address space.
+	UA_STATUSCODE_BADATTRIBUTEIDINVALID = 0x80350000, // The attribute is not supported for the specified Node.
+	UA_STATUSCODE_BADINDEXRANGEINVALID = 0x80360000, // The syntax of the index range parameter is invalid.
+	UA_STATUSCODE_BADINDEXRANGENODATA = 0x80370000, // No data exists within the range of indexes specified.
+	UA_STATUSCODE_BADDATAENCODINGINVALID = 0x80380000, // The data encoding is invalid.
+	UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED = 0x80390000, // The server does not support the requested data encoding for the node.
+	UA_STATUSCODE_BADNOTREADABLE = 0x803a0000, // The access level does not allow reading or subscribing to the Node.
+	UA_STATUSCODE_BADNOTWRITABLE = 0x803b0000, // The access level does not allow writing to the Node.
+	UA_STATUSCODE_BADOUTOFRANGE = 0x803c0000, // The value was out of range.
+	UA_STATUSCODE_BADNOTSUPPORTED = 0x803d0000, // The requested operation is not supported.
+	UA_STATUSCODE_BADNOTFOUND = 0x803e0000, // A requested item was not found or a search operation ended without success.
+	UA_STATUSCODE_BADOBJECTDELETED = 0x803f0000, // The object cannot be used because it has been deleted.
+	UA_STATUSCODE_BADNOTIMPLEMENTED = 0x80400000, // Requested operation is not implemented.
+	UA_STATUSCODE_BADMONITORINGMODEINVALID = 0x80410000, // The monitoring mode is invalid.
+	UA_STATUSCODE_BADMONITOREDITEMIDINVALID = 0x80420000, // The monitoring item id does not refer to a valid monitored item.
+	UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID = 0x80430000, // The monitored item filter parameter is not valid.
+	UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED = 0x80440000, // The server does not support the requested monitored item filter.
+	UA_STATUSCODE_BADFILTERNOTALLOWED = 0x80450000, // A monitoring filter cannot be used in combination with the attribute specified.
+	UA_STATUSCODE_BADSTRUCTUREMISSING = 0x80460000, // A mandatory structured parameter was missing or null.
+	UA_STATUSCODE_BADEVENTFILTERINVALID = 0x80470000, // The event filter is not valid.
+	UA_STATUSCODE_BADCONTENTFILTERINVALID = 0x80480000, // The content filter is not valid.
+	UA_STATUSCODE_BADFILTEROPERATORINVALID = 0x80c10000, // An unregognized operator was provided in a filter.
+	UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED = 0x80c20000, // A valid operator was provided, but the server does not provide support for this filter operator.
+	UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH = 0x80c30000, // The number of operands provided for the filter operator was less then expected for the operand provided.
+	UA_STATUSCODE_BADFILTEROPERANDINVALID = 0x80490000, // The operand used in a content filter is not valid.
+	UA_STATUSCODE_BADFILTERELEMENTINVALID = 0x80c40000, // The referenced element is not a valid element in the content filter.
+	UA_STATUSCODE_BADFILTERLITERALINVALID = 0x80c50000, // The referenced literal is not a valid value.
+	UA_STATUSCODE_BADCONTINUATIONPOINTINVALID = 0x804a0000, // The continuation point provide is longer valid.
+	UA_STATUSCODE_BADNOCONTINUATIONPOINTS = 0x804b0000, // The operation could not be processed because all continuation points have been allocated.
+	UA_STATUSCODE_BADREFERENCETYPEIDINVALID = 0x804c0000, // The operation could not be processed because all continuation points have been allocated.
+	UA_STATUSCODE_BADBROWSEDIRECTIONINVALID = 0x804d0000, // The browse direction is not valid.
+	UA_STATUSCODE_BADNODENOTINVIEW = 0x804e0000, // The node is not part of the view.
+	UA_STATUSCODE_BADSERVERURIINVALID = 0x804f0000, // The ServerUri is not a valid URI.
+	UA_STATUSCODE_BADSERVERNAMEMISSING = 0x80500000, // No ServerName was specified.
+	UA_STATUSCODE_BADDISCOVERYURLMISSING = 0x80510000, // No DiscoveryUrl was specified.
+	UA_STATUSCODE_BADSEMPAHOREFILEMISSING = 0x80520000, // The semaphore file specified by the client is not valid.
+	UA_STATUSCODE_BADREQUESTTYPEINVALID = 0x80530000, // The security token request type is not valid.
+	UA_STATUSCODE_BADSECURITYMODEREJECTED = 0x80540000, // The security mode does not meet the requirements set by the Server.
+	UA_STATUSCODE_BADSECURITYPOLICYREJECTED = 0x80550000, // The security policy does not meet the requirements set by the Server.
+	UA_STATUSCODE_BADTOOMANYSESSIONS = 0x80560000, // The server has reached its maximum number of sessions.
+	UA_STATUSCODE_BADUSERSIGNATUREINVALID = 0x80570000, // The user token signature is missing or invalid.
+	UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID = 0x80580000, // The signature generated with the client certificate is missing or invalid.
+	UA_STATUSCODE_BADNOVALIDCERTIFICATES = 0x80590000, // The client did not provide at least one software certificate that is valid and meets the profile requirements for the server.
+	UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED = 0x80c60000, // The Server does not support changing the user identity assigned to the session.
+	UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST = 0x805a0000, // The request was cancelled by the client with the Cancel service.
+	UA_STATUSCODE_BADPARENTNODEIDINVALID = 0x805b0000, // The parent node id does not to refer to a valid node.
+	UA_STATUSCODE_BADREFERENCENOTALLOWED = 0x805c0000, // The reference could not be created because it violates constraints imposed by the data model.
+	UA_STATUSCODE_BADNODEIDREJECTED = 0x805d0000, // The requested node id was reject because it was either invalid or server does not allow node ids to be specified by the client.
+	UA_STATUSCODE_BADNODEIDEXISTS = 0x805e0000, // The requested node id is already used by another node.
+	UA_STATUSCODE_BADNODECLASSINVALID = 0x805f0000, // The node class is not valid.
+	UA_STATUSCODE_BADBROWSENAMEINVALID = 0x80600000, // The browse name is invalid.
+	UA_STATUSCODE_BADBROWSENAMEDUPLICATED = 0x80610000, // The browse name is not unique among nodes that share the same relationship with the parent.
+	UA_STATUSCODE_BADNODEATTRIBUTESINVALID = 0x80620000, // The node attributes are not valid for the node class.
+	UA_STATUSCODE_BADTYPEDEFINITIONINVALID = 0x80630000, // The type definition node id does not reference an appropriate type node.
+	UA_STATUSCODE_BADSOURCENODEIDINVALID = 0x80640000, // The source node id does not reference a valid node.
+	UA_STATUSCODE_BADTARGETNODEIDINVALID = 0x80650000, // The target node id does not reference a valid node.
+	UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED = 0x80660000, // The reference type between the nodes is already defined.
+	UA_STATUSCODE_BADINVALIDSELFREFERENCE = 0x80670000, // The server does not allow this type of self reference on this node.
+	UA_STATUSCODE_BADREFERENCELOCALONLY = 0x80680000, // The reference type is not valid for a reference to a remote server.
+	UA_STATUSCODE_BADNODELETERIGHTS = 0x80690000, // The server will not allow the node to be deleted.
+	UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED = 0x40bc0000, // The server was not able to delete all target references.
+	UA_STATUSCODE_BADSERVERINDEXINVALID = 0x806a0000, // The server index is not valid.
+	UA_STATUSCODE_BADVIEWIDUNKNOWN = 0x806b0000, // The view id does not refer to a valid view node.
+	UA_STATUSCODE_BADVIEWTIMESTAMPINVALID = 0x80c90000, // The view timestamp is not available or not supported.
+	UA_STATUSCODE_BADVIEWPARAMETERMISMATCH = 0x80ca0000, // The view parameters are not consistent with each other.
+	UA_STATUSCODE_BADVIEWVERSIONINVALID = 0x80cb0000, // The view version is not available or not supported.
+	UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE = 0x40c00000, // The list of references may not be complete because the underlying system is not available.
+	UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE = 0x00ba0000, // The server should have followed a reference to a node in a remote server but did not. The result set may be incomplete.
+	UA_STATUSCODE_BADNOTTYPEDEFINITION = 0x80c80000, // The provided Nodeid was not a type definition nodeid.
+	UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER = 0x406c0000, // One of the references to follow in the relative path references to a node in the address space in another server.
+	UA_STATUSCODE_BADTOOMANYMATCHES = 0x806d0000, // The requested operation has too many matches to return.
+	UA_STATUSCODE_BADQUERYTOOCOMPLEX = 0x806e0000, // The requested operation requires too many resources in the server.
+	UA_STATUSCODE_BADNOMATCH = 0x806f0000, // The requested operation has no match to return.
+	UA_STATUSCODE_BADMAXAGEINVALID = 0x80700000, // The max age parameter is invalid.
+	UA_STATUSCODE_BADHISTORYOPERATIONINVALID = 0x80710000, // The history details parameter is not valid.
+	UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED = 0x80720000, // The server does not support the requested operation.
+	UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT = 0x80bd0000, // The defined timestamp to return was invalid.
+	UA_STATUSCODE_BADWRITENOTSUPPORTED = 0x80730000, // The server not does support writing the combination of value, status and timestamps provided.
+	UA_STATUSCODE_BADTYPEMISMATCH = 0x80740000, // The value supplied for the attribute is not of the same type as the attribute's value.
+	UA_STATUSCODE_BADMETHODINVALID = 0x80750000, // The method id does not refer to a method for the specified object.
+	UA_STATUSCODE_BADARGUMENTSMISSING = 0x80760000, // The client did not specify all of the input arguments for the method.
+	UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS = 0x80770000, // The server has reached its  maximum number of subscriptions.
+	UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS = 0x80780000, // The server has reached the maximum number of queued publish requests.
+	UA_STATUSCODE_BADNOSUBSCRIPTION = 0x80790000, // There is no subscription available for this session.
+	UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN = 0x807a0000, // The sequence number is unknown to the server.
+	UA_STATUSCODE_BADMESSAGENOTAVAILABLE = 0x807b0000, // The requested notification message is no longer available.
+	UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE = 0x807c0000, // The Client of the current Session does not support one or more Profiles that are necessary for the Subscription.
+	UA_STATUSCODE_BADSTATENOTACTIVE = 0x80bf0000, // The sub-state machine is not currently active.
+	UA_STATUSCODE_BADTCPSERVERTOOBUSY = 0x807d0000, // The server cannot process the request because it is too busy.
+	UA_STATUSCODE_BADTCPMESSAGETYPEINVALID = 0x807e0000, // The type of the message specified in the header invalid.
+	UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN = 0x807f0000, // The SecureChannelId and/or TokenId are not currently in use.
+	UA_STATUSCODE_BADTCPMESSAGETOOLARGE = 0x80800000, // The size of the message specified in the header is too large.
+	UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES = 0x80810000, // There are not enough resources to process the request.
+	UA_STATUSCODE_BADTCPINTERNALERROR = 0x80820000, // An internal error occurred.
+	UA_STATUSCODE_BADTCPENDPOINTURLINVALID = 0x80830000, // The Server does not recognize the QueryString specified.
+	UA_STATUSCODE_BADREQUESTINTERRUPTED = 0x80840000, // The request could not be sent because of a network interruption.
+	UA_STATUSCODE_BADREQUESTTIMEOUT = 0x80850000, // Timeout occurred while processing the request.
+	UA_STATUSCODE_BADSECURECHANNELCLOSED = 0x80860000, // The secure channel has been closed.
+	UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN = 0x80870000, // The token has expired or is not recognized.
+	UA_STATUSCODE_BADSEQUENCENUMBERINVALID = 0x80880000, // The sequence number is not valid.
+	UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED = 0x80be0000, // The applications do not have compatible protocol versions.
+	UA_STATUSCODE_BADCONFIGURATIONERROR = 0x80890000, // There is a problem with the configuration that affects the usefulness of the value.
+	UA_STATUSCODE_BADNOTCONNECTED = 0x808a0000, // The variable should receive its value from another variable, but has never been configured to do so.
+	UA_STATUSCODE_BADDEVICEFAILURE = 0x808b0000, // There has been a failure in the device/data source that generates the value that has affected the value.
+	UA_STATUSCODE_BADSENSORFAILURE = 0x808c0000, // There has been a failure in the sensor from which the value is derived by the device/data source.
+	UA_STATUSCODE_BADOUTOFSERVICE = 0x808d0000, // The source of the data is not operational.
+	UA_STATUSCODE_BADDEADBANDFILTERINVALID = 0x808e0000, // The deadband filter is not valid.
+	UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE = 0x408f0000, // Communication to the data source has failed. The variable value is the last value that had a good quality.
+	UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE = 0x40900000, // Whatever was updating this value has stopped doing so.
+	UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE = 0x40910000, // The value is an operational value that was manually overwritten.
+	UA_STATUSCODE_UNCERTAININITIALVALUE = 0x40920000, // The value is an initial value for a variable that normally receives its value from another variable.
+	UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE = 0x40930000, // The value is at one of the sensor limits.
+	UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED = 0x40940000, // The value is outside of the range of values defined for this parameter.
+	UA_STATUSCODE_UNCERTAINSUBNORMAL = 0x40950000, // The value is derived from multiple sources and has less than the required number of Good sources.
+	UA_STATUSCODE_GOODLOCALOVERRIDE = 0x00960000, // The value has been overridden.
+	UA_STATUSCODE_BADREFRESHINPROGRESS = 0x80970000, // This Condition refresh failed, a Condition refresh operation is already in progress.
+	UA_STATUSCODE_BADCONDITIONALREADYDISABLED = 0x80980000, // This condition has already been disabled.
+	UA_STATUSCODE_BADCONDITIONALREADYENABLED = 0x80cc0000, // This condition has already been enabled.
+	UA_STATUSCODE_BADCONDITIONDISABLED = 0x80990000, // Property not available, this condition is disabled.
+	UA_STATUSCODE_BADEVENTIDUNKNOWN = 0x809a0000, // The specified event id is not recognized.
+	UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE = 0x80bb0000, // The event cannot be acknowledged.
+	UA_STATUSCODE_BADDIALOGNOTACTIVE = 0x80cd0000, // The dialog condition is not active.
+	UA_STATUSCODE_BADDIALOGRESPONSEINVALID = 0x80ce0000, // The response is not valid for the dialog.
+	UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED = 0x80cf0000, // The condition branch has already been acknowledged.
+	UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED = 0x80d00000, // The condition branch has already been confirmed.
+	UA_STATUSCODE_BADCONDITIONALREADYSHELVED = 0x80d10000, // The condition has already been shelved.
+	UA_STATUSCODE_BADCONDITIONNOTSHELVED = 0x80d20000, // The condition is not currently shelved.
+	UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE = 0x80d30000, // The shelving time not within an acceptable range.
+	UA_STATUSCODE_BADNODATA = 0x809b0000, // No data exists for the requested time range or event filter.
+	UA_STATUSCODE_BADBOUNDNOTFOUND = 0x80d70000, // No data found to provide upper or lower bound value.
+	UA_STATUSCODE_BADBOUNDNOTSUPPORTED = 0x80d80000, // The server cannot retrieve a bound for the variable.
+	UA_STATUSCODE_BADDATALOST = 0x809d0000, // Data is missing due to collection started/stopped/lost.
+	UA_STATUSCODE_BADDATAUNAVAILABLE = 0x809e0000, // Expected data is unavailable for the requested time range due to an un-mounted volume, an off-line archive or tape, or similar reason for temporary unavailability.
+	UA_STATUSCODE_BADENTRYEXISTS = 0x809f0000, // The data or event was not successfully inserted because a matching entry exists.
+	UA_STATUSCODE_BADNOENTRYEXISTS = 0x80a00000, // The data or event was not successfully updated because no matching entry exists.
+	UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED = 0x80a10000, // The client requested history using a timestamp format the server does not support (i.e requested ServerTimestamp when server only supports SourceTimestamp).
+	UA_STATUSCODE_GOODENTRYINSERTED = 0x00a20000, // The data or event was successfully inserted into the historical database.
+	UA_STATUSCODE_GOODENTRYREPLACED = 0x00a30000, // The data or event field was successfully replaced in the historical database.
+	UA_STATUSCODE_UNCERTAINDATASUBNORMAL = 0x40a40000, // The value is derived from multiple values and has less than the required number of Good values.
+	UA_STATUSCODE_GOODNODATA = 0x00a50000, // No data exists for the requested time range or event filter.
+	UA_STATUSCODE_GOODMOREDATA = 0x00a60000, // The data or event field was successfully replaced in the historical database.
+	UA_STATUSCODE_BADAGGREGATELISTMISMATCH = 0x80d40000, // The requested number of Aggregates does not match the requested number of NodeIds.
+	UA_STATUSCODE_BADAGGREGATENOTSUPPORTED = 0x80d50000, // The requested Aggregate is not support by the server.
+	UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS = 0x80d60000, // The aggregate value could not be derived due to invalid data inputs.
+	UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED = 0x80da0000, // The aggregate configuration is not valid for specified node.
+	UA_STATUSCODE_GOODDATAIGNORED = 0x00d90000, // The request pecifies fields which are not valid for the EventType or cannot be saved by the historian.
+	UA_STATUSCODE_GOODCOMMUNICATIONEVENT = 0x00a70000, // The communication layer has raised an event.
+	UA_STATUSCODE_GOODSHUTDOWNEVENT = 0x00a80000, // The system is shutting down.
+	UA_STATUSCODE_GOODCALLAGAIN = 0x00a90000, // The operation is not finished and needs to be called again.
+	UA_STATUSCODE_GOODNONCRITICALTIMEOUT = 0x00aa0000, // A non-critical timeout occurred.
+	UA_STATUSCODE_BADINVALIDARGUMENT = 0x80ab0000, // One or more arguments are invalid.
+	UA_STATUSCODE_BADCONNECTIONREJECTED = 0x80ac0000, // Could not establish a network connection to remote server.
+	UA_STATUSCODE_BADDISCONNECT = 0x80ad0000, // The server has disconnected from the client.
+	UA_STATUSCODE_BADCONNECTIONCLOSED = 0x80ae0000, // The network connection has been closed.
+	UA_STATUSCODE_BADINVALIDSTATE = 0x80af0000, // The operation cannot be completed because the object is closed, uninitialized or in some other invalid state.
+	UA_STATUSCODE_BADENDOFSTREAM = 0x80b00000, // Cannot move beyond end of the stream.
+	UA_STATUSCODE_BADNODATAAVAILABLE = 0x80b10000, // No data is currently available for reading from a non-blocking stream.
+	UA_STATUSCODE_BADWAITINGFORRESPONSE = 0x80b20000, // The asynchronous operation is waiting for a response.
+	UA_STATUSCODE_BADOPERATIONABANDONED = 0x80b30000, // The asynchronous operation was abandoned by the caller.
+	UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK = 0x80b40000, // The stream did not return all data requested (possibly because it is a non-blocking stream).
+	UA_STATUSCODE_BADWOULDBLOCK = 0x80b50000, // Non blocking behaviour is required and the operation would block.
+	UA_STATUSCODE_BADSYNTAXERROR = 0x80b60000, // A value had an invalid syntax.
+	UA_STATUSCODE_BADMAXCONNECTIONSREACHED = 0x80b70000 // The operation could not be finished because all available connections are in use.
 };
 
 #endif /* UA_STATUSCODES_H_ */
-#endif /* UA_TYPES_H_ */

+ 57 - 52
include/ua_types.h

@@ -188,51 +188,37 @@ typedef struct {
     UA_ByteString body; // contains either the bytestring or a pointer to the memory-object
 } UA_ExtensionObject;
 
-/** @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  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. 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 *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;
-
 struct UA_DataType;
 typedef struct UA_DataType UA_DataType; 
 
+/** @brief NumericRanges are used select a subset in a (multidimensional) variant array.
+    NumericRange has no official type structure in the standard. Officially, it only exists as an
+    encoded string, such as "1:2,0:3,5". The colon separates min/max index and the comma separates
+    dimensions. A single value indicates a range with a single element (min==max). */
+typedef struct {
+    UA_Int32 dimensionsSize;
+    struct UA_NumericRangeDimension {
+        UA_UInt32 min;
+        UA_UInt32 max;
+    } *dimensions;
+} UA_NumericRange;
+
 /** @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_DataType *type;
-    UA_NodeId typeId;
     enum {
         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;
-        UA_VariantDataSource datasource;
-    } storage;
+    UA_Int32  arrayLength;  ///< the number of elements in the data-pointer
+    void     *dataPtr; ///< points to the scalar or array data
+    UA_Int32  arrayDimensionsSize; ///< the number of dimensions the data-array has
+    UA_Int32 *arrayDimensions; ///< the length of each dimension of the data-array
 } UA_Variant;
 
 /** @brief A data value with an associated status code and timestamps. */
@@ -269,12 +255,16 @@ typedef struct UA_DiagnosticInfo {
     struct UA_DiagnosticInfo *innerDiagnosticInfo;
 } UA_DiagnosticInfo;
 
+#ifndef SWIG
 #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);
+#else
+#define UA_TYPE_HANDLING_FUNCTIONS(TYPE)
+#endif
 
 /* Functions for all types */
 UA_TYPE_HANDLING_FUNCTIONS(UA_Boolean)
@@ -307,11 +297,11 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_Guid)
 #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
+#define UA_StatusCode_new(p) UA_Int32_new((UA_Int32*)p)
+#define UA_StatusCode_init(p) UA_Int32_init((UA_Int32*)p)
+#define UA_StatusCode_delete(p) UA_Int32_delete((UA_Int32*)p)
+#define UA_StatusCode_deleteMembers(p) UA_Int32_deleteMembers((UA_Int32*)p)
+#define UA_StatusCode_copy(p) UA_Int32_copy((UA_Int32*)p)
 UA_TYPE_HANDLING_FUNCTIONS(UA_QualifiedName)
 UA_TYPE_HANDLING_FUNCTIONS(UA_LocalizedText)
 UA_TYPE_HANDLING_FUNCTIONS(UA_ExtensionObject)
@@ -402,7 +392,7 @@ 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 }
+        .serverIndex = 0, .namespaceUri = {.data = (UA_Byte*)0, .length = -1} }
     
 /* QualifiedName */
 UA_StatusCode UA_EXPORT UA_QualifiedName_copycstring(char const *src, UA_QualifiedName *dst);
@@ -417,28 +407,40 @@ UA_StatusCode UA_EXPORT UA_LocalizedText_copycstring(char const *src, UA_Localiz
 
 /* Variant */
 
+/**
+ * Variant semantics:
+ *  - arrayLength = -1 && dataPtr == NULL: empty variant
+ *  - arrayLength = -1 && dataPtr == !NULL: variant holds a single element (a scalar)
+ *  - arrayLength >= 0: variant holds an array of the appropriate length
+ *                    : dataPtr can be NULL if arrayLength == 0
+ */
+
+/**
+ * Copy the variant, but use only a subset of the (multidimensional) array. Returns an error code if
+ * the variant is no array or if the indicated range does not fit.
+ */
+UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, UA_NumericRange range);
+
 /**
  * Set the variant to a scalar value that already resides in memory. The value takes on the
  * lifecycle of the variant and is deleted with it.
  *
  * @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
+ * @param p A pointer to the value data
+ * @param type The datatype of the value in question
  * @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);
+UA_StatusCode UA_EXPORT UA_Variant_setScalar(UA_Variant *v, void *p, const UA_DataType *type);
 
 /**
  * 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
+ * @param p A pointer to the value data
+ * @param type The datatype of the value
  * @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);
+UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type);
 
 /**
  * Set the variant to an array that already resides in memory. The array takes on the lifecycle of
@@ -447,11 +449,11 @@ UA_StatusCode UA_EXPORT UA_Variant_copySetValue(UA_Variant *v, const void *p, UA
  * @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
+ * @param type The datatype of the array
  * @return Indicates whether the operation succeeded or returns an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElements, UA_UInt16 typeIndex);
+UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array,
+                                            UA_Int32 noElements, const UA_DataType *type);
 
 /**
  * Set the variant to an array that is copied from an existing array.
@@ -459,11 +461,11 @@ UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32
  * @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
+ * @param type The datatype of the array
  * @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);
+UA_StatusCode UA_EXPORT UA_Variant_setArrayCopy(UA_Variant *v, const void *array,
+                                                UA_Int32 noElements, const UA_DataType *type);
 
 /****************************/
 /* Structured Type Handling */
@@ -477,6 +479,8 @@ UA_StatusCode UA_EXPORT UA_Variant_copySetArray(UA_Variant *v, const void *array
 # define UA_BITFIELD(SIZE)
 #endif
 
+#define UA_IS_BUILTIN(ID) (ID <= UA_TYPES_DIAGNOSTICINFO)
+
 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
@@ -491,8 +495,9 @@ typedef struct {
 } 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_NodeId typeId; ///< The nodeid of the type
+    ptrdiff_t memSize UA_BITFIELD(16); ///< Size of the struct in memory
+    UA_UInt16 typeIndex UA_BITFIELD(13); ///< Index of the type in the datatypetable
     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?

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

@@ -18,7 +18,7 @@ index c785182..9e66da0 100644
  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
+-                -Wshadow -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes # -Wconversion
 -                -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -ffunction-sections -fdata-sections)
 +add_definitions(-std=c99 -fomit-frame-pointer -pipe -msoft-float -fno-builtin -DEMBED -fno-strict-aliasing)
      if(NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
@@ -36,15 +36,16 @@ index c785182..9e66da0 100644
  	endif()
  endif()
  
-@@ -90,10 +90,7 @@ else()
+@@ -90,11 +90,7 @@ else()
  endif()
  
  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
--target_compile_definitions(open62541-objects PUBLIC UA_DYNAMIC_LINKING)
+-target_compile_definitions(open62541-objects PRIVATE UA_DYNAMIC_LINKING)
+-target_compile_definitions(open62541-static PRIVATE UA_DYNAMIC_LINKING)
 +add_library(open62541 $<TARGET_OBJECTS:open62541-objects>)
  
  ## logging
- set(UA_LOGLEVEL 400 CACHE STRING "Level at which logs shall be reported")
+ set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")

+ 5 - 0
src/client/ua_client.c

@@ -23,6 +23,11 @@ UA_Client * UA_Client_new(void) {
     return c;
 }
 
+void UA_Client_delete(UA_Client* client){
+	if(client)
+		free(client);
+}
+
 static UA_StatusCode HelAckHandshake(UA_Client *c);
 static UA_StatusCode SecureChannelHandshake(UA_Client *c);
 static UA_StatusCode SessionHandshake(UA_Client *c);

+ 0 - 11
src/ongoing/wrappers/Makefile.am

@@ -1,11 +0,0 @@
-# We expand open62541.h with the preprocessor. SWIG can't handle all our macros.
-# The standard libs are not included into the expanded header file.
-
-# the lib is stated as a dependency to refresh if a header changes in ../src
-open62541_expanded.h: open62541.h open62541.i $(top_builddir)/lib/libopen62541.a
-	gcc -E open62541.h > open62541_expanded.h -I../src -D_STDIO_H=1 -D_STDDEF_H=1 -D_STDLIB_H=1 -D_STRING_H=1 -D_CTYPE_H=1 -D_UNISTD_H=1 -D_STDINT_H=1
-
-all: open62541_expanded.h
-
-clean-local:
-	rm -rf open62541_expanded.h

+ 0 - 20
src/ongoing/wrappers/lua/Makefile.am

@@ -1,20 +0,0 @@
-INCLUDEDIRS = -I$(top_builddir)/src -I$(top_builddir)/src/util -I$(top_builddir)/examples/src
-AM_CFLAGS = $(GLOBAL_AM_CFLAGS) $(INCLUDEDIRS)
-WRAPPER_DIR = $(top_builddir)/wrappers
-
-open62541.lua open62541_wrap_lua.c:
-	swig -lua $(INCLUDEDIRS) -o ./open62541_wrap_lua.c $(WRAPPER_DIR)/open62541.i
-
-networklayer.so:
-	gcc -c $(AM_CFLAGS) $(top_builddir)/examples/src/networklayer.c -o networklayer.so
-
-open62541_wrap_lua.o: open62541_wrap_lua.c
-	gcc -c $(subst -Wall, ,$(subst -Wreturn-type, ,$(subst -pedantic, , $(AM_CFLAGS)))) -I/usr/include/lua5.2 open62541_wrap_lua.c
-
-open62541.so: networklayer.so open62541_wrap_lua.o
-	ld -shared open62541_wrap_lua.o networklayer.so $(top_builddir)/lib/libopen62541.so -o open62541.so
-
-all: open62541.lua open62541.so
-
-clean-local:
-	rm -rf networklayer.so open62541.lua open62541.so open62541_wrap_lua.c open62541_wrap_lua.o || true;

+ 0 - 2
src/ongoing/wrappers/open62541.h

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

+ 0 - 9
src/ongoing/wrappers/open62541.i

@@ -1,9 +0,0 @@
-%module open62541
-%{
-/* Includes the header in the wrapper code */
-#include "open62541_expanded.h"
-%}
-
-/* Parse the header file to generate wrappers */
-%include "stdint.i"
-%include "open62541_expanded.h"

+ 0 - 18
src/ongoing/wrappers/python/Makefile.am

@@ -1,18 +0,0 @@
-WRAPPER_DIR = $(top_builddir)/wrappers
-#AM_CFLAGS = $(GLOBAL_AM_CFLAGS) -I$(WRAPPER_DIR)
-AM_CFLAGS = -fPIC -I$(WRAPPER_DIR)
-
-open62541.py open62541_wrap_python.c: $(WRAPPER_DIR)/open62541.i \
-									  $(WRAPPER_DIR)/open62541_expanded.h
-	swig -python -o ./open62541_wrap_python.c $(WRAPPER_DIR)/open62541.i
-
-open62541_wrap_python.o: open62541_wrap_python.c
-	gcc -c $(subst -pedantic, , $(AM_CFLAGS)) -I/usr/include/python2.7 open62541_wrap_python.c
-
-_open62541.so: open62541_wrap_python.o
-	ld -shared open62541_wrap_python.o $(top_builddir)/lib/libopen62541.a -lexpat -o _open62541.so
-
-all: open62541.py _open62541.so
-
-clean-local:
-	rm -rf open62541.py open62541.pyc _open62541.so open62541_wrap_python.c open62541_wrap_python.o || true;

+ 10 - 4
src/server/ua_nodes.c

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

+ 13 - 7
src/server/ua_nodes.h

@@ -1,6 +1,7 @@
 #ifndef UA_NODES_H_
 #define UA_NODES_H_
 
+#include "ua_server.h"
 #include "ua_types_generated.h"
 #include "ua_types_encoding_binary.h"
 
@@ -33,28 +34,33 @@ 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
+    enum {
+        UA_VARIABLENODETYPE_VARIANT,
+        UA_VARIABLENODETYPE_DATASOURCE
+    } variableType;
+    union {
+        UA_Variant variant;
+        UA_DataSource dataSource;
+    } variable;
     UA_Byte accessLevel;
     UA_Byte userAccessLevel;
     UA_Double minimumSamplingInterval;
     UA_Boolean historizing;
 } UA_VariableNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_VariableNode)
+/** Make a copy but leave out the references and the variable */
+UA_StatusCode UA_VariableNode_copyWithoutRefsAndVariable(const UA_VariableNode *src, UA_VariableNode *dst);
 
 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_Int32 valueRank;
+    UA_Variant value;
 } UA_VariableTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)
 

+ 4 - 1
src/server/ua_nodestore.c

@@ -252,6 +252,9 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
         // find a unique nodeid that is not taken
         node->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
         node->nodeId.namespaceIndex = 1; // namespace 1 is always in the local nodestore
+        if(node->nodeClass==UA_NODECLASS_VARIABLE){ //set namespaceIndex in browseName in case id is generated
+        	((UA_VariableNode*)node)->browseName.namespaceIndex=node->nodeId.namespaceIndex;
+        }
         UA_Int32 identifier = ns->count+1; // start value
         UA_Int32 size = ns->size;
         hash_t increase = mod2(identifier, size);
@@ -267,7 +270,7 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
         if(containsNodeId(ns, &node->nodeId, &slot))
             return UA_STATUSCODE_BADNODEIDEXISTS;
     }
-    
+
     struct nodeEntry *entry = nodeEntryFromNode(node);
     if(!entry)
         return UA_STATUSCODE_BADOUTOFMEMORY;

+ 4 - 7
src/server/ua_nodestore_concurrent.c

@@ -1,11 +1,5 @@
-#define _LGPL_SOURCE
-#include <urcu.h>
-#include <urcu/compiler.h> // for caa_container_of
-#include <urcu/uatomic.h>
-#include <urcu/rculfhash.h>
-
-#include "ua_nodestore.h"
 #include "ua_util.h"
+#include "ua_nodestore.h"
 
 #define ALIVE_BIT (1 << 15) /* Alive bit in the refcount */
 
@@ -175,6 +169,9 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
         /* create a unique nodeid */
         ((UA_Node *)&entry->node)->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
         ((UA_Node *)&entry->node)->nodeId.namespaceIndex = 1; // namespace 1 is always in the local nodestore
+        if(((UA_Node *)&entry->node)->nodeClass==UA_NODECLASS_VARIABLE){ //set namespaceIndex in browseName in case id is generated
+        	((UA_VariableNode*)&entry->node)->browseName.namespaceIndex=((UA_Node *)&entry->node)->nodeId.namespaceIndex;
+        }
         unsigned long identifier;
         long before, after;
         rcu_read_lock();

+ 12 - 12
src/server/ua_securechannel_manager.c

@@ -1,5 +1,3 @@
-#include <stdio.h>
-
 #include "ua_securechannel_manager.h"
 #include "ua_session.h"
 #include "ua_statuscodes.h"
@@ -21,16 +19,18 @@ UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_UInt3
 }
 
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
-    struct channel_list_entry *entry = LIST_FIRST(&cm->channels);
-    while(entry) {
-        LIST_REMOVE(entry, pointers);
-        if(entry->channel.session)
-            entry->channel.session->channel = UA_NULL;
-        if(entry->channel.connection)
-            entry->channel.connection->channel = UA_NULL;
-        UA_SecureChannel_deleteMembers(&entry->channel);
-        UA_free(entry);
-        entry = LIST_FIRST(&cm->channels);
+    struct channel_list_entry *current;
+    struct channel_list_entry *next = LIST_FIRST(&cm->channels);
+    while(next) {
+        current = next;
+        next = LIST_NEXT(current, pointers);
+        LIST_REMOVE(current, pointers);
+        if(current->channel.session)
+            current->channel.session->channel = UA_NULL;
+        if(current->channel.connection)
+            current->channel.connection->channel = UA_NULL;
+        UA_SecureChannel_deleteMembers(&current->channel);
+        UA_free(current);
     }
 }
 

+ 1 - 2
src/server/ua_securechannel_manager.h

@@ -1,10 +1,9 @@
 #ifndef UA_CHANNEL_MANAGER_H_
 #define UA_CHANNEL_MANAGER_H_
 
-#include "../deps/queue.h"
+#include "ua_util.h"
 #include "ua_server.h"
 #include "ua_securechannel.h"
-#include "ua_util.h"
 
 typedef struct UA_SecureChannelManager {
     LIST_HEAD(channel_list, channel_list_entry) channels; // doubly-linked list of channels

+ 459 - 176
src/server/ua_server.c

@@ -1,8 +1,3 @@
-#ifdef UA_MULTITHREADING
-#define _LGPL_SOURCE
-#include <urcu.h>
-#endif
-
 #include "ua_types.h"
 #include "ua_server_internal.h"
 #include "ua_securechannel_manager.h"
@@ -11,6 +6,8 @@
 #include "ua_services.h"
 #include "ua_nodeids.h"
 
+const char *UA_LoggerCategoryNames[3] = {"communication", "server", "userland"};
+
 /**********************/
 /* Namespace Handling */
 /**********************/
@@ -30,13 +27,34 @@ static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
 /*****************/
 
 void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
-    server->nls = UA_realloc(server->nls, sizeof(UA_ServerNetworkLayer)*(server->nlsSize+1));
+    UA_ServerNetworkLayer *newlayers = UA_realloc(server->nls, sizeof(UA_ServerNetworkLayer)*(server->nlsSize+1));
+    if(!newlayers) {
+        UA_LOG_ERROR(server->logger, UA_LOGGERCATEGORY_SERVER, "Networklayer added");
+        return;
+    }
+    server->nls = newlayers;
     server->nls[server->nlsSize] = networkLayer;
     server->nlsSize++;
+
+    if(networkLayer.discoveryUrl){
+		UA_String* newUrls = UA_realloc(server->description.discoveryUrls, sizeof(UA_String)*(server->description.discoveryUrlsSize+1)); //TODO: rework this pattern into *_array_insert
+		if(!newUrls) {
+			UA_LOG_ERROR(server->logger, UA_LOGGERCATEGORY_SERVER, "Adding discoveryUrl");
+			return;
+		}
+		server->description.discoveryUrls = newUrls;
+		UA_String_copy(networkLayer.discoveryUrl, &server->description.discoveryUrls[0]);
+		server->description.discoveryUrlsSize++;
+    }
 }
 
 void UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate) {
-    UA_ByteString_copy(&certificate, &server->serverCertificate);
+    for(UA_Int32 i=0;i<server->endpointDescriptionsSize;i++)
+        UA_ByteString_copy(&certificate, &server->endpointDescriptions[i].serverCertificate);
+}
+
+void UA_Server_setLogger(UA_Server *server, UA_Logger logger) {
+    server->logger = logger;
 }
 
 /**********/
@@ -44,29 +62,125 @@ void UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate
 /**********/
 
 void UA_Server_delete(UA_Server *server) {
-    // The server needs to be stopped before it can be deleted
+	// The server needs to be stopped before it can be deleted
+
+	// Delete all internal data
+	UA_ApplicationDescription_deleteMembers(&server->description);
+	UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
+	UA_SessionManager_deleteMembers(&server->sessionManager);
+	UA_NodeStore_delete(server->nodestore);
+	UA_ByteString_deleteMembers(&server->serverCertificate);
+	UA_Array_delete(server->endpointDescriptions, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], server->endpointDescriptionsSize);
+
+	// Delete the timed work
+	UA_Server_deleteTimedWork(server);
+
+
+	// Delete the network layers
+	for(UA_Int32 i=0;i<server->nlsSize;i++) {
+		server->nls[i].free(server->nls[i].nlHandle);
+	}
+	UA_free(server->nls);
 
-    // Delete the network layers
-    for(UA_Int32 i=0;i<server->nlsSize;i++) {
-        server->nls[i].free(server->nls[i].nlHandle);
-    }
-    UA_free(server->nls);
-
-    // Delete the timed work
-    UA_Server_deleteTimedWork(server);
-
-    // Delete all internal data
-    UA_ApplicationDescription_deleteMembers(&server->description);
-    UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
-    UA_SessionManager_deleteMembers(&server->sessionManager);
-    UA_NodeStore_delete(server->nodestore);
-    UA_ByteString_deleteMembers(&server->serverCertificate);
-    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
+	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
 #endif
-    UA_free(server);
+	UA_free(server);
+}
+
+static UA_StatusCode readStatus(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+    UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
+    status->startTime   = ((const UA_Server*)handle)->startTime;
+    status->currentTime = UA_DateTime_now();
+    status->state       = UA_SERVERSTATE_RUNNING;
+    UA_String_copycstring("http://www.open62541.org", &status->buildInfo.productUri);
+    UA_String_copycstring("open62541", &status->buildInfo.manufacturerName);
+    UA_String_copycstring("open62541 OPC UA Server", &status->buildInfo.productName);
+#define STRINGIFY(x) #x //some magic
+#define TOSTRING(x) STRINGIFY(x) //some magic
+    UA_String_copycstring(TOSTRING(OPEN62541_VERSION_MAJOR) "." TOSTRING(OPEN62541_VERSION_MINOR) "." TOSTRING(OPEN62541_VERSION_PATCH), &status->buildInfo.softwareVersion);
+    UA_String_copycstring("0", &status->buildInfo.buildNumber);
+    status->buildInfo.buildDate = ((const UA_Server*)handle)->buildDate;
+    status->secondsTillShutdown = 0;
+    value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
+	value->value.arrayLength = -1;
+    value->value.dataPtr = status;
+    value->value.arrayDimensionsSize = -1;
+    value->value.arrayDimensions = UA_NULL;
+    value->hasVariant = UA_TRUE;
+    if(sourceTimeStamp) {
+        value->hasSourceTimestamp = UA_TRUE;
+        value->sourceTimestamp = UA_DateTime_now();
+    }
+    return UA_STATUSCODE_GOOD;
+}
+
+static void releaseStatus(const void *handle, UA_DataValue *value) {
+    UA_DataValue_deleteMembers(value);
+}
+
+static UA_StatusCode readCurrentTime(const void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+	UA_DateTime *currentTime = UA_DateTime_new();
+	if(!currentTime)
+		return UA_STATUSCODE_BADOUTOFMEMORY;
+	*currentTime = UA_DateTime_now();
+	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
+	value->value.arrayLength = -1;
+	value->value.dataPtr = currentTime;
+	value->value.arrayDimensionsSize = -1;
+	value->value.arrayDimensions = NULL;
+	value->hasVariant = UA_TRUE;
+	if(sourceTimeStamp) {
+		value->hasSourceTimestamp = UA_TRUE;
+		value->sourceTimestamp = *currentTime;
+	}
+	return UA_STATUSCODE_GOOD;
+}
+
+static void releaseCurrentTime(const void *handle, UA_DataValue *value) {
+	UA_DateTime_delete((UA_DateTime*)value->value.dataPtr);
+}
+
+static void copyNames(UA_Node *node, char *name) {
+    UA_QualifiedName_copycstring(name, &node->browseName);
+    UA_LocalizedText_copycstring(name, &node->displayName);
+    UA_LocalizedText_copycstring(name, &node->description);
+}
+
+static void addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid, UA_Int32 parent) {
+    UA_DataTypeNode *datatype = UA_DataTypeNode_new();
+    copyNames((UA_Node*)datatype, name);
+    datatype->nodeId.identifier.numeric = datatypeid;
+    UA_Server_addNode(server, (UA_Node*)datatype,
+                      &UA_EXPANDEDNODEID_STATIC(0, parent),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+}
+
+static UA_VariableTypeNode* createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid, UA_Int32 parent, UA_Boolean abstract) {
+    UA_VariableTypeNode *variabletype = UA_VariableTypeNode_new();
+    copyNames((UA_Node*)variabletype, name);
+    variabletype->nodeId.identifier.numeric = variabletypeid;
+    variabletype->isAbstract = abstract;
+    variabletype->value.type = &UA_TYPES[UA_TYPES_VARIANT];
+
+    return variabletype;
+}
+
+static void addVariableTypeNode_organized(UA_Server *server, char* name, UA_UInt32 variabletypeid, UA_Int32 parent, UA_Boolean abstract) {
+	UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
+
+    UA_Server_addNode(server, (UA_Node*)variabletype,
+                      &UA_EXPANDEDNODEID_STATIC(0, parent),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+}
+
+static void addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletypeid, UA_Int32 parent, UA_Boolean abstract) {
+	UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
+
+    UA_Server_addNode(server, (UA_Node*)variabletype,
+                      &UA_EXPANDEDNODEID_STATIC(0, parent),
+                      &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 }
 
 UA_Server * UA_Server_new(void) {
@@ -77,49 +191,60 @@ UA_Server * UA_Server_new(void) {
     LIST_INIT(&server->timedWork);
 #ifdef UA_MULTITHREADING
     rcu_init();
-	cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
+    cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
     server->delayedWork = UA_NULL;
 #endif
 
+    // logger
+    server->logger = (UA_Logger){ UA_NULL, UA_NULL, UA_NULL, UA_NULL, UA_NULL, UA_NULL };
+
     // random seed
-    server->random_seed = (UA_UInt32) UA_DateTime_now();
+    server->random_seed = (UA_UInt32)UA_DateTime_now();
 
     // networklayers
     server->nls = UA_NULL;
     server->nlsSize = 0;
 
     UA_ByteString_init(&server->serverCertificate);
-        
+
+#define PRODUCT_URI "http://open62541.org"
+#define APPLICATION_URI "urn:unconfigured:open62541:open62541Server"
     // mockup application description
     UA_ApplicationDescription_init(&server->description);
-    UA_String_copycstring("urn:unconfigured:open62541:application", &server->description.productUri);
-    UA_String_copycstring("http://unconfigured.open62541/applications/", &server->description.applicationUri);
+    UA_String_copycstring(PRODUCT_URI, &server->description.productUri);
+    UA_String_copycstring(APPLICATION_URI, &server->description.applicationUri);
+    server->description.discoveryUrlsSize = 0;
+
     UA_LocalizedText_copycstring("Unconfigured open62541 application", &server->description.applicationName);
     server->description.applicationType = UA_APPLICATIONTYPE_SERVER;
     server->externalNamespacesSize = 0;
     server->externalNamespaces = UA_NULL;
 
-    // mockup endpoint description
-    server->endpointDescriptionsSize = 1;
     UA_EndpointDescription *endpoint = UA_EndpointDescription_new(); // todo: check return code
-
-    endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
-    UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &endpoint->securityPolicyUri);
-    UA_String_copycstring("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary", &endpoint->transportProfileUri);
-
-    endpoint->userIdentityTokensSize = 1;
-    endpoint->userIdentityTokens = UA_malloc(sizeof(UA_UserTokenPolicy));
-    UA_UserTokenPolicy_init(endpoint->userIdentityTokens);
-    UA_String_copycstring("my-anonymous-policy", &endpoint->userIdentityTokens->policyId); // defined per server
-    endpoint->userIdentityTokens->tokenType = UA_USERTOKENTYPE_ANONYMOUS;
-
-    /* UA_String_copy(endpointUrl, &endpoint->endpointUrl); */
-    /* /\* The standard says "the HostName specified in the Server Certificate is the */
-    /*    same as the HostName contained in the endpointUrl provided in the */
-    /*    EndpointDescription *\/ */
-    /* UA_String_copy(&server->serverCertificate, &endpoint->serverCertificate); */
-    UA_ApplicationDescription_copy(&server->description, &endpoint->server);
-    server->endpointDescriptions = endpoint;
+    if(endpoint) {
+        endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
+        UA_String_copycstring("http://opcfoundation.org/UA/SecurityPolicy#None", &endpoint->securityPolicyUri);
+        UA_String_copycstring("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary", &endpoint->transportProfileUri);
+        endpoint->userIdentityTokens = UA_malloc(sizeof(UA_UserTokenPolicy));
+        if(!endpoint->userIdentityTokens) {
+            UA_EndpointDescription_delete(endpoint);
+        } else {
+            UA_UserTokenPolicy_init(endpoint->userIdentityTokens);
+            endpoint->userIdentityTokens->tokenType = UA_USERTOKENTYPE_ANONYMOUS;
+            UA_String_copycstring("my-anonymous-policy", &endpoint->userIdentityTokens->policyId); // defined per server
+
+            /* UA_String_copy(endpointUrl, &endpoint->endpointUrl); */
+            /* /\* The standard says "the HostName specified in the Server Certificate is the */
+            /*    same as the HostName contained in the endpointUrl provided in the */
+            /*    EndpointDescription *\/ */
+            /* UA_String_copy(&server->serverCertificate, &endpoint->serverCertificate); */
+            UA_ApplicationDescription_copy(&server->description, &endpoint->server);
+
+            endpoint->userIdentityTokensSize = 1;
+            server->endpointDescriptions = endpoint;
+            server->endpointDescriptionsSize = 1;
+        }
+    }
 
 #define MAXCHANNELCOUNT 100
 #define STARTCHANNELID 1
@@ -129,35 +254,19 @@ UA_Server * UA_Server_new(void) {
                                  TOKENLIFETIME, STARTCHANNELID, STARTTOKENID);
 
 #define MAXSESSIONCOUNT 1000
-#define SESSIONLIFETIME 10000
+#define MAXSESSIONLIFETIME 10000
 #define STARTSESSIONID 1
-    UA_SessionManager_init(&server->sessionManager, MAXSESSIONCOUNT, SESSIONLIFETIME, STARTSESSIONID);
+    UA_SessionManager_init(&server->sessionManager, MAXSESSIONCOUNT, MAXSESSIONLIFETIME, STARTSESSIONID);
 
     server->nodestore = UA_NodeStore_new();
 
-#define ADDREFERENCE(NODEID, REFTYPE_NODEID, TARGET_EXPNODEID) do {     \
-        UA_AddReferencesItem item;                                      \
-        UA_AddReferencesItem_init(&item);                               \
-        item.sourceNodeId = NODEID;                                     \
-        item.referenceTypeId = REFTYPE_NODEID;                          \
-        item.isForward = UA_TRUE;                                       \
-        item.targetNodeId = TARGET_EXPNODEID;                           \
-        UA_Server_addReference(server, &item);                          \
-    } while(0)
-
-#define COPYNAMES(TARGET, NAME) do {                                \
-        UA_QualifiedName_copycstring(NAME, &TARGET->browseName);    \
-        UA_LocalizedText_copycstring(NAME, &TARGET->displayName);   \
-        UA_LocalizedText_copycstring(NAME, &TARGET->description);   \
-    } while(0)
-
     /**************/
     /* References */
     /**************/
     
     /* bootstrap by manually inserting "references" and "hassubtype" */
     UA_ReferenceTypeNode *references = UA_ReferenceTypeNode_new();
-    COPYNAMES(references, "References");
+    copyNames((UA_Node*)references, "References");
     references->nodeId.identifier.numeric = UA_NS0ID_REFERENCES;
     references->isAbstract = UA_TRUE;
     references->symmetric  = UA_TRUE;
@@ -165,8 +274,8 @@ UA_Server * UA_Server_new(void) {
     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);
+    copyNames((UA_Node*)hassubtype, "HasSubtype");
+    UA_LocalizedText_copycstring("HasSupertype", &hassubtype->inverseName);
     hassubtype->nodeId.identifier.numeric = UA_NS0ID_HASSUBTYPE;
     hassubtype->isAbstract = UA_FALSE;
     hassubtype->symmetric  = UA_FALSE;
@@ -174,7 +283,7 @@ UA_Server * UA_Server_new(void) {
 
     /* continue adding reference types with normal "addnode" */
     UA_ReferenceTypeNode *hierarchicalreferences = UA_ReferenceTypeNode_new();
-    COPYNAMES(hierarchicalreferences, "Hierarchicalreferences");
+    copyNames((UA_Node*)hierarchicalreferences, "Hierarchicalreferences");
     hierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_HIERARCHICALREFERENCES;
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->symmetric  = UA_FALSE;
@@ -183,7 +292,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
-    COPYNAMES(nonhierarchicalreferences, "NonHierarchicalReferences");
+    copyNames((UA_Node*)nonhierarchicalreferences, "NonHierarchicalReferences");
     nonhierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_NONHIERARCHICALREFERENCES;
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
@@ -192,7 +301,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
-    COPYNAMES(haschild, "HasChild");
+    copyNames((UA_Node*)haschild, "HasChild");
     haschild->nodeId.identifier.numeric = UA_NS0ID_HASCHILD;
     haschild->isAbstract = UA_TRUE;
     haschild->symmetric  = UA_FALSE;
@@ -201,7 +310,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
-    COPYNAMES(organizes, "Organizes");
+    copyNames((UA_Node*)organizes, "Organizes");
     UA_LocalizedText_copycstring("OrganizedBy", &organizes->inverseName);
     organizes->nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     organizes->isAbstract = UA_FALSE;
@@ -211,7 +320,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
-    COPYNAMES(haseventsource, "HasEventSource");
+    copyNames((UA_Node*)haseventsource, "HasEventSource");
     UA_LocalizedText_copycstring("EventSourceOf", &haseventsource->inverseName);
     haseventsource->nodeId.identifier.numeric = UA_NS0ID_HASEVENTSOURCE;
     haseventsource->isAbstract = UA_FALSE;
@@ -221,7 +330,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
-    COPYNAMES(hasmodellingrule, "HasModellingRule");
+    copyNames((UA_Node*)hasmodellingrule, "HasModellingRule");
     UA_LocalizedText_copycstring("ModellingRuleOf", &hasmodellingrule->inverseName);
     hasmodellingrule->nodeId.identifier.numeric = UA_NS0ID_HASMODELLINGRULE;
     hasmodellingrule->isAbstract = UA_FALSE;
@@ -231,7 +340,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
-    COPYNAMES(hasencoding, "HasEncoding");
+    copyNames((UA_Node*)hasencoding, "HasEncoding");
     UA_LocalizedText_copycstring("EncodingOf", &hasencoding->inverseName);
     hasencoding->nodeId.identifier.numeric = UA_NS0ID_HASENCODING;
     hasencoding->isAbstract = UA_FALSE;
@@ -241,7 +350,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
-    COPYNAMES(hasdescription, "HasDescription");
+    copyNames((UA_Node*)hasdescription, "HasDescription");
     UA_LocalizedText_copycstring("DescriptionOf", &hasdescription->inverseName);
     hasdescription->nodeId.identifier.numeric = UA_NS0ID_HASDESCRIPTION;
     hasdescription->isAbstract = UA_FALSE;
@@ -251,7 +360,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
-    COPYNAMES(hastypedefinition, "HasTypeDefinition");
+    copyNames((UA_Node*)hastypedefinition, "HasTypeDefinition");
     UA_LocalizedText_copycstring("TypeDefinitionOf", &hastypedefinition->inverseName);
     hastypedefinition->nodeId.identifier.numeric = UA_NS0ID_HASTYPEDEFINITION;
     hastypedefinition->isAbstract = UA_FALSE;
@@ -261,7 +370,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
-    COPYNAMES(generatesevent, "GeneratesEvent");
+    copyNames((UA_Node*)generatesevent, "GeneratesEvent");
     UA_LocalizedText_copycstring("GeneratedBy", &generatesevent->inverseName);
     generatesevent->nodeId.identifier.numeric = UA_NS0ID_GENERATESEVENT;
     generatesevent->isAbstract = UA_FALSE;
@@ -271,7 +380,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
-    COPYNAMES(aggregates, "Aggregates");
+    copyNames((UA_Node*)aggregates, "Aggregates");
     // Todo: Is there an inverse name?
     aggregates->nodeId.identifier.numeric = UA_NS0ID_AGGREGATES;
     aggregates->isAbstract = UA_TRUE;
@@ -285,7 +394,7 @@ UA_Server * UA_Server_new(void) {
                  UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
-    COPYNAMES(hasproperty, "HasProperty");
+    copyNames((UA_Node*)hasproperty, "HasProperty");
     UA_LocalizedText_copycstring("PropertyOf", &hasproperty->inverseName);
     hasproperty->nodeId.identifier.numeric = UA_NS0ID_HASPROPERTY;
     hasproperty->isAbstract = UA_FALSE;
@@ -295,7 +404,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
-    COPYNAMES(hascomponent, "HasComponent");
+    copyNames((UA_Node*)hascomponent, "HasComponent");
     UA_LocalizedText_copycstring("ComponentOf", &hascomponent->inverseName);
     hascomponent->nodeId.identifier.numeric = UA_NS0ID_HASCOMPONENT;
     hascomponent->isAbstract = UA_FALSE;
@@ -305,7 +414,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
-    COPYNAMES(hasnotifier, "HasNotifier");
+    copyNames((UA_Node*)hasnotifier, "HasNotifier");
     UA_LocalizedText_copycstring("NotifierOf", &hasnotifier->inverseName);
     hasnotifier->nodeId.identifier.numeric = UA_NS0ID_HASNOTIFIER;
     hasnotifier->isAbstract = UA_FALSE;
@@ -315,7 +424,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
-    COPYNAMES(hasorderedcomponent, "HasOrderedComponent");
+    copyNames((UA_Node*)hasorderedcomponent, "HasOrderedComponent");
     UA_LocalizedText_copycstring("OrderedComponentOf", &hasorderedcomponent->inverseName);
     hasorderedcomponent->nodeId.identifier.numeric = UA_NS0ID_HASORDEREDCOMPONENT;
     hasorderedcomponent->isAbstract = UA_FALSE;
@@ -325,7 +434,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
-    COPYNAMES(hasmodelparent, "HasModelParent");
+    copyNames((UA_Node*)hasmodelparent, "HasModelParent");
     UA_LocalizedText_copycstring("ModelParentOf", &hasmodelparent->inverseName);
     hasmodelparent->nodeId.identifier.numeric = UA_NS0ID_HASMODELPARENT;
     hasmodelparent->isAbstract = UA_FALSE;
@@ -335,7 +444,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
-    COPYNAMES(fromstate, "FromState");
+    copyNames((UA_Node*)fromstate, "FromState");
     UA_LocalizedText_copycstring("ToTransition", &fromstate->inverseName);
     fromstate->nodeId.identifier.numeric = UA_NS0ID_FROMSTATE;
     fromstate->isAbstract = UA_FALSE;
@@ -345,7 +454,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
-    COPYNAMES(tostate, "ToState");
+    copyNames((UA_Node*)tostate, "ToState");
     UA_LocalizedText_copycstring("FromTransition", &tostate->inverseName);
     tostate->nodeId.identifier.numeric = UA_NS0ID_TOSTATE;
     tostate->isAbstract = UA_FALSE;
@@ -355,7 +464,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
-    COPYNAMES(hascause, "HasCause");
+    copyNames((UA_Node*)hascause, "HasCause");
     UA_LocalizedText_copycstring("MayBeCausedBy", &hascause->inverseName);
     hascause->nodeId.identifier.numeric = UA_NS0ID_HASCAUSE;
     hascause->isAbstract = UA_FALSE;
@@ -365,7 +474,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
     
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
-    COPYNAMES(haseffect, "HasEffect");
+    copyNames((UA_Node*)haseffect, "HasEffect");
     UA_LocalizedText_copycstring("MayBeEffectedBy", &haseffect->inverseName);
     haseffect->nodeId.identifier.numeric = UA_NS0ID_HASEFFECT;
     haseffect->isAbstract = UA_FALSE;
@@ -375,7 +484,7 @@ UA_Server * UA_Server_new(void) {
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
-    COPYNAMES(hashistoricalconfiguration, "HasHistoricalConfiguration");
+    copyNames((UA_Node*)hashistoricalconfiguration, "HasHistoricalConfiguration");
     UA_LocalizedText_copycstring("HistoricalConfigurationOf", &hashistoricalconfiguration->inverseName);
     hashistoricalconfiguration->nodeId.identifier.numeric = UA_NS0ID_HASHISTORICALCONFIGURATION;
     hashistoricalconfiguration->isAbstract = UA_FALSE;
@@ -384,113 +493,287 @@ UA_Server * UA_Server_new(void) {
                       &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_AGGREGATES),
                       &UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE));
 
-    /***********/
-    /* Objects */
-    /***********/
-    
+    /**********************/
+    /* Basic Object Types */
+    /**********************/
+
+    UA_ObjectTypeNode *baseObjectType = UA_ObjectTypeNode_new();
+    baseObjectType->nodeId.identifier.numeric = UA_NS0ID_BASEOBJECTTYPE;
+    copyNames((UA_Node*)baseObjectType, "BaseObjectType");
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)baseObjectType, UA_NULL);
+
+    UA_ObjectTypeNode *baseDataVarialbeType = UA_ObjectTypeNode_new();
+    baseDataVarialbeType->nodeId.identifier.numeric = UA_NS0ID_BASEDATAVARIABLETYPE;
+    copyNames((UA_Node*)baseDataVarialbeType, "BaseDataVariableType");
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)baseDataVarialbeType, UA_NULL);
+
     UA_ObjectTypeNode *folderType = UA_ObjectTypeNode_new();
     folderType->nodeId.identifier.numeric = UA_NS0ID_FOLDERTYPE;
-    COPYNAMES(folderType, "FolderType");
+    copyNames((UA_Node*)folderType, "FolderType");
     UA_NodeStore_insert(server->nodestore, (UA_Node*)folderType, UA_NULL);
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_STATIC(0, UA_NS0ID_HASSUBTYPE),
+ 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+
+    /*****************/
+    /* Basic Folders */
+    /*****************/
 
     UA_ObjectNode *root = UA_ObjectNode_new();
-    COPYNAMES(root, "Root");
+    copyNames((UA_Node*)root, "Root");
     root->nodeId.identifier.numeric = UA_NS0ID_ROOTFOLDER;
     UA_NodeStore_insert(server->nodestore, (UA_Node*)root, UA_NULL);
     ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_ROOTFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+ 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *objects = UA_ObjectNode_new();
-    COPYNAMES(objects, "Objects");
+    copyNames((UA_Node*)objects, "Objects");
     objects->nodeId.identifier.numeric = UA_NS0ID_OBJECTSFOLDER;
     UA_Server_addNode(server, (UA_Node*)objects,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+ 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
+ 		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
     ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+ 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *types = UA_ObjectNode_new();
-    COPYNAMES(types, "Types");
+    copyNames((UA_Node*)types, "Types");
     types->nodeId.identifier.numeric = UA_NS0ID_TYPESFOLDER;
     UA_Server_addNode(server, (UA_Node*)types,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+ 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
+ 		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
     ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_TYPESFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
-                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+ 		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
 
     UA_ObjectNode *views = UA_ObjectNode_new();
-    COPYNAMES(views, "Views");
+    copyNames((UA_Node*)views, "Views");
     views->nodeId.identifier.numeric = UA_NS0ID_VIEWSFOLDER;
     UA_Server_addNode(server, (UA_Node*)views,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+ 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_ROOTFOLDER),
+ 		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
     ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
                  UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
 
-    UA_ObjectNode *servernode = UA_ObjectNode_new();
-    COPYNAMES(servernode, "Server");
-    servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
-    UA_Server_addNode(server, (UA_Node*)servernode,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+    /**********************/
+    /* Further Data Types */
+    /**********************/
+
+    UA_ObjectNode *datatypes = UA_ObjectNode_new();
+    copyNames((UA_Node*)datatypes, "DataTypes");
+    datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
+    UA_Server_addNode(server, (UA_Node*)datatypes,
+                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_TYPESFOLDER),
                       &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
-    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_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.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
-    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]);
-    namespaceArray->valueRank = 1;
-    namespaceArray->minimumSamplingInterval = 1.0;
-    namespaceArray->historizing = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)namespaceArray,
-                      &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
-                      &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+    ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_DATATYPESFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
 
-    UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
-    status->startTime   = UA_DateTime_now();
-    status->currentTime = UA_DateTime_now();
-    status->state       = UA_SERVERSTATE_RUNNING;
-    UA_String_copycstring("open62541.org", &status->buildInfo.productUri);
-    UA_String_copycstring("open62541", &status->buildInfo.manufacturerName);
-    UA_String_copycstring("open62541", &status->buildInfo.productName);
-    UA_String_copycstring("0.0", &status->buildInfo.softwareVersion);
-    UA_String_copycstring("0.0", &status->buildInfo.buildNumber);
-    status->buildInfo.buildDate = UA_DateTime_now();
-    status->secondsTillShutdown = 99999999;
-    UA_LocalizedText_copycstring("because", &status->shutdownReason);
-    UA_VariableNode *serverstatus = UA_VariableNode_new();
-    COPYNAMES(serverstatus, "ServerStatus");
-    serverstatus->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS;
-    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, (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.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
-    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, (UA_Node*)state, UA_NULL);
-    return server;
+    addDataTypeNode(server, "BaseDataType", UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER);
+    addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "Number", UA_NS0ID_NUMBER, UA_NS0ID_BASEDATATYPE);
+    	addDataTypeNode(server, "Float", UA_NS0ID_FLOAT, UA_NS0ID_NUMBER);
+    	addDataTypeNode(server, "Double", UA_NS0ID_DOUBLE, UA_NS0ID_NUMBER);
+    	addDataTypeNode(server, "Integer", UA_NS0ID_INTEGER, UA_NS0ID_NUMBER);
+    		addDataTypeNode(server, "SByte", UA_NS0ID_SBYTE, UA_NS0ID_INTEGER);
+    		addDataTypeNode(server, "Int16", UA_NS0ID_INT16, UA_NS0ID_INTEGER);
+    		addDataTypeNode(server, "Int32", UA_NS0ID_INT32, UA_NS0ID_INTEGER);
+    		addDataTypeNode(server, "Int64", UA_NS0ID_INT64, UA_NS0ID_INTEGER);
+    		addDataTypeNode(server, "UInteger", UA_NS0ID_UINTEGER, UA_NS0ID_INTEGER);
+				addDataTypeNode(server, "Byte", UA_NS0ID_BYTE, UA_NS0ID_UINTEGER);
+				addDataTypeNode(server, "UInt16", UA_NS0ID_UINT16, UA_NS0ID_UINTEGER);
+				addDataTypeNode(server, "UInt32", UA_NS0ID_UINT32, UA_NS0ID_UINTEGER);
+				addDataTypeNode(server, "UInt64", UA_NS0ID_UINT64, UA_NS0ID_UINTEGER);
+    addDataTypeNode(server, "String", UA_NS0ID_STRING, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "DateTime", UA_NS0ID_DATETIME, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "Guid", UA_NS0ID_GUID, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "ByteString", UA_NS0ID_BYTESTRING, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "XmlElement", UA_NS0ID_XMLELEMENT, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "NodeId", UA_NS0ID_NODEID, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "ExpandedNodeId", UA_NS0ID_EXPANDEDNODEID, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "StatusCode", UA_NS0ID_STATUSCODE, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "QualifiedName", UA_NS0ID_QUALIFIEDNAME, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "LocalizedText", UA_NS0ID_LOCALIZEDTEXT, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "Structure", UA_NS0ID_STRUCTURE, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "DataValue", UA_NS0ID_DATAVALUE, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "DiagnosticInfo", UA_NS0ID_DIAGNOSTICINFO, UA_NS0ID_BASEDATATYPE);
+    addDataTypeNode(server, "Enumeration", UA_NS0ID_ENUMERATION, UA_NS0ID_BASEDATATYPE);
+    	addDataTypeNode(server, "ServerState", UA_NS0ID_SERVERSTATE, UA_NS0ID_ENUMERATION);
+
+   UA_ObjectNode *variabletypes = UA_ObjectNode_new();
+   copyNames((UA_Node*)variabletypes, "VariableTypes");
+   variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
+   UA_Server_addNode(server, (UA_Node*)variabletypes,
+                     &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_TYPESFOLDER),
+                     &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_VARIABLETYPESFOLDER), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+   addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE, UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
+   addVariableTypeNode_subtype(server, "PropertyType", UA_NS0ID_PROPERTYTYPE, UA_NS0ID_BASEVARIABLETYPE, UA_FALSE);
+
+   /*******************/
+   /* Further Objects */
+   /*******************/
+
+   UA_ObjectNode *servernode = UA_ObjectNode_new();
+   copyNames((UA_Node*)servernode, "Server");
+   servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
+   UA_Server_addNode(server, (UA_Node*)servernode,
+		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+   UA_VariableNode *namespaceArray = UA_VariableNode_new();
+   copyNames((UA_Node*)namespaceArray, "NamespaceArray");
+   namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
+   namespaceArray->variableType = UA_VARIABLENODETYPE_VARIANT;
+   namespaceArray->variable.variant.dataPtr = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
+   namespaceArray->variable.variant.arrayLength = 2;
+   namespaceArray->variable.variant.type = &UA_TYPES[UA_TYPES_STRING];
+   // Fixme: Insert the external namespaces
+   UA_String_copycstring("http://opcfoundation.org/UA/",
+		   &((UA_String *)(namespaceArray->variable.variant.dataPtr))[0]);
+   UA_String_copycstring(APPLICATION_URI,
+		   &((UA_String *)(namespaceArray->variable.variant.dataPtr))[1]);
+   namespaceArray->valueRank = 1;
+   namespaceArray->minimumSamplingInterval = 1.0;
+   namespaceArray->historizing = UA_FALSE;
+   UA_Server_addNode(server, (UA_Node*)namespaceArray,
+		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
+   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
+                UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_PROPERTYTYPE));
+
+   UA_VariableNode *serverArray = UA_VariableNode_new();
+   copyNames((UA_Node*)serverArray, "ServerArray");
+   serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
+   serverArray->variableType = UA_VARIABLENODETYPE_VARIANT;
+   serverArray->variable.variant.dataPtr = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+   serverArray->variable.variant.arrayLength = 1;
+   serverArray->variable.variant.type = &UA_TYPES[UA_TYPES_STRING];
+   UA_String_copycstring(APPLICATION_URI,
+ 		   &((UA_String *)(serverArray->variable.variant.dataPtr))[0]);
+   serverArray->valueRank = 1;
+   serverArray->minimumSamplingInterval = 1.0;
+   serverArray->historizing = UA_FALSE;
+   UA_Server_addNode(server, (UA_Node*)serverArray,
+ 		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
+ 		   &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
+   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERARRAY),
+                UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_PROPERTYTYPE));
+
+   UA_ObjectNode *servercapablities = UA_ObjectNode_new();
+   copyNames((UA_Node*)servercapablities, "ServerCapabilities");
+   servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
+   UA_Server_addNode(server, (UA_Node*)servercapablities,
+		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+
+   UA_VariableNode *localeIdArray = UA_VariableNode_new();
+   copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
+   localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
+   localeIdArray->variableType = UA_VARIABLENODETYPE_VARIANT;
+   localeIdArray->variable.variant.dataPtr = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
+   localeIdArray->variable.variant.arrayLength = 2;
+   localeIdArray->variable.variant.type = &UA_TYPES[UA_TYPES_STRING];
+   UA_String_copycstring("en",
+		   &((UA_String *)(localeIdArray->variable.variant.dataPtr))[0]);
+   UA_String_copycstring("de",
+		   &((UA_String *)(localeIdArray->variable.variant.dataPtr))[1]);
+   localeIdArray->valueRank = 1;
+   localeIdArray->minimumSamplingInterval = 1.0;
+   localeIdArray->historizing = UA_FALSE;
+   UA_Server_addNode(server, (UA_Node*)localeIdArray,
+		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_HASPROPERTY));
+   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_PROPERTYTYPE));
+
+   UA_VariableNode *serverstatus = UA_VariableNode_new();
+   copyNames((UA_Node*)serverstatus, "ServerStatus");
+   serverstatus->nodeId = UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
+   serverstatus->variableType = UA_VARIABLENODETYPE_DATASOURCE;
+   serverstatus->variable.dataSource = (UA_DataSource) {.handle = server, .read = readStatus,
+	   .release = releaseStatus, .write = UA_NULL};
+   UA_Server_addNode(server, (UA_Node*)serverstatus, &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+
+   UA_VariableNode *state = UA_VariableNode_new();
+   UA_ServerState *stateEnum = UA_ServerState_new();
+   *stateEnum = UA_SERVERSTATE_RUNNING;
+   copyNames((UA_Node*)state, "State");
+   state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
+   state->variableType = UA_VARIABLENODETYPE_VARIANT;
+   state->variable.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
+   state->variable.variant.arrayLength = -1;
+   state->variable.variant.dataPtr = stateEnum; // points into the other object.
+   UA_NodeStore_insert(server->nodestore, (UA_Node*)state, UA_NULL);
+   ADDREFERENCE(UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT),
+		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
+
+   UA_VariableNode *currenttime = UA_VariableNode_new();
+   copyNames((UA_Node*)currenttime, "CurrentTime");
+   currenttime->nodeId = UA_NODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+   currenttime->variableType = UA_VARIABLENODETYPE_DATASOURCE;
+   currenttime->variable.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
+	   .release = releaseCurrentTime, .write = UA_NULL};
+   UA_Server_addNode(server, (UA_Node*)currenttime, &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_HASCOMPONENT));
+
+#ifdef DEMO_NODESET
+   /**************/
+   /* Demo Nodes */
+   /**************/
+
+#define DEMOID 990
+   UA_ObjectNode *demo = UA_ObjectNode_new();
+   copyNames((UA_Node*)demo, "Demo");
+   demo->nodeId = UA_NODEID_STATIC(1, DEMOID);
+   UA_Server_addNode(server, (UA_Node*)demo,
+		   &UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_OBJECTSFOLDER),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_STATIC(1, DEMOID), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+
+#define SCALARID 991
+   UA_ObjectNode *scalar = UA_ObjectNode_new();
+   copyNames((UA_Node*)scalar, "Scalar");
+   scalar->nodeId = UA_NODEID_STATIC(1, SCALARID);
+   UA_Server_addNode(server, (UA_Node*)scalar,
+		   &UA_EXPANDEDNODEID_STATIC(1, DEMOID),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_STATIC(1, SCALARID), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+
+#define ARRAYID 992
+   UA_ObjectNode *array = UA_ObjectNode_new();
+   copyNames((UA_Node*)array, "Arrays");
+   array->nodeId = UA_NODEID_STATIC(1, ARRAYID);
+   UA_Server_addNode(server, (UA_Node*)array,
+		   &UA_EXPANDEDNODEID_STATIC(1, DEMOID),
+		   &UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_STATIC(1, ARRAYID), UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+		   UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_FOLDERTYPE));
+
+   UA_UInt32 id = 1000; //running id in namespace 1
+   for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
+       if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
+           continue;
+	   //add a scalar node for every built-in type
+	    void *value = UA_new(&UA_TYPES[type]);
+	    UA_Variant *variant = UA_Variant_new();
+	    UA_Variant_setScalar(variant, value, &UA_TYPES[type]);
+	    UA_QualifiedName myIntegerName;
+	    char name[15];
+	    sprintf(name, "%02d", type);
+	    UA_QUALIFIEDNAME_ASSIGN(myIntegerName, name);
+	    UA_Server_addVariableNode(server, variant, myIntegerName, UA_NODEID_STATIC(1, ++id),
+	                              UA_NODEID_STATIC(1, SCALARID), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+
+        //add an array node for every built-in type
+        UA_Variant *arrayvar = UA_Variant_new();
+        UA_Variant_setArray(arrayvar, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
+        UA_Server_addVariableNode(server, arrayvar, myIntegerName, UA_NODEID_STATIC(1, ++id),
+                                  UA_NODEID_STATIC(1, ARRAYID), UA_NODEID_STATIC(0, UA_NS0ID_ORGANIZES));
+   }
+#endif
+
+   return server;
 }

+ 60 - 30
src/server/ua_server_addressspace.c

@@ -1,34 +1,58 @@
 #include "ua_server.h"
 #include "ua_server_internal.h"
 
-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_StatusCode
+UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_QualifiedName browseName, 
+                          UA_NodeId nodeId, 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);
+    node->variable.variant = *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);
+    UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
+    UA_AddNodesResult res =
+        UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
+    ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_STATIC(0, value->type->typeId.identifier.numeric));
     if(res.statusCode != UA_STATUSCODE_GOOD) {
-        UA_Variant_init(&node->value);
+        UA_Variant_init(&node->variable.variant);
         UA_VariableNode_delete(node);
-    } else {
+    } else
         UA_free(value);
-    }
+    return res.statusCode;
+}
+
+UA_StatusCode
+UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
+                                    const UA_QualifiedName browseName, UA_NodeId nodeId,
+                                    const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId)
+{
+    UA_VariableNode *node = UA_VariableNode_new();
+    node->variableType = UA_VARIABLENODETYPE_DATASOURCE;
+    node->variable.dataSource = dataSource;
+    UA_NodeId_copy(&nodeId, &node->nodeId);
+    UA_QualifiedName_copy(&browseName, &node->browseName);
+    UA_String_copy(&browseName.name, &node->displayName.text);
+    UA_ExpandedNodeId parentId; // dummy exapndednodeid
+    UA_ExpandedNodeId_init(&parentId);
+    UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
+    UA_AddNodesResult res =
+        UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
+    ADDREFERENCE(res.addedNodeId, UA_NODEID_STATIC(0, UA_NS0ID_HASTYPEDEFINITION),
+                 UA_EXPANDEDNODEID_STATIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+    if(res.statusCode != UA_STATUSCODE_GOOD)
+        UA_VariableNode_delete(node);
     return res.statusCode;
 }
 
 /* Adds a one-way reference to the local nodestore */
-static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session *session,
-                                                   const UA_AddReferencesItem *item) {
-    // use the servers nodestore
+static UA_StatusCode
+addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item)
+{
     const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
-    // todo differentiate between error codes
     if(!node)
         return UA_STATUSCODE_BADINTERNALERROR;
 
@@ -76,7 +100,7 @@ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session
         deleteNode = (void (*)(UA_Node*))UA_ViewNode_delete;
         break;
     default:
-        UA_assert(UA_FALSE);
+        return UA_STATUSCODE_BADINTERNALERROR;
     }
 
     UA_Int32 count = node->referencesSize;
@@ -113,21 +137,23 @@ static UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session
     if(retval != UA_STATUSCODE_BADINTERNALERROR)
         return retval;
     
-    // error presumably because the node was replaced and an old version was updated
-    // just try again
+    // error presumably because the node was replaced and an old version was updated just try again
     deleteNode(newNode);
     return addOneWayReferenceWithSession(server, session, item);
 }
 
-UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item) {
+/* userland version of addReferenceWithSession */
+UA_StatusCode
+UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item)
+{
     return UA_Server_addReferenceWithSession(server, &adminSession, item);
 }
 
-UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
-                                                const UA_AddReferencesItem *item) {
-    // todo: we don't support references to other servers (expandednodeid) for now
+UA_StatusCode
+UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item)
+{
     if(item->targetServerUri.length > 0)
-        return UA_STATUSCODE_BADNOTIMPLEMENTED;
+        return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
     
     // Is this for an external nodestore?
     UA_ExternalNodeStore *ensFirst = UA_NULL;
@@ -161,14 +187,18 @@ UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *s
     return retval;
 } 
 
-UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId *parentNodeId,
-                                    const UA_NodeId *referenceTypeId) {
+/* userland version of addNodeWithSession */
+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, 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);
 

+ 208 - 198
src/server/ua_server_binary.c

@@ -1,5 +1,4 @@
-#include <stdio.h>
-
+#include "ua_util.h"
 #include "ua_server_internal.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_transport_generated.h"
@@ -7,7 +6,6 @@
 #include "ua_statuscodes.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 */
@@ -16,7 +14,7 @@
 static UA_StatusCode UA_ByteStringArray_deleteMembers(UA_ByteStringArray *stringarray) {
     if(!stringarray)
         return UA_STATUSCODE_BADINTERNALERROR;
-    for(UA_UInt32 i = 0;i < stringarray->stringsSize;i++)
+    for(UA_UInt32 i = 0; i < stringarray->stringsSize; i++)
         UA_String_deleteMembers(&stringarray->strings[i]);
     return UA_STATUSCODE_GOOD;
 }
@@ -28,29 +26,31 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
         return;
     }
 
-    connection->remoteConf.maxChunkCount   = helloMessage.maxChunkCount;
-    connection->remoteConf.maxMessageSize  = helloMessage.maxMessageSize;
+    connection->remoteConf.maxChunkCount = helloMessage.maxChunkCount;
+    connection->remoteConf.maxMessageSize = helloMessage.maxMessageSize;
     connection->remoteConf.protocolVersion = helloMessage.protocolVersion;
-    connection->remoteConf.recvBufferSize  = helloMessage.receiveBufferSize;
-    connection->remoteConf.sendBufferSize  = helloMessage.sendBufferSize;
-    connection->state                      = UA_CONNECTION_ESTABLISHED;
+    connection->remoteConf.recvBufferSize = helloMessage.receiveBufferSize;
+    connection->remoteConf.sendBufferSize = helloMessage.sendBufferSize;
+    connection->state = UA_CONNECTION_ESTABLISHED;
 
     // build acknowledge response
     UA_TcpAcknowledgeMessage ackMessage;
-    ackMessage.protocolVersion   = connection->localConf.protocolVersion;
+    ackMessage.protocolVersion = connection->localConf.protocolVersion;
     ackMessage.receiveBufferSize = connection->localConf.recvBufferSize;
-    ackMessage.sendBufferSize    = connection->localConf.sendBufferSize;
-    ackMessage.maxMessageSize    = connection->localConf.maxMessageSize;
-    ackMessage.maxChunkCount     = connection->localConf.maxChunkCount;
+    ackMessage.sendBufferSize = connection->localConf.sendBufferSize;
+    ackMessage.maxMessageSize = connection->localConf.maxMessageSize;
+    ackMessage.maxChunkCount = connection->localConf.maxChunkCount;
 
     UA_TcpMessageHeader ackHeader;
     ackHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_ACKF;
     ackHeader.messageSize = UA_TcpAcknowledgeMessage_calcSizeBinary(&ackMessage) +
-                            UA_TcpMessageHeader_calcSizeBinary(&ackHeader);
+        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_ByteString ack_msg = (UA_ByteString){
+        .length = ackHeader.messageSize,
+            .data = UA_alloca(ackHeader.messageSize)
+    };
     size_t tmpPos = 0;
     UA_TcpMessageHeader_encodeBinary(&ackHeader, &ack_msg, &tmpPos);
     UA_TcpAcknowledgeMessage_encodeBinary(&ackMessage, &ack_msg, &tmpPos);
@@ -61,7 +61,7 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
 }
 
 static void processOPN(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg,
-                        size_t *pos) {
+                       size_t *pos) {
     if(connection->state != UA_CONNECTION_ESTABLISHED) {
         connection->close(connection);
         return;
@@ -106,8 +106,10 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
         + UA_NodeId_calcSizeBinary(&responseType)
         + UA_OpenSecureChannelResponse_calcSizeBinary(&p);
 
-    UA_ByteString resp_msg = (UA_ByteString){ .length = respHeader.messageHeader.messageSize,
-                                              .data = UA_alloca(respHeader.messageHeader.messageSize) };
+    UA_ByteString resp_msg = (UA_ByteString){
+        .length = respHeader.messageHeader.messageSize,
+            .data = UA_alloca(respHeader.messageHeader.messageSize)
+    };
 
     size_t tmpPos = 0;
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
@@ -123,10 +125,10 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
 }
 
 static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
-    r->requestHandle   = p->requestHandle;
-    r->serviceResult   = UA_STATUSCODE_GOOD;
+    r->requestHandle = p->requestHandle;
+    r->serviceResult = UA_STATUSCODE_GOOD;
     r->stringTableSize = 0;
-    r->timestamp       = UA_DateTime_now();
+    r->timestamp = UA_DateTime_now();
 }
 
 // if the message is small enough, we allocate it on the stack and save a malloc
@@ -136,7 +138,7 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
             messageOnStack = UA_TRUE;                                   \
             *MESSAGE = (UA_ByteString){.length = messageSize,           \
                                        .data = UA_alloca(messageSize)}; \
-        } else                                                          \
+                        } else                                          \
             UA_ByteString_newMembers(MESSAGE, messageSize);             \
     } while(0)
 
@@ -158,40 +160,42 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
 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);
+    UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
+    if(retval != UA_STATUSCODE_GOOD)
+        return;
 
     UA_SecureChannel *clientChannel = connection->channel;
-    UA_Session *clientSession = UA_NULL;
+    UA_SecureChannel anonymousChannel;
+    if(!clientChannel) {
+        UA_SecureChannel_init(&anonymousChannel);
+        clientChannel = &anonymousChannel;
+    }
+
+    UA_Session *clientSession = clientChannel->session;
 #ifdef EXTENSION_STATELESS
-    UA_SecureChannel dummyChannel;
-    UA_SecureChannel_init(&dummyChannel);
-    if(secureChannelId == 0 || !clientChannel){
-        clientChannel = &dummyChannel;
+    if(secureChannelId == 0)
         clientSession = &anonymousSession;
-    } 
 #endif
-    if(!clientSession && clientChannel)
-        clientSession = clientChannel->session;
 
     // 2) Read the security header
     UA_UInt32 tokenId;
-    UA_UInt32_decodeBinary(msg, pos, &tokenId);
     UA_SequenceHeader sequenceHeader;
-    if(UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader))
+    retval = UA_UInt32_decodeBinary(msg, pos, &tokenId);
+    retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader);
+    if(retval != UA_STATUSCODE_GOOD)
         return;
 
-    clientChannel->sequenceNumber = sequenceHeader.sequenceNumber;
-    clientChannel->requestId = sequenceHeader.requestId;
-    // todo
     //UA_SecureChannel_checkSequenceNumber(channel,sequenceHeader.sequenceNumber);
     //UA_SecureChannel_checkRequestId(channel,sequenceHeader.requestId);
+    clientChannel->sequenceNumber = sequenceHeader.sequenceNumber;
+    clientChannel->requestId = sequenceHeader.requestId;
 
     // 3) Read the nodeid of the request
     UA_NodeId 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
+        // That must not happen. The requestType does not have to be deleted at the end.
         UA_NodeId_deleteMembers(&requestType);
         return;
     }
@@ -199,155 +203,158 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     // 4) process the request
     UA_ByteString responseBufs[2]; // 0->header, 1->response payload
     UA_UInt32 responseType;
-    UA_ByteString *header     = &responseBufs[0];
-    UA_ByteString *message    = &responseBufs[1];
+    UA_ByteString *header = &responseBufs[0];
+    UA_ByteString *message = &responseBufs[1];
     UA_Boolean messageOnStack = UA_FALSE;
-    size_t 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_NS0ID_READREQUEST:
-    		INVOKE_SERVICE(Read);
-    		break;
-
-    	case UA_NS0ID_WRITEREQUEST:
-    		INVOKE_SERVICE(Write);
-    		break;
-
-    	case UA_NS0ID_BROWSEREQUEST:
-    		INVOKE_SERVICE(Browse);
-    		break;
-
-    	default: {
-    		printf("SL_processMessage - stateless call for an unknown or not allowed request, namespace=%d, request=%d\n",
-    				requestType.namespaceIndex, requestType.identifier.numeric);
-    		UA_RequestHeader  p;
-    		UA_ResponseHeader r;
-    		if(UA_RequestHeader_decodeBinary(msg, pos, &p))
-                return;
-    		UA_ResponseHeader_init(&r);
-    		init_response_header(&p, &r);
-    		r.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
-    		ALLOC_MESSAGE(message, UA_ResponseHeader_calcSizeBinary(&r));
-    		UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
-    		UA_RequestHeader_deleteMembers(&p);
-    		UA_ResponseHeader_deleteMembers(&r);
-    		responseType = UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY; }
-            break;
-    	}
-    } else {
+    switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
+    case UA_NS0ID_READREQUEST:
+    case UA_NS0ID_WRITEREQUEST:
+    case UA_NS0ID_BROWSEREQUEST:
+        break;
+    default:
+        if(clientSession != &anonymousSession)
+            retval = UA_STATUSCODE_BADNOTCONNECTED;
+    }
 #endif
-    	//non-stateless service calls
-    	//subtract UA_ENCODINGOFFSET_BINARY for binary encoding
-    	switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY) {
-    	case UA_NS0ID_GETENDPOINTSREQUEST: {
-    		UA_GetEndpointsRequest  p;
-    		UA_GetEndpointsResponse r;
-    		if(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p))
-                return;
-    		UA_GetEndpointsResponse_init(&r);
-    		init_response_header(&p.requestHeader, &r.responseHeader);
-    		Service_GetEndpoints(server, &p, &r);
-    		ALLOC_MESSAGE(message, UA_GetEndpointsResponse_calcSizeBinary(&r));
-    		UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
-    		UA_GetEndpointsRequest_deleteMembers(&p);
-    		UA_GetEndpointsResponse_deleteMembers(&r);
-    		responseType = requestType.identifier.numeric + 3;
-    		break;
-    	}
-
-    	case UA_NS0ID_CREATESESSIONREQUEST: {
-    		UA_CreateSessionRequest  p;
-    		UA_CreateSessionResponse r;
-            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);
-    		ALLOC_MESSAGE(message, UA_CreateSessionResponse_calcSizeBinary(&r));
-    		UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
-    		UA_CreateSessionRequest_deleteMembers(&p);
-    		UA_CreateSessionResponse_deleteMembers(&r);
-    		responseType = requestType.identifier.numeric + 3;
-    		break;
-    	}
-
-    	case UA_NS0ID_ACTIVATESESSIONREQUEST: {
-    		UA_ActivateSessionRequest  p;
-    		UA_ActivateSessionResponse r;
-    		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);
-    		ALLOC_MESSAGE(message, UA_ActivateSessionResponse_calcSizeBinary(&r));
-    		UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
-    		UA_ActivateSessionRequest_deleteMembers(&p);
-    		UA_ActivateSessionResponse_deleteMembers(&r);
-    		responseType = requestType.identifier.numeric + 3;
-    		break;
-    	}
-
-    	case UA_NS0ID_CLOSESESSIONREQUEST: {
-    		UA_CloseSessionRequest  p;
-    		UA_CloseSessionResponse r;
-    		if(UA_CloseSessionRequest_decodeBinary(msg, pos, &p))
-                return;
-    		UA_CloseSessionResponse_init(&r);
-    		init_response_header(&p.requestHeader, &r.responseHeader);
-    		Service_CloseSession(server, &p, &r);
-    		ALLOC_MESSAGE(message, UA_CloseSessionResponse_calcSizeBinary(&r));
-    		UA_CloseSessionResponse_encodeBinary(&r, message, &sendOffset);
-    		UA_CloseSessionRequest_deleteMembers(&p);
-    		UA_CloseSessionResponse_deleteMembers(&r);
-    		responseType = requestType.identifier.numeric + 3;
-    		break;
-    	}
-
-    	case UA_NS0ID_READREQUEST:
-    		INVOKE_SERVICE(Read);
-    		break;
-
-    	case UA_NS0ID_WRITEREQUEST:
-    		INVOKE_SERVICE(Write);
-    		break;
-
-    	case UA_NS0ID_BROWSEREQUEST:
-    		INVOKE_SERVICE(Browse);
-    		break;
-
-    	case UA_NS0ID_ADDREFERENCESREQUEST:
-    		INVOKE_SERVICE(AddReferences);
-    		break;
-
-    	case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
-    		INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
-    		break;
-
-    	default: {
-    		printf("SL_processMessage - unknown request, namespace=%d, request=%d\n",
-    				requestType.namespaceIndex, requestType.identifier.numeric);
-    		UA_RequestHeader  p;
-    		UA_ResponseHeader r;
-    		if(UA_RequestHeader_decodeBinary(msg, pos, &p))
-                return;
-    		UA_ResponseHeader_init(&r);
-    		init_response_header(&p, &r);
-    		r.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
-    		ALLOC_MESSAGE(message, UA_ResponseHeader_calcSizeBinary(&r));
-    		UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
-    		UA_RequestHeader_deleteMembers(&p);
-    		UA_ResponseHeader_deleteMembers(&r);
-    		responseType = UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY;
-    	}
-    	break;
-    	}
-#ifdef EXTENSION_STATELESS
+
+    //subtract UA_ENCODINGOFFSET_BINARY for binary encoding, if retval is set, this forces the default path
+    switch(requestType.identifier.numeric - UA_ENCODINGOFFSET_BINARY + retval) {
+    case UA_NS0ID_GETENDPOINTSREQUEST: {
+        UA_GetEndpointsRequest  p;
+        UA_GetEndpointsResponse r;
+        if(UA_GetEndpointsRequest_decodeBinary(msg, pos, &p))
+            return;
+        UA_GetEndpointsResponse_init(&r);
+        init_response_header(&p.requestHeader, &r.responseHeader);
+        Service_GetEndpoints(server, &p, &r);
+        ALLOC_MESSAGE(message, UA_GetEndpointsResponse_calcSizeBinary(&r));
+        UA_GetEndpointsResponse_encodeBinary(&r, message, &sendOffset);
+        UA_GetEndpointsRequest_deleteMembers(&p);
+        UA_GetEndpointsResponse_deleteMembers(&r);
+        responseType = requestType.identifier.numeric + 3;
+        break;
+    }
+
+    case UA_NS0ID_FINDSERVERSREQUEST: {
+        UA_FindServersRequest  p;
+        UA_FindServersResponse r;
+        if(UA_FindServersRequest_decodeBinary(msg, pos, &p))
+            return;
+        UA_FindServersResponse_init(&r);
+        init_response_header(&p.requestHeader, &r.responseHeader);
+        Service_FindServers(server, &p, &r);
+        ALLOC_MESSAGE(message, UA_FindServersResponse_calcSizeBinary(&r));
+        UA_FindServersResponse_encodeBinary(&r, message, &sendOffset);
+        UA_FindServersRequest_deleteMembers(&p);
+        UA_FindServersResponse_deleteMembers(&r);
+        responseType = requestType.identifier.numeric + 3;
+        break;
+    }
+
+    case UA_NS0ID_CREATESESSIONREQUEST: {
+        UA_CreateSessionRequest  p;
+        UA_CreateSessionResponse r;
+        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);
+        ALLOC_MESSAGE(message, UA_CreateSessionResponse_calcSizeBinary(&r));
+        UA_CreateSessionResponse_encodeBinary(&r, message, &sendOffset);
+        UA_CreateSessionRequest_deleteMembers(&p);
+        UA_CreateSessionResponse_deleteMembers(&r);
+        responseType = requestType.identifier.numeric + 3;
+        break;
     }
+
+    case UA_NS0ID_ACTIVATESESSIONREQUEST: {
+        UA_ActivateSessionRequest  p;
+        UA_ActivateSessionResponse r;
+        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);
+        ALLOC_MESSAGE(message, UA_ActivateSessionResponse_calcSizeBinary(&r));
+        UA_ActivateSessionResponse_encodeBinary(&r, message, &sendOffset);
+        UA_ActivateSessionRequest_deleteMembers(&p);
+        UA_ActivateSessionResponse_deleteMembers(&r);
+        responseType = requestType.identifier.numeric + 3;
+        break;
+    }
+
+    case UA_NS0ID_CLOSESESSIONREQUEST: {
+        UA_CloseSessionRequest  p;
+        UA_CloseSessionResponse r;
+        if(UA_CloseSessionRequest_decodeBinary(msg, pos, &p))
+            return;
+        UA_CloseSessionResponse_init(&r);
+        init_response_header(&p.requestHeader, &r.responseHeader);
+        Service_CloseSession(server, &p, &r);
+        ALLOC_MESSAGE(message, UA_CloseSessionResponse_calcSizeBinary(&r));
+        UA_CloseSessionResponse_encodeBinary(&r, message, &sendOffset);
+        UA_CloseSessionRequest_deleteMembers(&p);
+        UA_CloseSessionResponse_deleteMembers(&r);
+        responseType = requestType.identifier.numeric + 3;
+        break;
+    }
+
+    case UA_NS0ID_READREQUEST:
+        INVOKE_SERVICE(Read);
+        break;
+
+    case UA_NS0ID_WRITEREQUEST:
+        INVOKE_SERVICE(Write);
+        break;
+
+    case UA_NS0ID_BROWSEREQUEST:
+        INVOKE_SERVICE(Browse);
+        break;
+
+    case UA_NS0ID_ADDREFERENCESREQUEST:
+        INVOKE_SERVICE(AddReferences);
+        break;
+
+    case UA_NS0ID_REGISTERNODESREQUEST:
+        INVOKE_SERVICE(RegisterNodes);
+        break;
+
+    case UA_NS0ID_UNREGISTERNODESREQUEST:
+        INVOKE_SERVICE(UnregisterNodes);
+        break;
+
+    case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
+        INVOKE_SERVICE(TranslateBrowsePathsToNodeIds);
+        break;
+
+    default: {
+        char logmsg[60];
+        sprintf(logmsg, "Unknown request: NodeId(ns=%d, i=%d)",
+                requestType.namespaceIndex, requestType.identifier.numeric);
+        UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, logmsg);
+
+        UA_RequestHeader  p;
+        UA_ResponseHeader r;
+        if(UA_RequestHeader_decodeBinary(msg, pos, &p))
+            return;
+        UA_ResponseHeader_init(&r);
+        init_response_header(&p, &r);
+        r.serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
+#ifdef EXTENSION_STATELESS
+        if(retval != UA_STATUSCODE_GOOD)
+            r.serviceResult = retval;
 #endif
+        ALLOC_MESSAGE(message, UA_ResponseHeader_calcSizeBinary(&r));
+        UA_ResponseHeader_encodeBinary(&r, message, &sendOffset);
+        UA_RequestHeader_deleteMembers(&p);
+        UA_ResponseHeader_deleteMembers(&r);
+        responseType = UA_NS0ID_RESPONSEHEADER + UA_ENCODINGOFFSET_BINARY;
+        break;
+    }
+    }
 
     // 5) Build the header
     UA_SecureConversationMessageHeader respHeader;
@@ -360,10 +367,10 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
 
     UA_SequenceHeader seqHeader;
     seqHeader.sequenceNumber = clientChannel->sequenceNumber;
-    seqHeader.requestId      = clientChannel->requestId;
+    seqHeader.requestId = clientChannel->requestId;
 
     UA_NodeId response_nodeid = { .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
-                                  .identifier.numeric = responseType };
+        .identifier.numeric = responseType };
 
     UA_UInt32 headerSize =
         UA_SecureConversationMessageHeader_calcSizeBinary(&respHeader)
@@ -384,7 +391,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
 
     // 6) Send it over the wire.
     UA_ByteStringArray responseBufArray;
-    responseBufArray.strings     = responseBufs;
+    responseBufArray.strings = responseBufs;
     responseBufArray.stringsSize = 2;
     connection->write(connection, responseBufArray);
 
@@ -393,14 +400,15 @@ 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,
-                         size_t *pos) {
+                       size_t *pos) {
     UA_UInt32 secureChannelId;
-    UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
+    UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
 
-    if(!connection->channel || connection->channel->securityToken.channelId != secureChannelId)
+    if(retval != UA_STATUSCODE_GOOD || !connection->channel ||
+       connection->channel->securityToken.channelId != secureChannelId)
         return;
 
-	Service_CloseSecureChannel(server, secureChannelId);
+    Service_CloseSecureChannel(server, secureChannelId);
 }
 
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg) {
@@ -408,7 +416,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
     UA_TcpMessageHeader tcpMessageHeader;
     do {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader) != UA_STATUSCODE_GOOD) {
-            printf("ERROR: decoding of header failed \n");
+            UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Decoding of message header failed");
             connection->close(connection);
             break;
         }
@@ -424,14 +432,15 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             break;
 
         case UA_MESSAGETYPEANDFINAL_MSGF & 0xffffff:
-#ifndef EXTENSION_STATELESS
-            if(connection->state == UA_CONNECTION_ESTABLISHED && connection->channel != UA_NULL)
-                processMSG(connection, server, msg, &pos);
-            else
-                connection->close(connection);
-#else
-                processMSG(connection, server, msg, &pos);
+#ifdef EXTENSION_STATELESS
+            processMSG(connection, server, msg, &pos);
+            break;
 #endif
+                if(connection->state != UA_CONNECTION_ESTABLISHED) {
+                connection->close(connection);
+                break;
+                }
+            processMSG(connection, server, msg, &pos);
             break;
 
         case UA_MESSAGETYPEANDFINAL_CLOF & 0xffffff:
@@ -439,10 +448,11 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             connection->close(connection);
             return;
         }
-        
+
         UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
         if(pos != targetpos) {
-            printf("The message size was not as announced or the message could not be processed, skipping to the end of the message.\n");
+            UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION,
+                        "The message was not entirely processed, skipping to the end");
             pos = targetpos;
         }
     } while(msg->length > (UA_Int32)pos);

+ 15 - 10
src/server/ua_server_internal.h

@@ -1,15 +1,7 @@
 #ifndef UA_SERVER_INTERNAL_H_
 #define UA_SERVER_INTERNAL_H_
 
-#include "ua_config.h"
-
-#ifdef UA_MULTITHREADING
-#define _LGPL_SOURCE
-#include <urcu.h>
-#include <urcu/wfcqueue.h>
-#endif
-
-#include "../deps/queue.h"
+#include "ua_util.h"
 #include "ua_server.h"
 #include "ua_session_manager.h"
 #include "ua_securechannel_manager.h"
@@ -62,6 +54,9 @@ struct UA_Server {
 #endif
 
     LIST_HEAD(UA_TimedWorkList, UA_TimedWork) timedWork;
+
+    UA_DateTime startTime;
+    UA_DateTime buildDate;
 };
 
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg);
@@ -103,4 +98,14 @@ typedef enum {
     UA_ATTRIBUTEID_USEREXECUTABLE          = 22
 } UA_AttributeId;
 
-#endif /* UA_SERVER_INTERNAL_H_ */
+#define ADDREFERENCE(NODEID, REFTYPE_NODEID, TARGET_EXPNODEID) do {     \
+        UA_AddReferencesItem item;                                      \
+        UA_AddReferencesItem_init(&item);                               \
+        item.sourceNodeId = NODEID;                                     \
+        item.referenceTypeId = REFTYPE_NODEID;                          \
+        item.isForward = UA_TRUE;                                       \
+        item.targetNodeId = TARGET_EXPNODEID;                           \
+        UA_Server_addReference(server, &item);                          \
+    } while(0)
+
+#endif /* UA_SERVER_INTERNAL_H_ */

+ 90 - 24
src/server/ua_server_worker.c

@@ -1,9 +1,4 @@
-#include <stdio.h>
-#define __USE_POSIX
-#define _XOPEN_SOURCE 500
-#define __USE_POSIX199309
-#include <sys/time.h>
-#include <time.h>
+#include "ua_util.h"
 #include "ua_server_internal.h"
 
 /**
@@ -168,8 +163,14 @@ static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA
     if(tw) {
         // append to matching entry
         tw->workSize++;
-        tw->work = UA_realloc(tw->work, sizeof(UA_WorkItem)*tw->workSize);
-        tw->workIds = UA_realloc(tw->workIds, sizeof(UA_Guid)*tw->workSize);
+        UA_WorkItem *biggerWorkArray = UA_realloc(tw->work, sizeof(UA_WorkItem)*tw->workSize);
+        if(!biggerWorkArray)
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        tw->work = biggerWorkArray;
+        UA_Guid *biggerWorkIds = UA_realloc(tw->workIds, sizeof(UA_Guid)*tw->workSize);
+        if(!biggerWorkIds)
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        tw->workIds = biggerWorkIds;
         tw->work[tw->workSize-1] = *item;
         tw->workIds[tw->workSize-1] = UA_Guid_random(&server->random_seed);
         if(resultWorkGuid)
@@ -180,13 +181,20 @@ static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA
     // create a new entry
     if(!(tw = UA_malloc(sizeof(UA_TimedWork))))
         return UA_STATUSCODE_BADOUTOFMEMORY;
+    if(!(tw->work = UA_malloc(sizeof(UA_WorkItem)))) {
+        UA_free(tw);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+    if(!(tw->workIds = UA_malloc(sizeof(UA_Guid)))) {
+        UA_free(tw->work);
+        UA_free(tw);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
 
     tw->workSize = 1;
     tw->time = firstTime;
     tw->repetitionInterval = repetitionInterval;
-    tw->work = UA_malloc(sizeof(UA_WorkItem));
     tw->work[0] = *item;
-    tw->workIds = UA_malloc(sizeof(UA_Guid));
     tw->workIds[0] = UA_Guid_random(&server->random_seed);
     if(lastTw)
         LIST_INSERT_AFTER(lastTw, tw, pointers);
@@ -248,7 +256,10 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
             UA_free(tw);
         }
 #else
-        processWork(server,tw->work, tw->workSize); // does not free the work
+        // 1) Process the work since it is past its due date
+        processWork(server, tw->work, tw->workSize); // does not free the work
+
+        // 2) If the work is repeated, add it back into the list. Otherwise remove it.
         if(tw->repetitionInterval > 0) {
             tw->time += tw->repetitionInterval;
             UA_TimedWork *prevTw = tw;
@@ -271,22 +282,27 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
 #endif
     }
 
-    tw = LIST_FIRST(&server->timedWork);
+    // check if the next timed work is sooner than the usual timeout
+    UA_TimedWork *first = LIST_FIRST(&server->timedWork);
     UA_UInt16 timeout = MAXTIMEOUT;
-    if(tw){
-        timeout = (tw->time - current)/10;
-        if(timeout>MAXTIMEOUT)timeout = MAXTIMEOUT;
+    if(first) {
+        timeout = (first->time - current)/10;
+        if(timeout > MAXTIMEOUT)
+            timeout = MAXTIMEOUT;
     }
     return timeout;
 }
 
 void UA_Server_deleteTimedWork(UA_Server *server) {
-    UA_TimedWork *tw;
-    while((tw = LIST_FIRST(&server->timedWork))) {
-        LIST_REMOVE(tw, pointers);
-        UA_free(tw->work);
-        UA_free(tw->workIds);
-        UA_free(tw);
+    UA_TimedWork *current;
+    UA_TimedWork *next = LIST_FIRST(&server->timedWork);
+    while(next) {
+        current = next;
+        next = LIST_NEXT(current, pointers);
+        LIST_REMOVE(current, pointers);
+        UA_free(current->work);
+        UA_free(current->workIds);
+        UA_free(current);
     }
 }
 
@@ -424,11 +440,61 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
     UA_Server_addRepeatedWorkItem(server, &processDelayed, 10000000, UA_NULL);
 #endif
 
-    // 2) Start the networklayers
+    // 2a) Start the networklayers
     for(UA_Int32 i=0;i<server->nlsSize;i++)
-        server->nls[i].start(server->nls[i].nlHandle);
+        server->nls[i].start(server->nls[i].nlHandle, &server->logger);
+
+    // 2b) Init server's meta-information
+    //fill startTime
+    server->startTime = UA_DateTime_now();
+
+    //fill build date
+    {
+		static struct tm ct;
+
+		ct.tm_year = (__DATE__[7] - '0') * 1000 +  (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0')- 1900;
+
+		if (0) ;
+		else if ((__DATE__[0]=='J') && (__DATE__[1]=='a') && (__DATE__[2]=='n')) ct.tm_mon = 1-1;
+		else if ((__DATE__[0]=='F') && (__DATE__[1]=='e') && (__DATE__[2]=='b')) ct.tm_mon = 2-1;
+		else if ((__DATE__[0]=='M') && (__DATE__[1]=='a') && (__DATE__[2]=='r')) ct.tm_mon = 3-1;
+		else if ((__DATE__[0]=='A') && (__DATE__[1]=='p') && (__DATE__[2]=='r')) ct.tm_mon = 4-1;
+		else if ((__DATE__[0]=='M') && (__DATE__[1]=='a') && (__DATE__[2]=='y')) ct.tm_mon = 5-1;
+		else if ((__DATE__[0]=='J') && (__DATE__[1]=='u') && (__DATE__[2]=='n')) ct.tm_mon = 6-1;
+		else if ((__DATE__[0]=='J') && (__DATE__[1]=='u') && (__DATE__[2]=='l')) ct.tm_mon = 7-1;
+		else if ((__DATE__[0]=='A') && (__DATE__[1]=='u') && (__DATE__[2]=='g')) ct.tm_mon = 8-1;
+		else if ((__DATE__[0]=='S') && (__DATE__[1]=='e') && (__DATE__[2]=='p')) ct.tm_mon = 9-1;
+		else if ((__DATE__[0]=='O') && (__DATE__[1]=='c') && (__DATE__[2]=='t')) ct.tm_mon = 10-1;
+		else if ((__DATE__[0]=='N') && (__DATE__[1]=='o') && (__DATE__[2]=='v')) ct.tm_mon = 11-1;
+		else if ((__DATE__[0]=='D') && (__DATE__[1]=='e') && (__DATE__[2]=='c')) ct.tm_mon = 12-1;
+
+		// special case to handle __DATE__ not inserting leading zero on day of month
+		// if Day of month is less than 10 - it inserts a blank character
+		// this results in a negative number for tm_mday
+
+		if(__DATE__[4] == ' ')
+		{
+			ct.tm_mday =  __DATE__[5]-'0';
+		}
+		else
+		{
+			ct.tm_mday = (__DATE__[4]-'0')*10 + (__DATE__[5]-'0');
+		}
+
+		ct.tm_hour = ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0');
+		ct.tm_min = ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0');
+		ct.tm_sec = ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0');
+
+		ct.tm_isdst = -1;  // information is not available.
+
+		//FIXME: next 3 lines are copy-pasted from ua_types.c
+		#define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
+		#define HUNDRED_NANOSEC_PER_USEC 10LL
+		#define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
+		server->buildDate = (mktime(&ct) + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC;
+    }
 
-    // 3) The loop
+    //3) The loop
     while(1) {
         // 3.1) Process timed work
         UA_UInt16 timeout = processTimedWork(server);

+ 10 - 1
src/server/ua_services.h

@@ -24,7 +24,9 @@
  * @{
  */
 // Service_FindServers
-
+void Service_FindServers(UA_Server                    *server,
+                          const UA_FindServersRequest *request,
+                          UA_FindServersResponse      *response);
 /**
  * Returns the Endpoints supported by a Server and all of the configuration
  * information required to establish a SecureChannel and a Session.
@@ -136,8 +138,15 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
                                            const UA_TranslateBrowsePathsToNodeIdsRequest *request,
                                            UA_TranslateBrowsePathsToNodeIdsResponse *response);
 // Service_BrowseNext
+
 // Service_RegisterNodes
+void Service_RegisterNodes(UA_Server *server, UA_Session *session,
+                                           const UA_RegisterNodesRequest *request,
+                                           UA_RegisterNodesResponse *response);
 // Service_UnregisterNodes
+void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
+                                           const UA_UnregisterNodesRequest *request,
+                                           UA_UnregisterNodesResponse *response);
 /** @} */
 
 /**

+ 348 - 165
src/server/ua_services_attribute.c

@@ -4,17 +4,108 @@
 #include "ua_statuscodes.h"
 #include "ua_nodestore.h"
 #include "ua_util.h"
-#include "stdio.h"
+
+static UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range) {
+    if(str.length < 0 || str.length >= 1023)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    char *cstring = UA_alloca(str.length+1);
+    UA_memcpy(cstring, str.data, str.length);
+    cstring[str.length] = 0;
+    UA_Int32 index = 0;
+    size_t dimensionsIndex = 0;
+    size_t dimensionsMax = 3; // more should be uncommon
+    struct UA_NumericRangeDimension *dimensions = UA_malloc(sizeof(struct UA_NumericRangeDimension) * 3);
+    if(!dimensions)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    do {
+        UA_Int32 min, max;
+        UA_Int32 progress;
+        UA_Int32 res = sscanf(&cstring[index], "%" SCNu32 "%n", &min, &progress);
+        if(res <= 0 || min < 0) {
+            retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
+            break;
+        }
+        index += progress;
+        if(index >= str.length || cstring[index] == ',')
+            max = min;
+        else {
+            res = sscanf(&cstring[index], ":%" SCNu32 "%n", &max, &progress);
+            if(res <= 0 || max < 0 || min >= max) {
+                retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
+                break;
+            }
+            index += progress;
+        }
+        
+        if(dimensionsIndex >= dimensionsMax) {
+            struct UA_NumericRangeDimension *newDimensions =
+                UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * 2 * dimensionsMax);
+            if(!newDimensions) {
+                UA_free(dimensions);
+                return UA_STATUSCODE_BADOUTOFMEMORY;
+            }
+            dimensions = newDimensions;
+            dimensionsMax *= 2;
+        }
+
+        dimensions[dimensionsIndex].min = min;
+        dimensions[dimensionsIndex].max = max;
+        dimensionsIndex++;
+    } while(retval == UA_STATUSCODE_GOOD && index + 1 < str.length && cstring[index] == ',' && ++index);
+
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_free(dimensions);
+        return retval;
+    }
+        
+    range->dimensions = dimensions;
+    range->dimensionsSize = dimensionsIndex;
+    return retval;
+}
 
 #define CHECK_NODECLASS(CLASS)                                  \
     if(!(node->nodeClass & (CLASS))) {                          \
         v->hasStatus = UA_TRUE;                                 \
-        v->status = UA_STATUSCODE_BADNOTREADABLE;               \
+        v->status = UA_STATUSCODE_BADATTRIBUTEIDINVALID;        \
         break;                                                  \
     }
 
+static void handleServerTimestamps(UA_TimestampsToReturn timestamps, UA_DataValue* v) {
+	if (v && (timestamps == UA_TIMESTAMPSTORETURN_SERVER
+			|| timestamps == UA_TIMESTAMPSTORETURN_BOTH)) {
+		v->hasServerTimestamp = UA_TRUE;
+		v->serverTimestamp = UA_DateTime_now();
+	}
+}
+
+static void handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValue* v) {
+	if(timestamps == UA_TIMESTAMPSTORETURN_SOURCE || timestamps == UA_TIMESTAMPSTORETURN_BOTH) {
+		v->hasSourceTimestamp = UA_TRUE;
+		v->sourceTimestamp = UA_DateTime_now();
+	}
+}
+
 /** Reads a single attribute from a node in the nodestore. */
-static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue *v) {
+static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
+                      const UA_ReadValueId *id, UA_DataValue *v) {
+
+	if(id->dataEncoding.name.length >= 0){
+		if(memcmp(id->dataEncoding.name.data, "DefaultBinary", 13)!=0 && memcmp(id->dataEncoding.name.data, "DefaultXml", 10)!=0){
+			v->hasStatus = UA_TRUE;
+			v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
+			return;
+		}
+	}
+
+	//index range for a non-value
+	if(id->indexRange.length >= 0 && id->attributeId != UA_ATTRIBUTEID_VALUE){
+		v->hasStatus = UA_TRUE;
+		v->status = UA_STATUSCODE_BADINDEXRANGENODATA;
+		return;
+	}
+
     UA_Node const *node = UA_NodeStore_get(server->nodestore, &(id->nodeId));
     if(!node) {
         v->hasStatus = UA_TRUE;
@@ -23,164 +114,233 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
     }
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-
     switch(id->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &node->nodeId, UA_TYPES_NODEID);
+        retval |= UA_Variant_setScalarCopy(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
         break;
-
     case UA_ATTRIBUTEID_NODECLASS:
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &node->nodeClass, UA_TYPES_INT32);
+        retval |= UA_Variant_setScalarCopy(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
         break;
-
     case UA_ATTRIBUTEID_BROWSENAME:
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &node->browseName, UA_TYPES_QUALIFIEDNAME);
+        retval |= UA_Variant_setScalarCopy(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
         break;
-
     case UA_ATTRIBUTEID_DISPLAYNAME:
-        retval |= UA_Variant_copySetValue(&v->value, &node->displayName, UA_TYPES_LOCALIZEDTEXT);
+        retval |= UA_Variant_setScalarCopy(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         if(retval == UA_STATUSCODE_GOOD)
             v->hasVariant = UA_TRUE;
         break;
-
     case UA_ATTRIBUTEID_DESCRIPTION:
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &node->description, UA_TYPES_LOCALIZEDTEXT);
+        retval |= UA_Variant_setScalarCopy(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
-
     case UA_ATTRIBUTEID_WRITEMASK:
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &node->writeMask, UA_TYPES_UINT32);
+        retval |= UA_Variant_setScalarCopy(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
-
     case UA_ATTRIBUTEID_USERWRITEMASK:
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &node->userWriteMask, UA_TYPES_UINT32);
+        retval |= UA_Variant_setScalarCopy(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
-
     case UA_ATTRIBUTEID_ISABSTRACT:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE |
                         UA_NODECLASS_DATATYPE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ReferenceTypeNode *)node)->isAbstract,
-                                          UA_TYPES_BOOLEAN);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->isAbstract,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
-
     case UA_ATTRIBUTEID_SYMMETRIC:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ReferenceTypeNode *)node)->symmetric,
-                                          UA_TYPES_BOOLEAN);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->symmetric,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
-
     case UA_ATTRIBUTEID_INVERSENAME:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ReferenceTypeNode *)node)->inverseName,
-                                          UA_TYPES_LOCALIZEDTEXT);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode *)node)->inverseName,
+                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
-
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ViewNode *)node)->containsNoLoops,
-                                          UA_TYPES_BOOLEAN);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode *)node)->containsNoLoops,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
-
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_ViewNode *)node)->eventNotifier,
-                                          UA_TYPES_BYTE);
+        if(node->nodeClass == UA_NODECLASS_VIEW){
+        	retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode *)node)->eventNotifier,
+                                          	  &UA_TYPES[UA_TYPES_BYTE]);
+        } else {
+        	retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_ObjectNode *)node)->eventNotifier,
+                                              &UA_TYPES[UA_TYPES_BYTE]);
+        }
         break;
 
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = UA_Variant_copy(&((const UA_VariableNode *)node)->value, &v->value);
-        if(retval == UA_STATUSCODE_GOOD)
-            v->hasVariant = UA_TRUE;
+        {
+        	if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+                // todo: copy only selective...
+                UA_Boolean hasRange = UA_FALSE;
+                UA_NumericRange range;
+                if(id->indexRange.length > 0) {
+                    hasRange = UA_TRUE;
+                    retval = parse_numericrange(id->indexRange, &range);
+                    if(retval != UA_STATUSCODE_GOOD)
+                        break;
+                }
+
+				const UA_VariableNode *vn = (const UA_VariableNode*)node;
+				if(vn->variableType == UA_VARIABLENODETYPE_VARIANT) {
+                    if(hasRange)
+                        retval = UA_Variant_copyRange(&vn->variable.variant, &v->value, range);
+                    else
+                        retval = UA_Variant_copy(&vn->variable.variant, &v->value);
+					if(retval != UA_STATUSCODE_GOOD) {
+                        if(hasRange)
+                            UA_free(range.dimensions);
+						break;
+                    }
+					v->hasVariant = UA_TRUE;
+					handleSourceTimestamps(timestamps, v);
+				} else {
+					UA_DataValue val;
+					UA_DataValue_init(&val);
+					UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
+												  timestamps == UA_TIMESTAMPSTORETURN_BOTH);
+					retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, sourceTimeStamp, &val);
+					if(retval != UA_STATUSCODE_GOOD)
+						break;
+					retval |= UA_DataValue_copy(&val, v);
+					vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+					if(retval != UA_STATUSCODE_GOOD)
+						break;
+                    // todo: selection of indexranges
+				}
+
+                if(hasRange)
+                    UA_free(range.dimensions);
+                
+        	} else {
+    			v->hasVariant = UA_FALSE;
+    			handleSourceTimestamps(timestamps, v);
+        	}
+        }
         break;
 
     case UA_ATTRIBUTEID_DATATYPE:
-        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableTypeNode *)node)->value.typeId,
-                                          UA_TYPES_NODEID);
+		CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
+		v->hasVariant = UA_TRUE;
+		if(node->nodeClass == UA_NODECLASS_VARIABLETYPE){
+			retval |= UA_Variant_setScalarCopy(&v->value,
+											  &((const UA_VariableTypeNode *)node)->value.type->typeId,
+											  &UA_TYPES[UA_TYPES_NODEID]);
+		} else {
+			const UA_VariableNode *vn = (const UA_VariableNode*)node;
+			if(vn->variableType == UA_VARIABLENODETYPE_VARIANT)
+				retval |= UA_Variant_setScalarCopy(&v->value, &vn->variable.variant.type->typeId,
+												  &UA_TYPES[UA_TYPES_NODEID]);
+			else {
+				UA_DataValue val;
+				UA_DataValue_init(&val);
+				retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, UA_FALSE, &val);
+				if(retval != UA_STATUSCODE_GOOD)
+					break;
+				retval |= UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId,
+												  &UA_TYPES[UA_TYPES_NODEID]);
+				vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+				if(retval != UA_STATUSCODE_GOOD)
+					break;
+			}
+		}
         break;
 
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableTypeNode *)node)->valueRank,
-                                          UA_TYPES_INT32);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode *)node)->valueRank,
+                                          &UA_TYPES[UA_TYPES_INT32]);
         break;
 
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         {
-            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);
+        	//TODO: handle indexRange
+        	if(node->nodeClass == UA_NODECLASS_VARIABLE){
+				const UA_VariableNode *vn = (const UA_VariableNode *)node;
+				if(vn->variableType == UA_VARIABLENODETYPE_VARIANT) {
+					retval = UA_Variant_setArrayCopy(&v->value, vn->variable.variant.arrayDimensions,
+													 vn->variable.variant.arrayDimensionsSize,
+													 &UA_TYPES[UA_TYPES_INT32]);
+					if(retval == UA_STATUSCODE_GOOD)
+						v->hasVariant = UA_TRUE;
+				} else {
+					UA_DataValue val;
+					UA_DataValue_init(&val);
+
+					retval |= vn->variable.dataSource.read(vn->variable.dataSource.handle, UA_FALSE, &val);
+					if(retval != UA_STATUSCODE_GOOD)
+						break;
+					if(!val.hasVariant) {
+						vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+						retval = UA_STATUSCODE_BADNOTREADABLE;
+						break;
+					}
+					retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions,
+													 val.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+					vn->variable.dataSource.release(vn->variable.dataSource.handle, &val);
+				}
+        	} else {
+        		retval = UA_STATUSCODE_GOOD;
+        	}
         }
         break;
 
     case UA_ATTRIBUTEID_ACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->accessLevel,
-                                          UA_TYPES_BYTE);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->accessLevel,
+                                          &UA_TYPES[UA_TYPES_BYTE]);
         break;
 
     case UA_ATTRIBUTEID_USERACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->userAccessLevel,
-                                          UA_TYPES_BYTE);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->userAccessLevel,
+                                          &UA_TYPES[UA_TYPES_BYTE]);
         break;
 
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->minimumSamplingInterval,
-                                          UA_TYPES_DOUBLE);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->minimumSamplingInterval,
+                                          &UA_TYPES[UA_TYPES_DOUBLE]);
         break;
 
     case UA_ATTRIBUTEID_HISTORIZING:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_VariableNode *)node)->historizing,
-                                          UA_TYPES_BOOLEAN);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode *)node)->historizing,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
 
     case UA_ATTRIBUTEID_EXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_MethodNode *)node)->executable,
-                                          UA_TYPES_BOOLEAN);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode *)node)->executable,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
 
     case UA_ATTRIBUTEID_USEREXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
         v->hasVariant = UA_TRUE;
-        retval |= UA_Variant_copySetValue(&v->value, &((const UA_MethodNode *)node)->userExecutable,
-                                          UA_TYPES_BOOLEAN);
+        retval |= UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode *)node)->userExecutable,
+                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
 
     default:
@@ -191,14 +351,12 @@ static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue
 
     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->hasStatus = UA_TRUE;
-        v->status = UA_STATUSCODE_BADNOTREADABLE;
+        v->status = retval;
     }
+
+    handleServerTimestamps(timestamps, v);
 }
 
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
@@ -208,19 +366,33 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
         return;
     }
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_DATAVALUE], request->nodesToReadSize);
+    if(request->timestampsToReturn > 3){
+    	response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
+    	return;
+    }
+
+    size_t size = request->nodesToReadSize;
+
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_DATAVALUE], size);
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 
+    response->resultsSize = size;
+
+    if(request->maxAge < 0) {
+    	response->responseHeader.serviceResult = UA_STATUSCODE_BADMAXAGEINVALID;
+        return;
+    }
+
     /* ### Begin External Namespaces */
-    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToReadSize);
-    UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToReadSize);
-    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToReadSize);
+    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
+    UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
+    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
-        UA_UInt32 indexSize = 0;
-        for(UA_Int32 i = 0;i < request->nodesToReadSize;i++) {
+        size_t indexSize = 0;
+        for(size_t i = 0;i < size;i++) {
             if(request->nodesToRead[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
                 continue;
             isExternal[i] = UA_TRUE;
@@ -235,10 +407,9 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
     /* ### End External Namespaces */
 
-    response->resultsSize = request->nodesToReadSize;
-    for(UA_Int32 i = 0;i < response->resultsSize;i++) {
+    for(size_t i = 0;i < size;i++) {
         if(!isExternal[i])
-            readValue(server, &request->nodesToRead[i], &response->results[i]);
+            readValue(server, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]);
     }
 
 #ifdef EXTENSION_STATELESS
@@ -247,17 +418,15 @@ 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.identifier.numeric = UA_TYPES_IDS[UA_TYPES_VARIANT];
 
 		UA_Variant variant;
 		UA_Variant_init(&variant);
 		variant.type = &UA_TYPES[UA_TYPES_DATETIME];
-		variant.storage.data.arrayLength = request->nodesToReadSize;
+		variant.arrayLength = request->nodesToReadSize;
 
 		UA_DateTime* expireArray = UA_NULL;
-		UA_Array_new((void**)&expireArray, request->nodesToReadSize,
-												&UA_TYPES[UA_TYPES_DATETIME]);
-		variant.storage.data.dataPtr = expireArray;
+		expireArray = UA_Array_new(&UA_TYPES[UA_TYPES_DATETIME], request->nodesToReadSize);
+		variant.dataPtr = expireArray;
 
 		UA_ByteString str;
 		UA_ByteString_init(&str);
@@ -266,7 +435,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 		for(UA_Int32 i = 0;i < response->resultsSize;i++) {
 			expireArray[i] = UA_DateTime_now() + 20 * 100 * 1000 * 1000;
 		}
-		UA_UInt32 offset = 0;
+		size_t offset = 0;
 		str.data = UA_malloc(UA_Variant_calcSizeBinary(&variant));
 		str.length = UA_Variant_calcSizeBinary(&variant);
 		UA_Variant_encodeBinary(&variant, &str, &offset);
@@ -286,56 +455,6 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
-        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 *(*)(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 *(*)(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 *(*)(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 *(*)(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 *(*)(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 *(*)(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 *(*)(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 *(*)(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;
-        }
-
         switch(wvalue->attributeId) {
         case UA_ATTRIBUTEID_NODEID:
         case UA_ATTRIBUTEID_NODECLASS:
@@ -352,45 +471,104 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
             retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
             break;
         case UA_ATTRIBUTEID_VALUE:
-            if((node->nodeClass != UA_NODECLASS_VARIABLE) && (node->nodeClass != UA_NODECLASS_VARIABLETYPE)) {
-                retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-                break;
-            }
+            if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+                const UA_VariableNode *vn = (const UA_VariableNode*)node;
+                if(vn->variableType == UA_VARIABLENODETYPE_DATASOURCE) {
+                    if(!vn->variable.dataSource.write) {
+                        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+                        break;
+                    }
+                    retval = vn->variable.dataSource.write(vn->variable.dataSource.handle, &wvalue->value.value);
+                    done = UA_TRUE;
+                    break;
+                }
 
-            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;
-            }
+                // array sizes are not compared
 
-            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(!wvalue->value.hasVariant) {
+                    retval = UA_STATUSCODE_BADTYPEMISMATCH;
+                    break;
+                }
+
+                if(!UA_NodeId_equal(&vn->variable.variant.type->typeId, &wvalue->value.value.type->typeId)) {
+                    if(vn->variable.variant.type->namespaceZero && wvalue->value.value.type->namespaceZero &&
+                       vn->variable.variant.type->typeIndex == wvalue->value.value.type->typeIndex)
+                        // an enum was sent as an int32, or an opaque type as a bytestring
+                        wvalue->value.value.type = vn->variable.variant.type;
+                    else if(vn->variable.variant.type == &UA_TYPES[UA_TYPES_BYTE] &&
+                            (!vn->variable.variant.dataPtr || vn->variable.variant.arrayLength > -1) /* isArray */ &&
+                            wvalue->value.value.type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
+                            wvalue->value.value.dataPtr && wvalue->value.value.arrayLength == -1 /* isScalar */) {
+                        // a string is written to a byte array
+                        UA_ByteString *str = (UA_ByteString*) wvalue->value.value.dataPtr;
+                        wvalue->value.value.arrayLength = str->length;
+                        wvalue->value.value.dataPtr = str->data;
+                        wvalue->value.value.type = &UA_TYPES[UA_TYPES_BYTE];
+                        UA_free(str);
+                    } else {
+                        retval = UA_STATUSCODE_BADTYPEMISMATCH;
+                        break;
+                    }
+                }
+
+                UA_VariableNode *newVn = UA_VariableNode_new();
                 if(!newVn) {
                     retval = UA_STATUSCODE_BADOUTOFMEMORY;
                     break;
                 }
-                retval = copyNode((const UA_Node*)vn, (UA_Node*)newVn);
+                retval = UA_VariableNode_copy(vn, newVn);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    UA_VariableNode_delete(newVn);
+                    break;
+                }
+                retval = UA_Variant_copy(&wvalue->value.value, &newVn->variable.variant);
+                if(retval != UA_STATUSCODE_GOOD) {
+                    UA_VariableNode_delete(newVn);
+                    break;
+                }
+                if(UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVn,
+                                        UA_NULL) == UA_STATUSCODE_GOOD)
+                    done = UA_TRUE;
+                else
+                    UA_VariableNode_delete(newVn);
+            } else if(node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
+                const UA_VariableTypeNode *vtn = (const UA_VariableTypeNode*)node;
+                if(!wvalue->value.hasVariant) {
+                    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+                    break;
+                }
+                if(!UA_NodeId_equal(&vtn->value.type->typeId, &wvalue->value.value.type->typeId)) {
+                    if(!vtn->value.type->namespaceZero || wvalue->value.value.type->namespaceZero ||
+                       vtn->value.type->typeIndex != wvalue->value.value.type->typeIndex) {
+                        retval = UA_STATUSCODE_BADTYPEMISMATCH;
+                        break;
+                    }
+                    wvalue->value.value.type = vtn->value.type;
+                }
+
+                UA_VariableTypeNode *newVtn = UA_VariableTypeNode_new();
+                if(!newVtn) {
+                    retval = UA_STATUSCODE_BADOUTOFMEMORY;
+                    break;
+                }
+                retval = UA_VariableTypeNode_copy(vtn, newVtn);
                 if(retval != UA_STATUSCODE_GOOD) {
-                    deleteNode((UA_Node*)newVn);
+                    UA_VariableTypeNode_delete(newVtn);
                     break;
                 }
-                retval = UA_Variant_copy(&wvalue->value.value, &newVn->value);
+                retval = UA_Variant_copy(&wvalue->value.value, &newVtn->value);
                 if(retval != UA_STATUSCODE_GOOD) {
-                    deleteNode((UA_Node*)newVn);
+                    UA_VariableTypeNode_delete(newVtn);
                     break;
                 }
-                if(UA_NodeStore_replace(server->nodestore,node,(UA_Node*)newVn,UA_NULL) == UA_STATUSCODE_GOOD)
+                if(UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVtn,
+                                        UA_NULL) == UA_STATUSCODE_GOOD)
                     done = UA_TRUE;
                 else
-                    deleteNode((UA_Node*)newVn);
-            } 
+                    UA_VariableTypeNode_delete(newVtn);
+            } else {
+                retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
+            }
             break;
         case UA_ATTRIBUTEID_DATATYPE:
         case UA_ATTRIBUTEID_VALUERANK:
@@ -421,6 +599,11 @@ 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);
 
+    if(request->nodesToWriteSize <= 0){
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+        return;
+    }
+
     response->results = UA_Array_new(&UA_TYPES[UA_TYPES_STATUSCODE], request->nodesToWriteSize);
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;

+ 30 - 1
src/server/ua_services_discovery.c

@@ -2,10 +2,39 @@
 #include "ua_services.h"
 #include "ua_util.h"
 
+void Service_FindServers(UA_Server                    *server,
+                          const UA_FindServersRequest *request,
+                          UA_FindServersResponse      *response) {
+    response->servers = UA_malloc(sizeof(UA_ApplicationDescription));
+    if(!response->servers) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
+    }
+    if(UA_ApplicationDescription_copy(&server->description, response->servers) != UA_STATUSCODE_GOOD) {
+        UA_free(response->servers);
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
+    }
+	response->serversSize = 1;
+}
+
 void Service_GetEndpoints(UA_Server                    *server,
                           const UA_GetEndpointsRequest *request,
                           UA_GetEndpointsResponse      *response) {
-    UA_GetEndpointsResponse_init(response);
+    /* test if the supported binary profile shall be returned */
+    UA_Boolean returnBinary = request->profileUrisSize == 0;
+    for(UA_Int32 i=0;i<request->profileUrisSize;i++) {
+        if(UA_String_equal(&request->profileUris[i], &server->endpointDescriptions->transportProfileUri)) {
+            returnBinary = UA_TRUE;
+            break;
+        }
+    }
+
+    if(!returnBinary) {
+        response->endpointsSize = 0;
+        return;
+    }
+
     response->endpoints = UA_malloc(sizeof(UA_EndpointDescription));
     if(!response->endpoints) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;

+ 33 - 38
src/server/ua_services_nodemanagement.c

@@ -22,7 +22,7 @@
 
 static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     if(attributes->typeId.identifier.numeric !=
-       UA_TYPES_IDS[UA_TYPES_VARIABLEATTRIBUTES] + UA_ENCODINGOFFSET_BINARY)
+       UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES].typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
 
     UA_VariableAttributes attr;
@@ -39,19 +39,14 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
 
     // now copy all the attributes. This potentially removes them from the decoded attributes.
     COPY_STANDARDATTRIBUTES;
-
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ACCESSLEVEL)
         vnode->accessLevel = attr.accessLevel;
-
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL)
         vnode->userAccessLevel = attr.userAccessLevel;
-
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING)
         vnode->historizing = attr.historizing;
-
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL)
         vnode->minimumSamplingInterval = attr.minimumSamplingInterval;
-
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
         vnode->valueRank = attr.valueRank;
 
@@ -71,7 +66,7 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     /* } */
 
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
-        vnode->value = attr.value;
+        vnode->variable.variant = attr.value;
         UA_Variant_init(&attr.value);
     }
 
@@ -83,8 +78,9 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
 
 static UA_StatusCode parseObjectNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     if(attributes->typeId.identifier.numeric !=
-       UA_TYPES_IDS[UA_TYPES_OBJECTATTRIBUTES] + UA_ENCODINGOFFSET_BINARY)  // VariableAttributes_Encoding_DefaultBinary
+       UA_TYPES[UA_TYPES_OBJECTATTRIBUTES].typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+
     UA_ObjectAttributes attr;
     size_t pos = 0;
     // todo return more informative error codes from decodeBinary
@@ -239,20 +235,21 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
     }
+    size_t size = request->nodesToAddSize;
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_ADDNODESRESULT], request->nodesToAddSize);
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_ADDNODESRESULT], size);
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
 
     /* ### Begin External Namespaces */
-    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToAddSize);
-    UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToAddSize);
-    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToAddSize);
+    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
+    UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
+    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
-        UA_UInt32 indexSize = 0;
-        for(UA_Int32 i = 0;i < request->nodesToAddSize;i++) {
+        size_t indexSize = 0;
+        for(size_t i = 0;i < size;i++) {
             if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex != server->externalNamespaces[j].index)
                 continue;
             isExternal[i] = UA_TRUE;
@@ -267,39 +264,36 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
     }
     /* ### End External Namespaces */
     
-    response->resultsSize = request->nodesToAddSize;
-    for(int i = 0;i < request->nodesToAddSize;i++) {
+    response->resultsSize = size;
+    for(size_t i = 0;i < size;i++) {
         if(!isExternal[i])
             addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
     }
 }
 
-void Service_AddReferences(UA_Server *server, UA_Session *session,
-		const UA_AddReferencesRequest *request,
-		UA_AddReferencesResponse *response) {
-	if (request->referencesToAddSize <= 0) {
+void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
+                           UA_AddReferencesResponse *response) {
+	if(request->referencesToAddSize <= 0) {
 		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
 		return;
 	}
-	response->results = UA_malloc(
-			sizeof(UA_StatusCode) * request->referencesToAddSize);
-	if (!response->results) {
+    size_t size = request->referencesToAddSize;
+	
+    if(!(response->results = UA_malloc(sizeof(UA_StatusCode) * size))) {
 		response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
 		return;
 	}
-	response->resultsSize = request->referencesToAddSize;
-	UA_memset(response->results, UA_STATUSCODE_GOOD,
-			sizeof(UA_StatusCode) * response->resultsSize);
+	response->resultsSize = size;
+	UA_memset(response->results, UA_STATUSCODE_GOOD, sizeof(UA_StatusCode) * size);
+
 	/* ### Begin External Namespaces */
-//UA_Boolean isExternal[MAX_ADDREFERENCES_SIZE];
-	UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->referencesToAddSize);
-	UA_memset(isExternal, UA_FALSE,
-			sizeof(UA_Boolean) * request->referencesToAddSize);
-	UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->referencesToAddSize);
-	for (UA_Int32 j = 0; j < server->externalNamespacesSize; j++) {
-		UA_UInt32 indexSize = 0;
-		for (UA_Int32 i = 0; i < request->referencesToAddSize; i++) {
-			if (request->referencesToAdd[i].sourceNodeId.namespaceIndex
+	UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
+	UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
+	UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
+	for(UA_Int32 j = 0; j < server->externalNamespacesSize; j++) {
+		size_t indexSize = 0;
+		for(size_t i = 0;i < size;i++) {
+			if(request->referencesToAdd[i].sourceNodeId.namespaceIndex
 					!= server->externalNamespaces[j].index)
 				continue;
 			isExternal[i] = UA_TRUE;
@@ -315,9 +309,10 @@ void Service_AddReferences(UA_Server *server, UA_Session *session,
 				response->diagnosticInfos);
 	}
 	/* ### End External Namespaces */
-	response->resultsSize = request->referencesToAddSize;
-	for (UA_Int32 i = 0; i < response->resultsSize; i++) {
-		if (!isExternal[i])
+
+	response->resultsSize = size;
+	for(UA_Int32 i = 0; i < response->resultsSize; i++) {
+		if(!isExternal[i])
 			UA_Server_addReference(server, &request->referencesToAdd[i]);
 	}
 }

+ 22 - 17
src/server/ua_services_session.c

@@ -7,26 +7,35 @@
 void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                            const UA_CreateSessionRequest *request,
                            UA_CreateSessionResponse *response) {
+
+    response->serverEndpoints = UA_malloc(sizeof(UA_EndpointDescription));
+    if(!response->serverEndpoints || (response->responseHeader.serviceResult =
+        UA_EndpointDescription_copy(server->endpointDescriptions, response->serverEndpoints)) !=
+       UA_STATUSCODE_GOOD)
+        return;
+    response->serverEndpointsSize = 1;
+
     // creates a session and adds a pointer to the channel. Only when the
     // session is activated will the channel point to the session as well
 	UA_Session *newSession;
-    response->responseHeader.serviceResult = UA_SessionManager_createSession(&server->sessionManager, channel, &newSession);
+    response->responseHeader.serviceResult = UA_SessionManager_createSession(&server->sessionManager,
+                                                                             channel, request, &newSession);
 	if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
 		return;
 
-    //TODO get maxResponseMessageSize
-    UA_String_copy(&request->sessionName, &newSession->sessionName);
+    //TODO get maxResponseMessageSize internally
     newSession->maxResponseMessageSize = request->maxResponseMessageSize;
-    
     response->sessionId = newSession->sessionId;
     response->revisedSessionTimeout = newSession->timeout;
     response->authenticationToken = newSession->authenticationToken;
-    UA_ByteString_copy(&server->serverCertificate, &response->serverCertificate);
-
-    response->serverEndpointsSize = 1;
-    response->serverEndpoints = UA_malloc(sizeof(UA_EndpointDescription));
-    UA_EndpointDescription_copy(server->endpointDescriptions, response->serverEndpoints);
-    
+    response->responseHeader.serviceResult = UA_String_copy(&request->sessionName, &newSession->sessionName);
+    if(server->endpointDescriptions)
+        response->responseHeader.serviceResult |=
+            UA_ByteString_copy(&server->endpointDescriptions->serverCertificate, &response->serverCertificate);
+    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
+        UA_SessionManager_removeSession(&server->sessionManager, &newSession->sessionId);
+         return;
+    }
 }
 
 void Service_ActivateSession(UA_Server *server,UA_SecureChannel *channel,
@@ -48,19 +57,15 @@ void Service_CloseSession(UA_Server *server, const UA_CloseSessionRequest *reque
                               UA_CloseSessionResponse *response) {
 	UA_Session *foundSession;
 	UA_SessionManager_getSessionByToken(&server->sessionManager,
-			(const UA_NodeId*)&request->requestHeader.authenticationToken,
-			&foundSession);
+			(const UA_NodeId*)&request->requestHeader.authenticationToken, &foundSession);
 
 	if(foundSession == UA_NULL){
 		response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
 		return;
 	}
 
-
-	if(UA_SessionManager_removeSession(&server->sessionManager, &foundSession->sessionId) == UA_STATUSCODE_GOOD){
+	if(UA_SessionManager_removeSession(&server->sessionManager, &foundSession->sessionId) == UA_STATUSCODE_GOOD)
 		response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
-	}else{
-		//still not 100% sure about the return code
+	else
 		response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
-	}
 }

+ 296 - 172
src/server/ua_services_view.c

@@ -4,223 +4,203 @@
 #include "ua_nodestore.h"
 #include "ua_util.h"
 
-/* Releases the current node, even if it was supplied as an argument. */
-static UA_StatusCode fillReferenceDescription(UA_NodeStore *ns, const UA_Node *currentNode, UA_ReferenceNode *reference,
-                                              UA_UInt32 resultMask, UA_ReferenceDescription *referenceDescription) {
+static UA_StatusCode
+fillrefdescr(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode *ref, UA_UInt32 mask,
+             UA_ReferenceDescription *descr)
+{
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_ReferenceDescription_init(referenceDescription);
-    retval |= UA_NodeId_copy(&currentNode->nodeId, &referenceDescription->nodeId.nodeId);
+    UA_ReferenceDescription_init(descr);
+    retval |= UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
     //TODO: ExpandedNodeId is mocked up
-    referenceDescription->nodeId.serverIndex = 0;
-    referenceDescription->nodeId.namespaceUri.length = -1;
-
-    if(resultMask & UA_BROWSERESULTMASK_REFERENCETYPEID)
-        retval |= UA_NodeId_copy(&reference->referenceTypeId, &referenceDescription->referenceTypeId);
-    if(resultMask & UA_BROWSERESULTMASK_ISFORWARD)
-        referenceDescription->isForward = !reference->isInverse;
-    if(resultMask & UA_BROWSERESULTMASK_NODECLASS)
-        retval |= UA_NodeClass_copy(&currentNode->nodeClass, &referenceDescription->nodeClass);
-    if(resultMask & UA_BROWSERESULTMASK_BROWSENAME)
-        retval |= UA_QualifiedName_copy(&currentNode->browseName, &referenceDescription->browseName);
-    if(resultMask & UA_BROWSERESULTMASK_DISPLAYNAME)
-        retval |= UA_LocalizedText_copy(&currentNode->displayName, &referenceDescription->displayName);
-    if(resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION && currentNode->nodeClass != UA_NODECLASS_OBJECT &&
-       currentNode->nodeClass != UA_NODECLASS_VARIABLE) {
-        for(UA_Int32 i = 0;i < currentNode->referencesSize;i++) {
-            UA_ReferenceNode *ref = &currentNode->references[i];
-            if(ref->referenceTypeId.identifier.numeric == 40 /* hastypedefinition */) {
-                retval |= UA_ExpandedNodeId_copy(&ref->targetId, &referenceDescription->typeDefinition);
+    descr->nodeId.serverIndex = 0;
+    descr->nodeId.namespaceUri.length = -1;
+
+    if(mask & UA_BROWSERESULTMASK_REFERENCETYPEID)
+        retval |= UA_NodeId_copy(&ref->referenceTypeId, &descr->referenceTypeId);
+    if(mask & UA_BROWSERESULTMASK_ISFORWARD)
+        descr->isForward = !ref->isInverse;
+    if(mask & UA_BROWSERESULTMASK_NODECLASS)
+        retval |= UA_NodeClass_copy(&curr->nodeClass, &descr->nodeClass);
+    if(mask & UA_BROWSERESULTMASK_BROWSENAME)
+        retval |= UA_QualifiedName_copy(&curr->browseName, &descr->browseName);
+    if(mask & UA_BROWSERESULTMASK_DISPLAYNAME)
+        retval |= UA_LocalizedText_copy(&curr->displayName, &descr->displayName);
+    if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION ) {
+        for(UA_Int32 i = 0;i < curr->referencesSize;i++) {
+            UA_ReferenceNode *refnode = &curr->references[i];
+            if(refnode->referenceTypeId.identifier.numeric == UA_NS0ID_HASTYPEDEFINITION) {
+                retval |= UA_ExpandedNodeId_copy(&refnode->targetId, &descr->typeDefinition);
                 break;
             }
         }
     }
 
-    if(currentNode)
-        UA_NodeStore_release(currentNode);
     if(retval)
-        UA_ReferenceDescription_deleteMembers(referenceDescription);
+        UA_ReferenceDescription_deleteMembers(descr);
     return retval;
 }
 
 /* Tests if the node is relevant to the browse request and shall be returned. If
    so, it is retrieved from the Nodestore. If not, null is returned. */
-static const UA_Node *
-getRelevantTargetNode(UA_NodeStore *ns, const UA_BrowseDescription *browseDescription, UA_Boolean returnAll,
-                      UA_ReferenceNode *reference, UA_NodeId *relevantRefTypes, UA_UInt32 relevantRefTypesCount) {
-    if(reference->isInverse == UA_TRUE && browseDescription->browseDirection == UA_BROWSEDIRECTION_FORWARD)
+static const UA_Node
+*relevant_node(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_Boolean return_all,
+               UA_ReferenceNode *reference, UA_NodeId *relevant, size_t relevant_count)
+{
+    if(reference->isInverse == UA_TRUE && descr->browseDirection == UA_BROWSEDIRECTION_FORWARD)
         return UA_NULL;
-
-    else if(reference->isInverse == UA_FALSE && browseDescription->browseDirection == UA_BROWSEDIRECTION_INVERSE)
+    else if(reference->isInverse == UA_FALSE && descr->browseDirection == UA_BROWSEDIRECTION_INVERSE)
         return UA_NULL;
 
-    UA_Boolean isRelevant = returnAll;
-    if(!isRelevant) {
-        for(UA_UInt32 i = 0;i < relevantRefTypesCount;i++) {
-            if(UA_NodeId_equal(&reference->referenceTypeId, &relevantRefTypes[i]))
-                isRelevant = UA_TRUE;
+    if(!return_all) {
+        for(size_t i = 0; i < relevant_count; i++) {
+            if(UA_NodeId_equal(&reference->referenceTypeId, &relevant[i]))
+                goto is_relevant;
         }
-        if(!isRelevant)
-            return UA_NULL;
+        return UA_NULL;
     }
-
+is_relevant: ;
     const UA_Node *node = UA_NodeStore_get(ns, &reference->targetId.nodeId);
-    if(!node)
-        return UA_NULL;
-
-    if(browseDescription->nodeClassMask != 0 && (node->nodeClass & browseDescription->nodeClassMask) == 0) {
+    if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
         UA_NodeStore_release(node);
         return UA_NULL;
     }
-
     return node;
 }
 
-/* We do not search across namespaces so far. The id of the root-referencetype
-   is returned in the array also. */
-static UA_StatusCode findRelevantReferenceTypes(UA_NodeStore *ns, const UA_NodeId *rootReferenceType,
-                                                UA_NodeId **referenceTypes, UA_UInt32 *referenceTypesSize) {
-    /* The references form a tree. We walk the tree by adding new nodes to the end of the array. */
-    UA_UInt32 currentIndex = 0;
-    UA_UInt32 currentLastIndex = 0;
-    UA_UInt32 currentArraySize = 20; // should be more than enough. if not, increase the array size.
-    UA_NodeId *typeArray = UA_malloc(sizeof(UA_NodeId) * currentArraySize);
-    if(!typeArray)
+/**
+ * We find all subtypes by a single iteration over the array. We start with an array with a single
+ * root nodeid at the beginning. When we find relevant references, we add the nodeids to the back of
+ * the array and increase the size. Since the hierarchy is not cyclic, we can safely progress in the
+ * array to process the newly found referencetype nodeids (emulated recursion).
+ */
+static UA_StatusCode
+findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size_t *reftypes_count)
+{
+    size_t results_size = 20; // probably too big, but saves mallocs
+    UA_NodeId *results = UA_malloc(sizeof(UA_NodeId) * results_size);
+    if(!results)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    retval |= UA_NodeId_copy(rootReferenceType, &typeArray[0]);
-    if(retval) {
-        UA_free(typeArray);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+    UA_StatusCode retval = UA_NodeId_copy(root, &results[0]);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_free(results);
+        return retval;
     }
         
+    size_t index = 0; // where are we currently in the array?
+    size_t last = 0; // where is the last element in the array?
     do {
-        const UA_ReferenceTypeNode *node =
-            (const UA_ReferenceTypeNode *)UA_NodeStore_get(ns, &typeArray[currentIndex]);
-        if(!node)
-            break;
-        // subtypes of referencestypes are always referencestypes?
-        if(node->nodeClass != UA_NODECLASS_REFERENCETYPE) 
+        const UA_Node *node = UA_NodeStore_get(ns, &results[index]);
+        if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
             continue;
-
-        // Find subtypes of the current referencetype
-        for(UA_Int32 i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; i++) {
-            if(node->references[i].referenceTypeId.identifier.numeric != 45 /* HasSubtype */ ||
+        for(UA_Int32 i = 0; i < node->referencesSize; i++) {
+            if(node->references[i].referenceTypeId.identifier.numeric != UA_NS0ID_HASSUBTYPE ||
                node->references[i].isInverse == UA_TRUE)
                 continue;
 
-            if(currentLastIndex + 1 >= currentArraySize) {
-                // we need to resize the array
-                UA_NodeId *newArray = UA_malloc(sizeof(UA_NodeId) * currentArraySize * 2);
-                if(newArray) {
-                    UA_memcpy(newArray, typeArray, sizeof(UA_NodeId) * currentArraySize);
-                    currentArraySize *= 2;
-                    UA_free(typeArray);
-                    typeArray = newArray;
-                } else {
+            if(++last >= results_size) { // is the array big enough?
+                UA_NodeId *new_results = UA_realloc(results, sizeof(UA_NodeId) * results_size * 2);
+                if(!new_results) {
                     retval = UA_STATUSCODE_BADOUTOFMEMORY;
                     break;
                 }
+                results = new_results;
+                results_size *= 2;
             }
 
-            // ok, we have space to add the new referencetype.
-            retval |= UA_NodeId_copy(&node->references[i].targetId.nodeId, &typeArray[++currentLastIndex]);
-            if(retval)
-                currentLastIndex--; // undo if we need to delete the typeArray
+            retval = UA_NodeId_copy(&node->references[i].targetId.nodeId, &results[last]);
+            if(retval != UA_STATUSCODE_GOOD) {
+                last--; // for array_delete
+                break;
+            }
         }
-        UA_NodeStore_release((const UA_Node*)node);
-    } while(++currentIndex <= currentLastIndex && retval == UA_STATUSCODE_GOOD);
+        UA_NodeStore_release(node);
+    } while(++index <= last && retval == UA_STATUSCODE_GOOD);
 
-    if(retval)
-        UA_Array_delete(typeArray, &UA_TYPES[UA_TYPES_NODEID], currentLastIndex);
-    else {
-        *referenceTypes = typeArray;
-        *referenceTypesSize = currentLastIndex + 1;
+    if(retval) {
+        UA_Array_delete(results, &UA_TYPES[UA_TYPES_NODEID], last);
+        return retval;
     }
-    
-    return retval;
+
+    *reftypes = results;
+    *reftypes_count = last + 1;
+    return UA_STATUSCODE_GOOD;
 }
 
 /* Results for a single browsedescription. */
-static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browseDescription,
-                            UA_UInt32 maxReferences, UA_BrowseResult *browseResult) {
-    UA_UInt32  relevantReferenceTypesSize = 0;
-    UA_NodeId *relevantReferenceTypes = UA_NULL;
-
-    // if the referencetype is null, all referencetypes are returned
-    UA_Boolean returnAll = UA_NodeId_isNull(&browseDescription->referenceTypeId);
-    if(!returnAll) {
-        if(browseDescription->includeSubtypes) {
-            browseResult->statusCode = findRelevantReferenceTypes(ns, &browseDescription->referenceTypeId,
-                                                                  &relevantReferenceTypes,
-                                                                  &relevantReferenceTypesSize);
-            if(browseResult->statusCode != UA_STATUSCODE_GOOD)
+static void
+browse(UA_NodeStore *ns, const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result)
+{
+    size_t relevant_refs_size = 0;
+    UA_NodeId *relevant_refs = UA_NULL;
+
+    // what are the relevant references?
+    UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
+    if(!all_refs) {
+        if(descr->includeSubtypes) {
+            result->statusCode = findsubtypes(ns, &descr->referenceTypeId,
+                                              &relevant_refs, &relevant_refs_size);
+            if(result->statusCode != UA_STATUSCODE_GOOD)
                 return;
         } else {
-            relevantReferenceTypes = UA_NodeId_new();
-            UA_NodeId_copy(&browseDescription->referenceTypeId, relevantReferenceTypes);
-            relevantReferenceTypesSize = 1;
+            relevant_refs = (UA_NodeId*)(uintptr_t)&descr->referenceTypeId;
+            relevant_refs_size = 1;
         }
     }
 
-    const UA_Node *parentNode = UA_NodeStore_get(ns, &browseDescription->nodeId);
-    if(!parentNode) {
-        browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
-        if(!returnAll)
-            UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
+    // get the node
+    const UA_Node *node = UA_NodeStore_get(ns, &descr->nodeId);
+    if(!node) {
+        result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
+        if(!all_refs && descr->includeSubtypes)
+            UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
         return;
     }
 
-    maxReferences = parentNode->referencesSize;
-    // 0 => unlimited references
-    if(maxReferences <= 0 || maxReferences > UA_INT32_MAX ||
-       (UA_Int32)maxReferences > parentNode->referencesSize) {
-        if(parentNode->referencesSize < 0)
-            maxReferences = 0;
-        else
-            maxReferences = parentNode->referencesSize;
+    if(node->referencesSize <= 0) {
+        result->referencesSize = 0;
+        goto cleanup;
     }
 
-    /* We allocate an array that is probably too big. But since most systems
-       have more than enough memory, this has zero impact on speed and
-       performance. Call Array_delete with the actual content size! */
-    browseResult->references = UA_malloc(sizeof(UA_ReferenceDescription) * maxReferences);
-    if(!browseResult->references) {
-        browseResult->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-    } else {
-        UA_UInt32 currentRefs = 0;
-        for(UA_Int32 i = 0;i < parentNode->referencesSize && currentRefs < maxReferences;i++) {
-            // 1) Is the node relevant? If yes, the node is retrieved from the nodestore.
-            const UA_Node *currentNode = getRelevantTargetNode(ns, browseDescription, returnAll,
-                                                               &parentNode->references[i],
-                                                               relevantReferenceTypes,
-                                                               relevantReferenceTypesSize);
-            if(!currentNode)
-                continue;
+    // allocate memory for the results
+    maxrefs = node->referencesSize; // allocate enough space for all of them
+    result->references = UA_malloc(sizeof(UA_ReferenceDescription) * maxrefs);
+    if(!result->references) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto cleanup;
+    }
 
-            // 2) Fill the reference description. This also releases the current node.
-            if(fillReferenceDescription(ns, currentNode, &parentNode->references[i],
-                                        browseDescription->resultMask,
-                                        &browseResult->references[currentRefs]) != UA_STATUSCODE_GOOD) {
-                UA_Array_delete(browseResult->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], currentRefs);
-                currentRefs = 0;
-                browseResult->references = UA_NULL;
-                browseResult->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
-                break;
-            }
-            currentRefs++;
-        }
-        if(currentRefs != 0)
-            browseResult->referencesSize = currentRefs;
-        else {
-            UA_free(browseResult->references);
-            browseResult->references = UA_NULL;
+    size_t count = 0;
+    for(UA_Int32 i = 0; i < node->referencesSize && count < maxrefs; i++) {
+        const UA_Node *current;
+        current = relevant_node(ns, descr, all_refs, &node->references[i], relevant_refs, relevant_refs_size);
+        if(!current)
+            continue;
+
+        UA_StatusCode retval = fillrefdescr(ns, current, &node->references[i],
+                                            descr->resultMask, &result->references[count]);
+        UA_NodeStore_release(current);
+
+        if(retval) {
+            UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], count);
+            count = 0;
+            result->references = UA_NULL;
+            result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
+            break;
         }
+        count++;
+    }
+    if(count != 0)
+        result->referencesSize = count;
+    else {
+        UA_free(result->references);
+        result->references = UA_NULL;
     }
 
-    UA_NodeStore_release(parentNode);
-    if(!returnAll)
-        UA_Array_delete(relevantReferenceTypes, &UA_TYPES[UA_TYPES_NODEID], relevantReferenceTypesSize);
+cleanup:
+    UA_NodeStore_release(node);
+    if(!all_refs && descr->includeSubtypes)
+        UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
 }
 
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
@@ -229,20 +209,21 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
     }
+   size_t size = request->nodesToBrowseSize;
 
-   response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], request->nodesToBrowseSize);
+   response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
     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);
-    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToBrowseSize);
+    UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
+    UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
+    UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
-        UA_UInt32 indexSize = 0;
-        for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++) {
+        size_t indexSize = 0;
+        for(size_t i = 0;i < size;i++) {
             if(request->nodesToBrowse[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
                 continue;
             isExternal[i] = UA_TRUE;
@@ -253,19 +234,131 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
             continue;
 
         UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
-        ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse,
-                       indices, indexSize, request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
+        ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse, indices, indexSize,
+                         request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
     }
     /* ### End External Namespaces */
 
+    response->resultsSize = size;
+    for(size_t i = 0;i < size;i++){
+        if(!isExternal[i])
+            browse(server->nodestore, &request->nodesToBrowse[i],
+                   request->requestedMaxReferencesPerNode, &response->results[i]);
+    }
+}
+
+/***********************/
+/* TranslateBrowsePath */
+/***********************/
+
+static UA_StatusCode
+walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_RelativePath *path,
+               UA_Int32 pathindex, UA_BrowsePathTarget **targets, UA_Int32 *targets_size,
+               UA_Int32 *target_count)
+{
+    const UA_RelativePathElement *elem = &path->elements[pathindex];
+    if(elem->targetName.name.length == -1)
+        return UA_STATUSCODE_BADBROWSENAMEINVALID;
 
-    response->resultsSize = request->nodesToBrowseSize;
-    for(UA_Int32 i = 0;i < request->nodesToBrowseSize;i++){
-        if(!isExternal[i]) {
-            getBrowseResult(server->nodestore, &request->nodesToBrowse[i],
-                        request->requestedMaxReferencesPerNode, &response->results[i]);
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_NodeId *reftypes;
+    size_t reftypes_count = 1; // all_refs or no subtypes => 1
+    UA_Boolean all_refs = UA_FALSE;
+    if(UA_NodeId_isNull(&elem->referenceTypeId))
+        all_refs = UA_TRUE;
+    else if(!elem->includeSubtypes)
+        reftypes = (UA_NodeId*)(uintptr_t)&elem->referenceTypeId; // ptr magic due to const cast
+    else
+        retval = findsubtypes(server->nodestore, &elem->referenceTypeId, &reftypes, &reftypes_count);
+
+    for(UA_Int32 i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; i++) {
+        UA_Boolean match = all_refs;
+        for(size_t j = 0; j < reftypes_count && !match; j++) {
+            if(node->references[i].isInverse == elem->isInverse &&
+               UA_NodeId_equal(&node->references[i].referenceTypeId, &reftypes[j]))
+                match = UA_TRUE;
+        }
+        if(!match)
+            continue;
+
+        // get the node, todo: expandednodeid
+        const UA_Node *next = UA_NodeStore_get(server->nodestore, &node->references[i].targetId.nodeId);
+        if(!next)
+            continue;
+
+        // test the browsename
+        if(elem->targetName.namespaceIndex != next->browseName.namespaceIndex ||
+           !UA_String_equal(&elem->targetName.name, &next->browseName.name)) {
+            UA_NodeStore_release(next);
+            continue;
+        }
+
+        if(pathindex + 1 < path->elementsSize) {
+            // recursion if the path is longer
+            retval = walkBrowsePath(server, session, next, path, pathindex + 1,
+                                    targets, targets_size, target_count);
+            UA_NodeStore_release(next);
+        } else {
+            // add the browsetarget
+            if(*target_count >= *targets_size) {
+                UA_BrowsePathTarget *newtargets;
+                newtargets = UA_realloc(targets, sizeof(UA_BrowsePathTarget) * (*targets_size) * 2);
+                if(!newtargets) {
+                    retval = UA_STATUSCODE_BADOUTOFMEMORY;
+                    UA_NodeStore_release(next);
+                    break;
+                }
+                *targets = newtargets;
+                *targets_size *= 2;
+            }
+
+            UA_BrowsePathTarget *res = *targets;
+            UA_ExpandedNodeId_init(&res[*target_count].targetId);
+            retval = UA_NodeId_copy(&next->nodeId, &res[*target_count].targetId.nodeId);
+            UA_NodeStore_release(next);
+            if(retval != UA_STATUSCODE_GOOD)
+                break;
+            res[*target_count].remainingPathIndex = UA_UINT32_MAX;
+            *target_count += 1;
         }
     }
+
+    if(!all_refs && elem->includeSubtypes)
+        UA_Array_delete(reftypes, &UA_TYPES[UA_TYPES_NODEID], (UA_Int32)reftypes_count);
+    return retval;
+}
+
+static void translateBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path,
+                                UA_BrowsePathResult *result) {
+    if(path->relativePath.elementsSize <= 0) {
+        result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
+        return;
+    }
+        
+    UA_Int32 arraySize = 10;
+    result->targets = UA_malloc(sizeof(UA_BrowsePathTarget) * arraySize);
+    if(!result->targets) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
+    }
+    result->targetsSize = 0;
+    const UA_Node *firstNode = UA_NodeStore_get(server->nodestore, &path->startingNode);
+    if(!firstNode) {
+        result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
+        UA_free(result->targets);
+        result->targets = UA_NULL;
+        return;
+    }
+    result->statusCode = walkBrowsePath(server, session, firstNode, &path->relativePath, 0,
+                                        &result->targets, &arraySize, &result->targetsSize);
+    UA_NodeStore_release(firstNode);
+    if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD)
+        result->statusCode = UA_STATUSCODE_BADNOMATCH;
+    if(result->statusCode != UA_STATUSCODE_GOOD) {
+        UA_Array_delete(result->targets, &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], result->targetsSize);
+        result->targets = UA_NULL;
+        result->targetsSize = -1;
+    }
 }
 
 void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
@@ -284,5 +377,36 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
 
     response->resultsSize = request->browsePathsSize;
     for(UA_Int32 i = 0;i < response->resultsSize;i++)
-        response->results[i].statusCode = UA_STATUSCODE_BADNOMATCH; //FIXME: implement
+        translateBrowsePath(server, session, &request->browsePaths[i], &response->results[i]);
+}
+
+void Service_RegisterNodes(UA_Server *server, UA_Session *session,
+                                           const UA_RegisterNodesRequest *request,
+                                           UA_RegisterNodesResponse *response) {
+
+	//TODO: hang the nodeids to the session if really needed
+	response->responseHeader.timestamp = UA_DateTime_now();
+	response->registeredNodeIdsSize = request->nodesToRegisterSize;
+	response->registeredNodeIds = request->nodesToRegister;
+	if(request->nodesToRegisterSize==0){
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+	}
+	if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) || !UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken) ){
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
+	}
+
+}
+
+void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
+                                           const UA_UnregisterNodesRequest *request,
+                                           UA_UnregisterNodesResponse *response) {
+
+	//TODO: remove the nodeids from the session if really needed
+	response->responseHeader.timestamp = UA_DateTime_now();
+	if(request->nodesToUnregisterSize==0){
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+	}
+	if(UA_NodeId_equal(&request->requestHeader.authenticationToken, &UA_NODEID_NULL) || !UA_NodeId_equal(&request->requestHeader.authenticationToken, &session->authenticationToken) ){
+		response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
+	}
 }

+ 9 - 7
src/server/ua_session_manager.c

@@ -14,24 +14,26 @@ struct session_list_entry {
 };
 
 UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt32 maxSessionCount,
-                                    UA_UInt32 sessionTimeout, UA_UInt32 startSessionId) {
+                                    UA_UInt32 maxSessionLifeTime, UA_UInt32 startSessionId) {
     LIST_INIT(&sessionManager->sessions);
     sessionManager->maxSessionCount = maxSessionCount;
     sessionManager->lastSessionId   = startSessionId;
-    sessionManager->sessionTimeout  = sessionTimeout;
+    sessionManager->maxSessionLifeTime  = maxSessionLifeTime;
     sessionManager->currentSessionCount = 0;
     return UA_STATUSCODE_GOOD;
 }
 
 void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager) {
-    struct session_list_entry *current = LIST_FIRST(&sessionManager->sessions);
-    while(current) {
+    struct session_list_entry *current;
+    struct session_list_entry *next = LIST_FIRST(&sessionManager->sessions);
+    while(next) {
+        current = next;
+        next = LIST_NEXT(current, pointers);
         LIST_REMOVE(current, pointers);
         if(current->session.channel)
             current->session.channel->session = UA_NULL; // the channel is no longer attached to a session
         UA_Session_deleteMembers(&current->session);
         UA_free(current);
-        current = LIST_FIRST(&sessionManager->sessions);
     }
 }
 
@@ -85,7 +87,7 @@ UA_StatusCode UA_SessionManager_getSessionByToken(UA_SessionManager *sessionMana
 
 /** Creates and adds a session. */
 UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChannel *channel,
-                                              UA_Session **session) {
+												const UA_CreateSessionRequest *request, UA_Session **session) {
     if(sessionManager->currentSessionCount >= sessionManager->maxSessionCount)
         return UA_STATUSCODE_BADTOOMANYSESSIONS;
 
@@ -100,7 +102,7 @@ UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager,
                                                          .identifierType = UA_NODEIDTYPE_NUMERIC,
                                                          .identifier.numeric = sessionManager->lastSessionId };
     newentry->session.channel = channel;
-    newentry->session.timeout = 3600 * 1000; // 1h
+    newentry->session.timeout = (request->requestedSessionTimeout <= sessionManager->maxSessionLifeTime && request->requestedSessionTimeout>0) ? request->requestedSessionTimeout : sessionManager->maxSessionLifeTime;
     UA_Session_setExpirationDate(&newentry->session);
 
     sessionManager->currentSessionCount++;

+ 2 - 3
src/server/ua_session_manager.h

@@ -12,16 +12,15 @@ typedef struct UA_SessionManager {
     UA_Int32     lastSessionId;
     UA_UInt32    currentSessionCount;
     UA_DateTime  maxSessionLifeTime;
-    UA_DateTime  sessionTimeout;
 } UA_SessionManager;
 
 UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt32 maxSessionCount,
-                                    UA_UInt32 sessionLifetime, UA_UInt32 startSessionId);
+                                    UA_UInt32 maxSessionLifeTime, UA_UInt32 startSessionId);
 
 void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager);
 
 UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager,
-                                              UA_SecureChannel *channel, UA_Session **session);
+                                              UA_SecureChannel *channel, const UA_CreateSessionRequest *request, UA_Session **session);
 
 UA_StatusCode UA_SessionManager_removeSession(UA_SessionManager *sessionManager,
                                               const UA_NodeId *sessionId);

+ 8 - 7
src/ua_config.h.in

@@ -1,3 +1,6 @@
+#ifndef UA_CONFIG_H_
+#define UA_CONFIG_H_
+
 /* Buid options and configuration (set by cmake) */
 
 #define UA_LOGLEVEL ${UA_LOGLEVEL}
@@ -12,14 +15,10 @@
 #      define UA_EXPORT __declspec(dllexport)
 #    endif
 #  else
-#    ifndef STATIC_LINKING
-#      ifdef __GNUC__
-#        define UA_EXPORT __attribute__ ((dllimport))
-#      else
-#        define UA_EXPORT __declspec(dllimport)
-#      endif
+#    ifdef __GNUC__
+#      define UA_EXPORT __attribute__ ((dllexport))
 #    else
-#      define UA_EXPORT
+#      define UA_EXPORT __declspec(dllimport)
 #    endif
 #  endif
 #else
@@ -29,3 +28,5 @@
 #    define UA_EXPORT
 #  endif
 #endif
+
+#endif /* UA_CONFIG_H_ */

+ 2 - 6
src/ua_securechannel.c

@@ -1,11 +1,7 @@
-#include "ua_securechannel.h"
 #include "ua_util.h"
+#include "ua_securechannel.h"
 #include "ua_statuscodes.h"
 
-#ifdef UA_MULTITHREADING
-#include <urcu/uatomic.h>
-#endif
-
 // max message size is 64k
 const UA_ConnectionConfig UA_ConnectionConfig_standard =
     {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
@@ -58,7 +54,7 @@ UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UIn
     return UA_STATUSCODE_GOOD;
 }
 
-UA_Int32 UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) {
+UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) {
     //TODO review checking of sequence
     if(channel->sequenceNumber+1  != sequenceNumber)
         return UA_STATUSCODE_BADINTERNALERROR;

+ 2 - 2
src/ua_securechannel.h

@@ -33,8 +33,8 @@ void UA_SecureChannel_delete(UA_SecureChannel *channel);
 UA_Boolean UA_SecureChannel_compare(UA_SecureChannel *sc1, UA_SecureChannel *sc2);
 
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce);
-UA_Int32 UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId);
-UA_Int32 UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber);
+UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId);
+UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber);
 
 void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session);

+ 1 - 5
src/ua_session.c

@@ -1,11 +1,7 @@
-#include "ua_session.h"
 #include "ua_util.h"
+#include "ua_session.h"
 #include "ua_statuscodes.h"
 
-#ifdef UA_MULTITHREADING
-#include <urcu/uatomic.h>
-#endif
-
 UA_Session anonymousSession = {
     .clientDescription =  {.applicationUri = {-1, UA_NULL},
                            .productUri = {-1, UA_NULL},

+ 186 - 129
src/ua_types.c

@@ -1,20 +1,4 @@
-#include <stdarg.h> // va_start, va_end
-#include <time.h>
-#include <stdio.h> // printf
-#include <string.h> // strlen
-#define __USE_POSIX
-#include <stdlib.h> // malloc, free, rand
-
 #include "ua_util.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#define RAND(SEED) (UA_UInt32)rand()
-#else
-#include <sys/time.h>
-#define RAND(SEED) (UA_UInt32)rand_r(SEED)
-#endif
-
 #include "ua_types.h"
 #include "ua_statuscodes.h"
 #include "ua_types_generated.h"
@@ -104,7 +88,8 @@ void UA_String_init(UA_String *p) {
 
 UA_TYPE_DELETE_DEFAULT(UA_String)
 void UA_String_deleteMembers(UA_String *p) {
-    UA_free(p->data);
+	if(p->data)
+		UA_free(p->data);
 }
 
 UA_StatusCode UA_String_copy(UA_String const *src, UA_String *dst) {
@@ -119,21 +104,19 @@ UA_StatusCode UA_String_copy(UA_String const *src, UA_String *dst) {
 }
 
 /* The c-string needs to be null-terminated. the string cannot be smaller than zero. */
-UA_Int32 UA_String_copycstring(char const *src, UA_String *dst) {
-    UA_UInt32 length = (UA_UInt32) strlen(src);
+UA_StatusCode UA_String_copycstring(char const *src, UA_String *dst) {
+    UA_String_init(dst);
+    size_t length = (UA_UInt32) strlen(src);
     if(length == 0) {
         dst->length = 0;
         dst->data = UA_NULL;
         return UA_STATUSCODE_GOOD;
     }
     dst->data = UA_malloc(length);
-    if(dst->data != UA_NULL) {
-        UA_memcpy(dst->data, src, length);
-        dst->length = (UA_Int32) (length & ~(1<<31)); // the highest bit is always zero to avoid overflows into negative values
-    } else {
-        dst->length = -1;
+    if(!dst->data)
         return UA_STATUSCODE_BADOUTOFMEMORY;
-    }
+    UA_memcpy(dst->data, src, length);
+    dst->length = length;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -240,7 +223,7 @@ UA_StatusCode UA_DateTime_toString(UA_DateTime atime, UA_String *timeString) {
     timeString->length = 31;
 
     UA_DateTimeStruct tSt = UA_DateTime_toStruct(atime);
-    sprintf((char*)timeString->data, "%2d/%2d/%4d %2d:%2d:%2d.%3d.%3d.%3d", tSt.month, tSt.day, tSt.year,
+    sprintf((char*)timeString->data, "%02d/%02d/%04d %02d:%02d:%02d.%03d.%03d.%03d", tSt.month, tSt.day, tSt.year,
             tSt.hour, tSt.min, tSt.sec, tSt.milliSec, tSt.microSec, tSt.nanoSec);
     return UA_STATUSCODE_GOOD;
 }
@@ -367,7 +350,7 @@ void UA_NodeId_deleteMembers(UA_NodeId *p) {
 }
 
 UA_Boolean UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) {
-    if(n1->namespaceIndex != n2->namespaceIndex)
+	if(n1->namespaceIndex != n2->namespaceIndex || n1->identifierType!=n2->identifierType)
         return UA_FALSE;
 
     switch(n1->identifierType) {
@@ -397,7 +380,7 @@ UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
         break;
 
     case UA_NODEIDTYPE_STRING:
-        if(p->namespaceIndex != 0 || p->identifier.string.length != 0)
+        if(p->namespaceIndex != 0 || p->identifier.string.length > 0)
             return UA_FALSE;
         break;
 
@@ -408,7 +391,7 @@ UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
         break;
 
     case UA_NODEIDTYPE_BYTESTRING:
-        if(p->namespaceIndex != 0 || p->identifier.byteString.length != 0)
+        if(p->namespaceIndex != 0 || p->identifier.byteString.length > 0)
             return UA_FALSE;
         break;
 
@@ -491,7 +474,7 @@ void UA_LocalizedText_init(UA_LocalizedText *p) {
 
 UA_TYPE_NEW_DEFAULT(UA_LocalizedText)
 UA_StatusCode UA_LocalizedText_copycstring(char const *src, UA_LocalizedText *dst) {
-    UA_StatusCode retval = UA_String_copycstring("en", &dst->locale); // TODO: Are language codes upper case?
+    UA_StatusCode retval = UA_String_copycstring("", &dst->locale);
     retval |= UA_String_copycstring(src, &dst->text);
     if(retval) {
         UA_LocalizedText_deleteMembers(dst);
@@ -542,7 +525,7 @@ void UA_DataValue_deleteMembers(UA_DataValue *p) {
 }
 
 void UA_DataValue_init(UA_DataValue *p) {
-    *((UA_Byte*)p) = 0; // zero out the bitfield 
+    *((UA_Byte*)p) = 0; // zero out the bitfield
     p->serverPicoseconds = 0;
     UA_DateTime_init(&p->serverTimestamp);
     p->sourcePicoseconds = 0;
@@ -572,104 +555,182 @@ UA_StatusCode UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst) {
 UA_TYPE_NEW_DEFAULT(UA_Variant)
 void UA_Variant_init(UA_Variant *p) {
     p->storageType = UA_VARIANT_DATA;
-    p->storage.data.arrayLength = -1;  // no element, p->data == UA_NULL
-    p->storage.data.dataPtr = UA_NULL;
-    p->storage.data.arrayDimensions = UA_NULL;
-    p->storage.data.arrayDimensionsSize = -1;
-    UA_NodeId_init(&p->typeId);
-    p->type = UA_NULL;
+    p->arrayLength = -1;
+    p->dataPtr = UA_NULL;
+    p->arrayDimensions = UA_NULL;
+    p->arrayDimensionsSize = -1;
+    p->type = &UA_TYPES[UA_TYPES_BOOLEAN];
 }
 
 UA_TYPE_DELETE_DEFAULT(UA_Variant)
 void UA_Variant_deleteMembers(UA_Variant *p) {
-    UA_NodeId_deleteMembers(&p->typeId);
     if(p->storageType == UA_VARIANT_DATA) {
-        if(p->storage.data.dataPtr) {
-            UA_Array_delete(p->storage.data.dataPtr, p->type, p->storage.data.arrayLength);
-            p->storage.data.dataPtr = UA_NULL;
-            p->storage.data.arrayLength = 0;
+        if(p->dataPtr) {
+            if(p->arrayLength == -1)
+                p->arrayLength = 1;
+            UA_Array_delete(p->dataPtr, p->type, p->arrayLength);
+            p->dataPtr = UA_NULL;
+            p->arrayLength = -1;
         }
-        if(p->storage.data.arrayDimensions) {
-            UA_free(p->storage.data.arrayDimensions);
-            p->storage.data.arrayDimensions = UA_NULL;
+        if(p->arrayDimensions) {
+            UA_free(p->arrayDimensions);
+            p->arrayDimensions = UA_NULL;
         }
     }
 }
 
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
     UA_Variant_init(dst);
-    UA_StatusCode retval = UA_NodeId_copy(&src->typeId, &dst->typeId);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    dst->type = src->type;
-    if(src->storageType == UA_VARIANT_DATASOURCE) {
-        dst->storageType = UA_VARIANT_DATASOURCE;
-        dst->storage = src->storage;
-        return UA_STATUSCODE_GOOD;
-    }
-    
-    UA_VariantData *dstdata = &dst->storage.data;
-    const UA_VariantData *srcdata = &src->storage.data;
-    dst->storageType = UA_VARIANT_DATA;
-    retval |= UA_Array_copy(srcdata->dataPtr, &dstdata->dataPtr, src->type, srcdata->arrayLength);
+    UA_Int32 tmp = src->arrayLength;
+    if(src->arrayLength == -1 && src->dataPtr)
+        tmp = 1;
+    UA_StatusCode retval = UA_Array_copy(src->dataPtr, &dst->dataPtr, src->type, tmp);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Variant_deleteMembers(dst);
         UA_Variant_init(dst);
         return retval;
     }
-    dstdata->arrayLength = srcdata->arrayLength;
+    dst->arrayLength = src->arrayLength;
+    dst->type = src->type;
+    dst->storageType = UA_VARIANT_DATA;
 
-    if(srcdata->arrayDimensions) {
-        retval |= UA_Array_copy(srcdata->arrayDimensions, (void **)&dstdata->arrayDimensions, &UA_TYPES[UA_TYPES_INT32],
-                                srcdata->arrayDimensionsSize);
+    if(src->arrayDimensions) {
+        retval |= UA_Array_copy(src->arrayDimensions, (void **)&dst->arrayDimensions,
+                                &UA_TYPES[UA_TYPES_INT32], src->arrayDimensionsSize);
         if(retval != UA_STATUSCODE_GOOD) {
             UA_Variant_deleteMembers(dst);
             UA_Variant_init(dst);
+            return retval;
         }
+        dst->arrayDimensionsSize = src->arrayDimensionsSize;
     }
-    dstdata->arrayDimensionsSize = srcdata->arrayDimensionsSize;
 
     return retval;
 }
 
-UA_StatusCode UA_Variant_setValue(UA_Variant *v, void *p, UA_UInt16 typeIndex) {
-    return UA_Variant_setArray(v, p, 1, typeIndex);
-}
+UA_StatusCode UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range) {
+    UA_Variant_init(dst);
+
+    // test the integrity of the variant dimensions
+    UA_Int32 dims_count = 1;
+    const UA_Int32 *dims = &src->arrayLength; // default: the array has only one dimension
+    if(src->arrayDimensionsSize > 0) {
+        dims_count = src->arrayDimensionsSize;
+        dims = src->arrayDimensions;
+        UA_Int32 elements = 1;
+        for(UA_Int32 i = 0; i < dims_count; i++)
+            elements *= dims[i];
+        if(elements != src->arrayLength)
+            return UA_STATUSCODE_BADINTERNALERROR;
+    }
 
-UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const void *p, UA_UInt16 typeIndex) {
-    if(typeIndex >= UA_TYPES_COUNT)
+    // test the integrity of the range and count objects
+    size_t count = 1;
+    if(range.dimensionsSize != dims_count)
         return UA_STATUSCODE_BADINTERNALERROR;
-    const UA_DataType *type = &UA_TYPES[typeIndex];
+    for(UA_Int32 i = 0; i < range.dimensionsSize; i++) {
+        if(range.dimensions[i].min > range.dimensions[i].max)
+            return UA_STATUSCODE_BADINDEXRANGEINVALID;
+        if(range.dimensions[i].max > (UA_UInt32)(dims[i]))
+            return UA_STATUSCODE_BADINDEXRANGENODATA;
+        count *= (range.dimensions[i].max - range.dimensions[i].min) + 1;
+    }
+
+    dst->dataPtr = UA_malloc(src->type->memSize * count);
+    if(!dst->dataPtr)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    
+    // copy a subset of the tensor with as few calls as possible.
+    // shift from copying single elements to contiguous blocks
+    size_t elem_size = src->type->memSize;
+    uintptr_t nextsrc = (uintptr_t)src->dataPtr; // the start ptr of the next copy operation
+    size_t contiguous_elems = src->arrayLength; // the length of the copy operation
+    ptrdiff_t jump_length = elem_size * dims[0]; // how far to jump until the next contiguous copy
+    size_t copy_count = count; // how often to copy
+
+    size_t running_dimssize = 1; // how big is a contiguous block for the dimensions k_max to k
+    UA_Boolean found_contiguous = UA_FALSE;
+    for(UA_Int32 k = dims_count - 1; k >= 0; k--) {
+        if(!found_contiguous) {
+            if(range.dimensions[k].min != 0 || range.dimensions[k].max + 1 != (UA_UInt32)dims[k]) {
+                found_contiguous = UA_TRUE;
+                contiguous_elems = (range.dimensions[k].max - range.dimensions[k].min + 1) * running_dimssize;
+                jump_length = ((dims[k] * running_dimssize) - contiguous_elems) * elem_size;
+                copy_count /= range.dimensions[k].max - range.dimensions[k].min + 1;
+            } else
+                copy_count /= dims[k];
+        } 
+        nextsrc += running_dimssize * range.dimensions[k].min * elem_size;
+        running_dimssize *= dims[k];
+    }
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    uintptr_t nextdst = (uintptr_t)dst->dataPtr;
+    size_t copied = 0;
+    for(size_t i = 0; i < copy_count; i++) {
+        if(src->type->fixedSize) {
+            memcpy((void*)nextdst, (void*)nextsrc, elem_size * contiguous_elems);
+        } else {
+            for(size_t j = 0; j < contiguous_elems; j++)
+                retval = UA_copy((const void*)(nextsrc + (j * elem_size)), (void*)(nextdst + (j * elem_size)), src->type);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_Array_delete(dst->dataPtr, src->type, copied);
+                return retval;
+            }
+            copied += contiguous_elems;
+        }
+        nextdst += elem_size * contiguous_elems;
+        nextsrc += jump_length;
+    }
+
+    if(src->arrayDimensionsSize > 0) {
+        retval = UA_Array_copy(dims, (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_INT32], dims_count);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_Array_delete(dst->dataPtr, src->type, copied);
+            return retval;
+        }
+        for(UA_Int32 k = 0; k < dims_count; k++) {
+            dst->arrayDimensions[k] = range.dimensions[k].max - range.dimensions[k].min + 1;
+        }
+        dst->arrayDimensionsSize = dims_count;
+    }
+    dst->arrayLength = count;
+    dst->type = src->type;
+    dst->storageType = UA_VARIANT_DATA;
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode UA_Variant_setScalar(UA_Variant *v, void *p, const UA_DataType *type) {
+    return UA_Variant_setArray(v, p, -1, type);
+}
+
+UA_StatusCode UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type) {
     void *new = UA_malloc(type->memSize);
     if(!new)
         return UA_STATUSCODE_BADOUTOFMEMORY;
-    UA_StatusCode retval = UA_copy(p, new, &UA_TYPES[typeIndex]);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    return UA_Variant_setArray(v, new, 1, typeIndex);
+    UA_StatusCode retval = UA_copy(p, new, type);
+	if(retval != UA_STATUSCODE_GOOD) {
+		UA_delete(new, type);
+		return retval;
+	}
+    return UA_Variant_setArray(v, new, -1, type);
 }
 
 UA_StatusCode UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 noElements,
-                                  UA_UInt16 typeIndex) {
-    if(typeIndex >= UA_TYPES_COUNT)
-        return UA_STATUSCODE_BADINTERNALERROR;
-
-    v->type = &UA_TYPES[typeIndex];
-    v->typeId = UA_NODEID_STATIC(0, UA_TYPES_IDS[typeIndex]);
-    v->storage.data.arrayLength = noElements;
-    v->storage.data.dataPtr = array;
+                                  const UA_DataType *type) {
+    v->type = type;
+    v->arrayLength = noElements;
+    v->dataPtr = array;
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_Variant_copySetArray(UA_Variant *v, const void *array, UA_Int32 noElements,
-                                      UA_UInt16 typeIndex) {
-    if(typeIndex >= UA_TYPES_COUNT)
-        return UA_STATUSCODE_BADINTERNALERROR;
+UA_StatusCode UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32 noElements,
+                                      const UA_DataType *type) {
     void *new;
-    UA_StatusCode retval = UA_Array_copy(array, &new, &UA_TYPES[typeIndex], noElements);
+    UA_StatusCode retval = UA_Array_copy(array, &new, type, noElements);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
-    return UA_Variant_setArray(v, new, noElements, typeIndex);
+    return UA_Variant_setArray(v, new, noElements, type);
 }
 
 /* DiagnosticInfo */
@@ -684,7 +745,7 @@ void UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
 
 UA_TYPE_NEW_DEFAULT(UA_DiagnosticInfo)
 void UA_DiagnosticInfo_init(UA_DiagnosticInfo *p) {
-    *(UA_Byte*)p = 0;
+	*((UA_Byte*)p) = 0; // zero out the bitfield
     p->symbolicId          = 0;
     p->namespaceUri        = 0;
     p->localizedText       = 0;
@@ -696,19 +757,24 @@ void UA_DiagnosticInfo_init(UA_DiagnosticInfo *p) {
 
 UA_StatusCode UA_DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst) {
     UA_DiagnosticInfo_init(dst);
-    *(UA_Byte*)dst = *(const UA_Byte*)src; // bitfields
-    UA_StatusCode retval = UA_String_copy(&src->additionalInfo, &dst->additionalInfo);
-    retval |= UA_StatusCode_copy(&src->innerStatusCode, &dst->innerStatusCode);
+    *((UA_Byte*)dst) = *((const UA_Byte*)src); // the bitfield
+    
+    dst->symbolicId = src->symbolicId;
+    dst->namespaceUri = src->namespaceUri;
+    dst->localizedText = src->localizedText;
+    dst->locale = src->locale;
+    dst->innerStatusCode = src->innerStatusCode;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(src->hasAdditionalInfo)
+       retval = UA_String_copy(&src->additionalInfo, &dst->additionalInfo);
     if(src->hasInnerDiagnosticInfo && src->innerDiagnosticInfo) {
-        if((dst->innerDiagnosticInfo = UA_malloc(sizeof(UA_DiagnosticInfo))))
+        if((dst->innerDiagnosticInfo = UA_malloc(sizeof(UA_DiagnosticInfo)))) {
             retval |= UA_DiagnosticInfo_copy(src->innerDiagnosticInfo, dst->innerDiagnosticInfo);
+            dst->hasInnerDiagnosticInfo = src->hasInnerDiagnosticInfo;
+        }
         else
             retval |= UA_STATUSCODE_BADOUTOFMEMORY;
     }
-    dst->locale = src->locale;
-    dst->localizedText = src->localizedText;
-    dst->namespaceUri = src->namespaceUri;
-    dst->symbolicId = src->symbolicId;
     if(retval) {
         UA_DiagnosticInfo_deleteMembers(dst);
         UA_DiagnosticInfo_init(dst);
@@ -782,9 +848,6 @@ void UA_init(void *p, const UA_DataType *dataType) {
         case UA_TYPES_EXPANDEDNODEID:
             UA_ExpandedNodeId_init((UA_ExpandedNodeId*)ptr);
             break;
-        case UA_TYPES_QUALIFIEDNAME:
-            UA_QualifiedName_init((UA_QualifiedName*)ptr);
-            break;
         case UA_TYPES_LOCALIZEDTEXT:
             UA_LocalizedText_init((UA_LocalizedText*)ptr);
             break;
@@ -800,12 +863,8 @@ void UA_init(void *p, const UA_DataType *dataType) {
         case UA_TYPES_DIAGNOSTICINFO:
             UA_DiagnosticInfo_init((UA_DiagnosticInfo*)ptr);
             break;
-        case UA_TYPES_STRING:
-        case UA_TYPES_BYTESTRING:
-        case UA_TYPES_XMLELEMENT:
-            UA_String_init((UA_String*)ptr);
-            break;
         default:
+            // QualifiedName, LocalizedText and strings are treated as structures, also
             UA_init((void*)ptr, &UA_TYPES[member->memberTypeIndex]);
         }
         ptr += UA_TYPES[member->memberTypeIndex].memSize;
@@ -901,9 +960,6 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *dataType) {
         case UA_TYPES_EXPANDEDNODEID:
             retval |= UA_ExpandedNodeId_copy((const UA_ExpandedNodeId*)ptrs, (UA_ExpandedNodeId*)ptrd);
             break;
-        case UA_TYPES_QUALIFIEDNAME:
-            retval |= UA_QualifiedName_copy((const UA_QualifiedName*)ptrs, (UA_QualifiedName*)ptrd);
-            break;
         case UA_TYPES_LOCALIZEDTEXT:
             retval |= UA_LocalizedText_copy((const UA_LocalizedText*)ptrs, (UA_LocalizedText*)ptrd);
             break;
@@ -919,12 +975,8 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *dataType) {
         case UA_TYPES_DIAGNOSTICINFO:
             retval |= UA_DiagnosticInfo_copy((const UA_DiagnosticInfo*)ptrs, (UA_DiagnosticInfo*)ptrd);
             break;
-        case UA_TYPES_STRING:
-        case UA_TYPES_BYTESTRING:
-        case UA_TYPES_XMLELEMENT:
-            retval |= UA_String_copy((const UA_String*)ptrs, (UA_String*)ptrd);
-            break;
         default:
+            // QualifiedName, LocalizedText and strings are treated as structures, also
             retval |= UA_copy((const void *)ptrs, (void*)ptrd, memberType);
         }
         ptrs += memberType->memSize;
@@ -965,20 +1017,29 @@ void UA_deleteMembers(void *p, const UA_DataType *dataType) {
             ptr += memberType->memSize;
             continue;
         }
-        
+
         switch(member->memberTypeIndex) {
-            // the following types have a fixed size.
-            /* UA_BOOLEAN, UA_SBYTE, UA_BYTE, UA_INT16, UA_UINT16, UA_INT32, UA_UINT32, */
-            /* UA_STATUSCODE, UA_FLOAT, UA_INT64, UA_UINT64, UA_DOUBLE, UA_DATETIME, UA_GUID */
+        case UA_TYPES_BOOLEAN:
+        case UA_TYPES_SBYTE:
+        case UA_TYPES_BYTE:
+        case UA_TYPES_INT16:
+        case UA_TYPES_UINT16:
+        case UA_TYPES_INT32:
+        case UA_TYPES_UINT32:
+        case UA_TYPES_STATUSCODE:
+        case UA_TYPES_FLOAT:
+        case UA_TYPES_INT64:
+        case UA_TYPES_UINT64:
+        case UA_TYPES_DOUBLE:
+        case UA_TYPES_DATETIME:
+        case UA_TYPES_GUID:
+            break;
         case UA_TYPES_NODEID:
             UA_NodeId_deleteMembers((UA_NodeId*)ptr);
             break;
         case UA_TYPES_EXPANDEDNODEID:
             UA_ExpandedNodeId_deleteMembers((UA_ExpandedNodeId*)ptr);
             break;
-        case UA_TYPES_QUALIFIEDNAME:
-            UA_QualifiedName_deleteMembers((UA_QualifiedName*)ptr);
-            break;
         case UA_TYPES_LOCALIZEDTEXT:
             UA_LocalizedText_deleteMembers((UA_LocalizedText*)ptr);
             break;
@@ -994,12 +1055,8 @@ void UA_deleteMembers(void *p, const UA_DataType *dataType) {
         case UA_TYPES_DIAGNOSTICINFO:
             UA_DiagnosticInfo_deleteMembers((UA_DiagnosticInfo*)ptr);
             break;
-        case UA_TYPES_STRING:
-        case UA_TYPES_BYTESTRING:
-        case UA_TYPES_XMLELEMENT:
-            UA_String_deleteMembers((UA_String*)ptr);
-            break;
         default:
+            // QualifiedName, LocalizedText and strings are treated as structures, also
             UA_deleteMembers((void*)ptr, memberType);
         }
         ptr += memberType->memSize;
@@ -1022,8 +1079,11 @@ void* UA_Array_new(const UA_DataType *dataType, UA_Int32 noElements) {
     if((UA_Int32)dataType->memSize * noElements < 0 || dataType->memSize * noElements > MAX_ARRAY_SIZE )
         return UA_NULL;
 
+    if(dataType->fixedSize)
+        return calloc(noElements, dataType->memSize);
+
     void *p = malloc(dataType->memSize * (size_t)noElements);
-    if(!p || dataType->fixedSize) // datatypes of fixed size are not initialized.
+    if(!p)
         return p;
 
     uintptr_t ptr = (uintptr_t)p;
@@ -1064,9 +1124,6 @@ UA_StatusCode UA_Array_copy(const void *src, void **dst, const UA_DataType *data
 }
 
 void UA_Array_delete(void *p, const UA_DataType *dataType, UA_Int32 noElements) {
-    if(noElements <= 0 || !p)
-        return;
-
     if(!dataType->fixedSize) {
         uintptr_t ptr = (uintptr_t)p;
         for(UA_Int32 i = 0; i<noElements; i++) {

+ 215 - 252
src/ua_types_encoding_binary.c

@@ -1,6 +1,5 @@
-#include <string.h>
-#include "ua_types_encoding_binary.h"
 #include "ua_util.h"
+#include "ua_types_encoding_binary.h"
 #include "ua_statuscodes.h"
 #include "ua_types_generated.h"
 
@@ -24,7 +23,7 @@ UA_StatusCode UA_Boolean_encodeBinary(const UA_Boolean *src, UA_ByteString *dst,
     if(*offset + sizeof(UA_Boolean) > (size_t)dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
     dst->data[*offset] = (UA_Byte)*src;
-    (*offset)++;
+    ++(*offset);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -32,7 +31,7 @@ UA_StatusCode UA_Boolean_decodeBinary(UA_ByteString const *src, size_t *offset,
     if(*offset + sizeof(UA_Boolean) > (size_t)src->length )
         return UA_STATUSCODE_BADDECODINGERROR;
     *dst = (src->data[*offset] > 0) ? UA_TRUE : UA_FALSE;
-    (*offset)++;
+    ++(*offset);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -45,7 +44,7 @@ UA_StatusCode UA_Byte_encodeBinary(const UA_Byte *src, UA_ByteString *dst, size_
     if(*offset + sizeof(UA_Byte) > (size_t)dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
     dst->data[*offset] = (UA_Byte)*src;
-    (*offset)++;
+    ++(*offset);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -53,7 +52,7 @@ UA_StatusCode UA_Byte_decodeBinary(UA_ByteString const *src, size_t *offset, UA_
     if(*offset + sizeof(UA_Byte) > (size_t)src->length )
         return UA_STATUSCODE_BADDECODINGERROR;
     *dst = src->data[*offset];
-    (*offset)++;
+    ++(*offset);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -65,16 +64,25 @@ UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt16)
 UA_StatusCode UA_UInt16_encodeBinary(UA_UInt16 const *src, UA_ByteString * dst, size_t *offset) {
     if(*offset + sizeof(UA_UInt16) > (size_t)dst->length )
         return UA_STATUSCODE_BADENCODINGERROR;
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x00FF) >> 0);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0xFF00) >> 8);
+    UA_UInt16 *dst_ptr = (UA_UInt16*)&dst->data[*offset];
+#ifndef _WIN32
+    *dst_ptr = htole16(*src);
+#else
+    *dst_ptr = *src;
+#endif
+    *offset += 2;
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_UInt16_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt16 * dst) {
+UA_StatusCode UA_UInt16_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt16 *dst) {
     if(*offset + sizeof(UA_UInt16) > (size_t)src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-    *dst =  (UA_UInt16)src->data[(*offset)++] << 0;
-    *dst |= (UA_UInt16)src->data[(*offset)++] << 8;
+    UA_UInt16 value = *((UA_UInt16*)&src->data[*offset]);
+#ifndef _WIN32
+    value = le16toh(value);
+#endif
+    *dst = value;
+    *offset += 2;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -86,20 +94,25 @@ UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt32)
 UA_StatusCode UA_UInt32_encodeBinary(UA_UInt32 const *src, UA_ByteString * dst, size_t *offset) {
     if(*offset + sizeof(UA_UInt32) > (size_t)dst->length )
         return UA_STATUSCODE_BADENCODINGERROR;
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x000000FF) >> 0);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x0000FF00) >> 8);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x00FF0000) >> 16);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0xFF000000) >> 24);
+    UA_UInt32 *dst_ptr = (UA_UInt32*)&dst->data[*offset];
+#ifndef _WIN32
+    *dst_ptr = htole32(*src);
+#else
+    *dst_ptr = *src;
+#endif
+    *offset += 4;
     return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode UA_UInt32_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt32 * dst) {
     if(*offset + sizeof(UA_UInt32) > (size_t)src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-    *dst  = (UA_UInt32)src->data[(*offset)++] << 0;
-    *dst |= (UA_UInt32)src->data[(*offset)++] << 8;
-    *dst |= (UA_UInt32)src->data[(*offset)++] << 16;
-    *dst |= (UA_UInt32)src->data[(*offset)++] << 24;
+    UA_UInt32 value = *((UA_UInt32*)&src->data[*offset]);
+#ifndef _WIN32
+    value = le32toh(value);
+#endif
+    *dst = value;
+    *offset += 4;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -111,95 +124,74 @@ UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_UInt64)
 UA_StatusCode UA_UInt64_encodeBinary(UA_UInt64 const *src, UA_ByteString *dst, size_t *offset) {
     if(*offset + sizeof(UA_UInt64) > (size_t)dst->length )
         return UA_STATUSCODE_BADENCODINGERROR;
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x00000000000000FF) >> 0);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x000000000000FF00) >> 8);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x0000000000FF0000) >> 16);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x00000000FF000000) >> 24);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x000000FF00000000) >> 32);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x0000FF0000000000) >> 40);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0x00FF000000000000) >> 48);
-    dst->data[(*offset)++] = (UA_Byte)((*src & 0xFF00000000000000) >> 56);
+    UA_UInt64 *dst_ptr = (UA_UInt64*)&dst->data[*offset];
+#ifndef _WIN32
+    *dst_ptr = htole64(*src);
+#else
+    *dst_ptr = *src;
+#endif
+    *offset += 8;
     return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode UA_UInt64_decodeBinary(UA_ByteString const *src, size_t *offset, UA_UInt64 * dst) {
     if(*offset + sizeof(UA_UInt64) > (size_t)src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-    *dst  = (UA_UInt64)src->data[(*offset)++] << 0;
-    *dst |= (UA_UInt64)src->data[(*offset)++] << 8;
-    *dst |= (UA_UInt64)src->data[(*offset)++] << 16;
-    *dst |= (UA_UInt64)src->data[(*offset)++] << 24;
-    *dst |= (UA_UInt64)src->data[(*offset)++] << 32;
-    *dst |= (UA_UInt64)src->data[(*offset)++] << 40;
-    *dst |= (UA_UInt64)src->data[(*offset)++] << 48;
-    *dst |= (UA_UInt64)src->data[(*offset)++] << 56;
+    UA_UInt64 value = *((UA_UInt64*)&src->data[*offset]);
+#ifndef _WIN32
+    value = le64toh(value);
+#endif
+    *dst = value;
+    *offset += 8;
     return UA_STATUSCODE_GOOD;
 }
 
 /* Float */
-UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_Float)
-// FIXME: Implement NaN, Inf and Zero(s)
-UA_Byte UA_FLOAT_ZERO[] = { 0x00, 0x00, 0x00, 0x00 };
-UA_StatusCode UA_Float_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Float * dst) {
-    if(*offset + sizeof(UA_Float) > (size_t)src->length )
-        return UA_STATUSCODE_BADDECODINGERROR;
-    UA_Float mantissa;
-    UA_UInt32 biasedExponent;
-    UA_Float sign;
-    if(memcmp(&src->data[*offset], UA_FLOAT_ZERO, 4) == 0)
-        return UA_Int32_decodeBinary(src, offset, (UA_Int32 *)dst);
-    mantissa = (UA_Float)(src->data[*offset] & 0xFF);                                   // bits 0-7
-    mantissa = (mantissa / (UA_Float)256.0 ) + (UA_Float)(src->data[*offset+1] & 0xFF); // bits 8-15
-    mantissa = (mantissa / (UA_Float)256.0 ) + (UA_Float)(src->data[*offset+2] & 0x7F); // bits 16-22
-    biasedExponent  = (src->data[*offset+2] & 0x80) >>  7;                              // bits 23
-    biasedExponent |= (UA_UInt32)(src->data[*offset+3] & 0x7F) <<  1;                   // bits 24-30
-    sign = ( src->data[*offset+ 3] & 0x80 ) ? -1.0 : 1.0;                               // bit 31
-    if(biasedExponent >= 127)
-        *dst = (UA_Float)sign * (1 << (biasedExponent-127)) * (1.0 + mantissa / 128.0 );
-    else
-        *dst = (UA_Float)sign * 2.0 * (1.0 + mantissa / 128.0 ) / ((UA_Float)(biasedExponent-127));
-    *offset += 4;
-    return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode UA_Float_encodeBinary(UA_Float const *src, UA_ByteString * dst, size_t *offset) {
-    return UA_Int32_encodeBinary((const UA_Int32 *)src, dst, offset);
-}
+/* In case that the float endiannes is different from the integer endianness (very unlikely on
+   modern cpus), use the following code:
+
+   UA_Byte UA_FLOAT_ZERO[] = { 0x00, 0x00, 0x00, 0x00 };
+   UA_Float mantissa;
+   UA_UInt32 biasedExponent;
+   UA_Float sign;
+   if(memcmp(&src->data[*offset], UA_FLOAT_ZERO, 4) == 0)
+       return UA_Int32_decodeBinary(src, offset, (UA_Int32 *)dst);
+   mantissa = (UA_Float)(src->data[*offset] & 0xFF);                                   // bits 0-7
+   mantissa = (mantissa / (UA_Float)256.0 ) + (UA_Float)(src->data[*offset+1] & 0xFF); // bits 8-15
+   mantissa = (mantissa / (UA_Float)256.0 ) + (UA_Float)(src->data[*offset+2] & 0x7F); // bits 16-22
+   biasedExponent  = (src->data[*offset+2] & 0x80) >>  7;                              // bits 23
+   biasedExponent |= (UA_UInt32)(src->data[*offset+3] & 0x7F) <<  1;                   // bits 24-30
+   sign = ( src->data[*offset+ 3] & 0x80 ) ? -1.0 : 1.0;                               // bit 31
+   if(biasedExponent >= 127)
+       *dst = (UA_Float)sign * (1ULL << (biasedExponent-127)) * (1.0 + mantissa / 128.0 );
+   else
+       *dst = (UA_Float)sign * 2.0 * (1.0 + mantissa / 128.0 ) / ((UA_Float)(biasedExponent-127));}
+ */
+UA_TYPE_BINARY_ENCODING_AS(UA_Float, UA_UInt32)
 
 /* Double */
-UA_TYPE_CALCSIZEBINARY_MEMSIZE(UA_Double)
-// FIXME: Implement NaN, Inf and Zero(s)
-UA_Byte UA_DOUBLE_ZERO[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-UA_StatusCode UA_Double_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Double * dst) {
-    if(*offset + sizeof(UA_Double) > (UA_UInt32)src->length )
-        return UA_STATUSCODE_BADDECODINGERROR;
-    UA_Double sign;
-    UA_Double mantissa;
-    UA_UInt32 biasedExponent;
-    if(memcmp(&src->data[*offset], UA_DOUBLE_ZERO, 8) == 0)
-        return UA_Int64_decodeBinary(src, offset, (UA_Int64 *)dst);
-    mantissa = (UA_Double)(src->data[*offset] & 0xFF);                         // bits 0-7
-    mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+1] & 0xFF); // bits 8-15
-    mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+2] & 0xFF); // bits 16-23
-    mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+3] & 0xFF); // bits 24-31
-    mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+4] & 0xFF); // bits 32-39
-    mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+5] & 0xFF); // bits 40-47
-    mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+6] & 0x0F); // bits 48-51
-    biasedExponent  = (src->data[*offset+6] & 0xF0) >>  4; // bits 52-55
-    biasedExponent |= ((UA_UInt32)(src->data[*offset+7] & 0x7F)) <<  4; // bits 56-62
-    sign = ( src->data[*offset+7] & 0x80 ) ? -1.0 : 1.0; // bit 63
-    if(biasedExponent >= 1023)
-        *dst = (UA_Double)sign * (1 << (biasedExponent-1023)) * (1.0 + mantissa / 8.0 );
-    else
-        *dst = (UA_Double)sign * 2.0 *
-            (1.0 + mantissa / 8.0 ) / ((UA_Double)(biasedExponent-1023));
-    *offset += 8;
-    return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode UA_Double_encodeBinary(UA_Double const *src, UA_ByteString * dst, size_t *offset) {
-    return UA_Int64_encodeBinary((const UA_Int64*)src, dst, offset);
-}
+/* UA_Byte UA_DOUBLE_ZERO[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+   UA_Double sign;
+   UA_Double mantissa;
+   UA_UInt32 biasedExponent;
+   if(memcmp(&src->data[*offset], UA_DOUBLE_ZERO, 8) == 0)
+       return UA_Int64_decodeBinary(src, offset, (UA_Int64 *)dst);
+   mantissa = (UA_Double)(src->data[*offset] & 0xFF);                         // bits 0-7
+   mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+1] & 0xFF); // bits 8-15
+   mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+2] & 0xFF); // bits 16-23
+   mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+3] & 0xFF); // bits 24-31
+   mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+4] & 0xFF); // bits 32-39
+   mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+5] & 0xFF); // bits 40-47
+   mantissa = (mantissa / 256.0 ) + (UA_Double)(src->data[*offset+6] & 0x0F); // bits 48-51
+   biasedExponent  = (src->data[*offset+6] & 0xF0) >>  4; // bits 52-55
+   biasedExponent |= ((UA_UInt32)(src->data[*offset+7] & 0x7F)) <<  4; // bits 56-62
+   sign = ( src->data[*offset+7] & 0x80 ) ? -1.0 : 1.0; // bit 63
+   if(biasedExponent >= 1023)
+       *dst = (UA_Double)sign * (1ULL << (biasedExponent-1023)) * (1.0 + mantissa / 8.0 );
+   else
+     *dst = (UA_Double)sign * 2.0 * (1.0 + mantissa / 8.0 ) / ((UA_Double)(biasedExponent-1023));
+*/
+UA_TYPE_BINARY_ENCODING_AS(UA_Double, UA_UInt64)
 
 /* String */
 size_t UA_String_calcSizeBinary(UA_String const *string) {
@@ -314,29 +306,31 @@ size_t UA_NodeId_calcSizeBinary(UA_NodeId const *p) {
     return length;
 }
 
-UA_StatusCode UA_NodeId_encodeBinary(UA_NodeId const *src, UA_ByteString * dst, size_t *offset) {
+static UA_StatusCode UA_NodeId_encodeBinary_nodeid_offset(UA_NodeId const *src, UA_ByteString * dst, size_t *offset, UA_Int32 nodeid_offset) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     // temporary variables for endian-save code
     UA_Byte srcByte;
     UA_UInt16 srcUInt16;
+    UA_UInt32 srcUInt32;
     switch(src->identifierType) {
     case UA_NODEIDTYPE_NUMERIC:
-        if(src->identifier.numeric > UA_UINT16_MAX || src->namespaceIndex > UA_BYTE_MAX) {
+        if(src->identifier.numeric+nodeid_offset > UA_UINT16_MAX || src->namespaceIndex > UA_BYTE_MAX) {
             srcByte = UA_NODEIDTYPE_NUMERIC;
             retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
             retval |= UA_UInt16_encodeBinary(&src->namespaceIndex, dst, offset);
-            retval |= UA_UInt32_encodeBinary(&src->identifier.numeric, dst, offset);
-        } else if(src->identifier.numeric > UA_BYTE_MAX || src->namespaceIndex > 0) { /* UA_NODEIDTYPE_FOURBYTE */
+            srcUInt32 = src->identifier.numeric+nodeid_offset;
+            retval |= UA_UInt32_encodeBinary(&srcUInt32, dst, offset);
+        } else if(src->identifier.numeric+nodeid_offset > UA_BYTE_MAX || src->namespaceIndex > 0) { /* UA_NODEIDTYPE_FOURBYTE */
             srcByte = UA_NODEIDTYPE_FOURBYTE;
             retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
             srcByte = src->namespaceIndex;
-            srcUInt16 = src->identifier.numeric;
+            srcUInt16 = src->identifier.numeric+nodeid_offset;
             retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
             retval |= UA_UInt16_encodeBinary(&srcUInt16, dst, offset);
         } else { /* UA_NODEIDTYPE_TWOBYTE */
             srcByte = UA_NODEIDTYPE_TWOBYTE;
             retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
-            srcByte = src->identifier.numeric;
+            srcByte = src->identifier.numeric+nodeid_offset;
             retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
         }
         break;
@@ -364,6 +358,10 @@ UA_StatusCode UA_NodeId_encodeBinary(UA_NodeId const *src, UA_ByteString * dst,
     return retval;
 }
 
+UA_StatusCode UA_NodeId_encodeBinary(UA_NodeId const *src, UA_ByteString * dst, size_t *offset) {
+	return UA_NodeId_encodeBinary_nodeid_offset(src, dst, offset, 0);
+}
+
 UA_StatusCode UA_NodeId_decodeBinary(UA_ByteString const *src, size_t *offset, UA_NodeId *dst) {
     // temporary variables to overcome decoder's non-endian-saveness for datatypes with different length
     UA_Byte   dstByte = 0;
@@ -680,61 +678,35 @@ enum UA_VARIANT_ENCODINGMASKTYPE_enum {
 };
 
 size_t UA_Variant_calcSizeBinary(UA_Variant const *p) {
-    if(p->type == UA_NULL) // type is not set after init
-        return 0;
-    const UA_VariantData *data;
-    UA_VariantData datasourceData;
-    if(p->storageType == UA_VARIANT_DATA || p->storageType == UA_VARIANT_DATA_NODELETE)
-        data = &p->storage.data;
-    else {
-        if(p->storage.datasource.read(p->storage.datasource.handle, &datasourceData) != UA_STATUSCODE_GOOD)
-            return 0;
-        data = &datasourceData;
-    }
-
+    UA_Boolean isArray = p->arrayLength != -1 || !p->dataPtr;  // a single element is not an array
+    UA_Boolean hasDimensions = isArray && p->arrayDimensions != UA_NULL;
+    UA_Boolean isBuiltin = p->type->namespaceZero && UA_IS_BUILTIN(p->type->typeIndex);
     size_t length = sizeof(UA_Byte); //p->encodingMask
-    UA_Int32 arrayLength = data->arrayLength;
-    if(arrayLength <= 0 || data->dataPtr == UA_NULL) {
-        length += 4;
-        arrayLength = 0; // for adding the extensionobject overhead...
+    UA_Int32 arrayLength = p->arrayLength;
+    if(!isArray) {
+    	arrayLength = 1;
+        length += UA_calcSizeBinary(p->dataPtr, p->type);
     }
-    else if(arrayLength == 1)
-        length += UA_calcSizeBinary(data->dataPtr, p->type);
     else
-        length += UA_Array_calcSizeBinary(data->dataPtr, arrayLength, p->type);
+        length += UA_Array_calcSizeBinary(p->dataPtr, arrayLength, p->type);
         
     // if the type is not builtin, we encode it as an extensionobject
-    if(p->type->typeIndex > 24 || !p->type->namespaceZero)
-        length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
-                                    // encoding + 4 byte bytestring length
-
-    if(arrayLength != 1 && data->arrayDimensions != UA_NULL)
-        length += UA_Array_calcSizeBinary(data->arrayDimensions, data->arrayDimensionsSize,
+    if(!isBuiltin) {
+        if(arrayLength > 0)
+            length += 9 * arrayLength;  // overhead for extensionobjects: 4 byte nodeid + 1 byte
+                                        // encoding + 4 byte bytestring length
+    }
+    if(hasDimensions)
+        length += UA_Array_calcSizeBinary(p->arrayDimensions, p->arrayDimensionsSize,
                                           &UA_TYPES[UA_TYPES_INT32]);
-    
-    if(p->storageType == UA_VARIANT_DATASOURCE)
-        p->storage.datasource.release(p->storage.datasource.handle, &datasourceData);
-
     return length;
 }
 
 UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst, size_t *offset) {
-    const UA_VariantData  *data;
-    UA_VariantData datasourceData;
-    if(!src->type)
-        return UA_STATUSCODE_BADINTERNALERROR;
-    if(src->storageType == UA_VARIANT_DATA)
-        data = &src->storage.data;
-    else {
-        if(src->storage.datasource.read(src->storage.datasource.handle, &datasourceData) != UA_STATUSCODE_GOOD)
-            return UA_STATUSCODE_BADENCODINGERROR;
-        data = &datasourceData;
-    }
-    
     UA_Byte encodingByte = 0;
-    UA_Boolean isArray = data->arrayLength != 1;  // a single element is not an array
-    UA_Boolean hasDimensions = isArray && data->arrayDimensions != UA_NULL;
-    UA_Boolean isBuiltin = (src->type->namespaceZero && src->type->typeIndex <= 24);
+    UA_Boolean isArray = src->arrayLength != -1 || !src->dataPtr;  // a single element is not an array
+    UA_Boolean hasDimensions = isArray && src->arrayDimensions != UA_NULL;
+    UA_Boolean isBuiltin = src->type->namespaceZero && UA_IS_BUILTIN(src->type->typeIndex);
 
     if(isArray) {
         encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
@@ -743,39 +715,40 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
     }
 
     if(isBuiltin)
-        encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (UA_Byte)UA_TYPES_IDS[src->type->typeIndex];
+        encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK &
+            (UA_Byte)UA_TYPES[src->type->typeIndex].typeId.identifier.numeric;
     else
-        encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (UA_Byte)22;  // ExtensionObject
+        encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (UA_Byte)22; // wrap in an extensionobject
 
     UA_StatusCode retval = UA_Byte_encodeBinary(&encodingByte, dst, offset);
 
     if(isArray)
-        retval |= UA_Array_encodeBinary(data->dataPtr, data->arrayLength, src->type, dst, offset);
-    else if(!data->dataPtr)
-        retval = UA_STATUSCODE_BADENCODINGERROR; // an array can be empty. a single element must be present.
-    else {
+        retval |= UA_Int32_encodeBinary(&src->arrayLength, dst, offset);
+    uintptr_t ptr = (uintptr_t)src->dataPtr;
+    ptrdiff_t memSize = src->type->memSize;
+    UA_Int32 numToEncode = src->arrayLength;
+    if(!isArray)
+        numToEncode = 1;
+    for(UA_Int32 i=0;i<numToEncode;i++) {
         if(!isBuiltin) {
-            // print the extensionobject header
-            UA_NodeId_encodeBinary(&src->typeId, dst, offset);
+            /* The type is wrapped inside an extensionobject*/
+            // todo: offest holds only for namespace 0
+            retval |= UA_NodeId_encodeBinary_nodeid_offset(&src->type->typeId, dst, offset, UA_ENCODINGOFFSET_BINARY);
             UA_Byte eoEncoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-            UA_Byte_encodeBinary(&eoEncoding, dst, offset);
-            UA_Int32 eoEncodingLength = UA_calcSizeBinary(data->dataPtr, src->type);
-            UA_Int32_encodeBinary(&eoEncodingLength, dst, offset);
+            retval |= UA_Byte_encodeBinary(&eoEncoding, dst, offset);
+            UA_Int32 eoEncodingLength = UA_calcSizeBinary(src->dataPtr, src->type);
+            retval |= UA_Int32_encodeBinary(&eoEncodingLength, dst, offset);
         }
-        retval |= UA_encodeBinary(data->dataPtr, src->type, dst, offset);
+        retval |= UA_encodeBinary((void*)ptr, src->type, dst, offset);
+        ptr += memSize;
     }
-
     if(hasDimensions)
-        retval |= UA_Array_encodeBinary(data->arrayDimensions, data->arrayDimensionsSize,
-                                        &UA_TYPES[UA_TYPES_INT32], dst, offset);
-
-    if(src->storageType == UA_VARIANT_DATASOURCE)
-        src->storage.datasource.release(src->storage.datasource.handle, &datasourceData);
-                     
+        retval |= UA_Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32], dst, offset);
     return retval;
 }
 
-/* The resulting variant always has the storagetype UA_VARIANT_DATA. */
+/* The resulting variant always has the storagetype UA_VARIANT_DATA. Currently,
+   we only support ns0 types (todo: attach typedescriptions to datatypenodes) */
 UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Variant *dst) {
     UA_Variant_init(dst);
     UA_Byte encodingByte;
@@ -783,55 +756,69 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset,
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
-    UA_VariantData *data = &dst->storage.data;
     UA_Boolean isArray = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
-    UA_Boolean hasDimensions = isArray && (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS);
-    UA_NodeId typeid = { .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
-                         .identifier.numeric = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK };
-
-    UA_UInt16 typeIndex;
-    for(typeIndex = 0; typeIndex < UA_TYPES_COUNT; typeIndex++) {
-        if(UA_TYPES_IDS[typeIndex] == typeid.identifier.numeric)
-            break;
-    }
-
-    if(typeIndex >= UA_TYPES_COUNT)
+    size_t typeIndex = (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1;
+    if(typeIndex > 24) /* must be builtin */
         return UA_STATUSCODE_BADDECODINGERROR;
 
-    const UA_DataType *dataType = &UA_TYPES[typeIndex];
-
-    if(!isArray) {
-        if(!(data->dataPtr = UA_malloc(dataType->memSize)))
-            return UA_STATUSCODE_BADOUTOFMEMORY;
-        retval |= UA_decodeBinary(src, offset, data->dataPtr, dataType);
-        if(retval) {
-            UA_free(data->dataPtr);
-            return retval;
+    if(isArray || typeIndex != UA_TYPES_EXTENSIONOBJECT) {
+        /* an array or a single builtin */
+        const UA_DataType *dataType = &UA_TYPES[typeIndex];
+        UA_Int32 arraySize = -1;
+        if(isArray) {
+            retval |= UA_Int32_decodeBinary(src, offset, &arraySize);
+            if(retval != UA_STATUSCODE_GOOD)
+                return retval;
         }
-        data->arrayLength = 1;
+        retval |= UA_Array_decodeBinary(src, offset, (!isArray && arraySize==-1) ? 1: arraySize, &dst->dataPtr, dataType);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+        dst->arrayLength = arraySize; // for deleteMembers
+        dst->type = dataType;
     } else {
-        retval |= UA_Int32_decodeBinary(src, offset, &data->arrayLength);
-        if(retval == UA_STATUSCODE_GOOD)
-            retval |= UA_Array_decodeBinary(src, offset, data->arrayLength, &data->dataPtr, dataType);
-        if(retval)
-            data->arrayLength = -1; // for deleteMembers
+        /* a single extensionobject */
+        size_t oldoffset = *offset;
+        UA_NodeId typeId;
+        if((retval |= UA_NodeId_decodeBinary(src, offset, &typeId)) != UA_STATUSCODE_GOOD)
+            return retval;
+        UA_Byte EOencodingByte;
+        if((retval |= UA_Byte_decodeBinary(src, offset, &EOencodingByte)) != UA_STATUSCODE_GOOD) {
+            UA_NodeId_deleteMembers(&typeId);
+            return retval;
+        }
+        const UA_DataType *dataType = UA_NULL;
+        if(typeId.namespaceIndex == 0 && EOencodingByte == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
+            for(typeIndex = 0;typeIndex < UA_TYPES_COUNT; typeIndex++) {
+                if(UA_NodeId_equal(&typeId, &UA_TYPES[typeIndex].typeId)) {
+                    dataType = &UA_TYPES[typeIndex];
+                    break;
+                }
+            }
+        }
+        UA_NodeId_deleteMembers(&typeId);
+        if(!dataType) {
+            *offset = oldoffset;
+            dataType = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
+        }
+        if((retval |= UA_decodeBinary(src, offset, dst->dataPtr, dataType)) != UA_STATUSCODE_GOOD)
+            return retval;
+        dst->type = dataType;
+        dst->arrayLength = -1;
     }
-
-    if(hasDimensions && retval == UA_STATUSCODE_GOOD) {
-        retval |= UA_Int32_decodeBinary(src, offset, &data->arrayDimensionsSize);
+    
+    /* array dimensions */
+    if(isArray && (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS)) {
+        retval |= UA_Int32_decodeBinary(src, offset, &dst->arrayDimensionsSize);
         if(retval == UA_STATUSCODE_GOOD)
-            retval |= UA_Array_decodeBinary(src, offset, data->arrayDimensionsSize,
-                                            &data->dataPtr, &UA_TYPES[UA_TYPES_INT32]);
-        if(retval)
-            data->arrayLength = -1; // for deleteMembers
+            retval |= UA_Array_decodeBinary(src, offset, dst->arrayDimensionsSize,
+                                            &dst->dataPtr, &UA_TYPES[UA_TYPES_INT32]);
+        if(retval != UA_STATUSCODE_GOOD) {
+            dst->arrayDimensionsSize = -1;
+            UA_Variant_deleteMembers(dst);
+            return retval;
+        }
     }
-
-    dst->type = dataType;
-    dst->typeId = typeid;
-
-    if(retval)
-        UA_Variant_deleteMembers(dst);
-    return retval;
+    return UA_STATUSCODE_GOOD;
 }
 
 /* DiagnosticInfo */
@@ -970,9 +957,6 @@ size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType) {
         case UA_TYPES_EXPANDEDNODEID:
             size += UA_ExpandedNodeId_calcSizeBinary((const UA_ExpandedNodeId*)ptr);
             break;
-        case UA_TYPES_QUALIFIEDNAME:
-            size += UA_QualifiedName_calcSizeBinary((const UA_QualifiedName*)ptr);
-            break;
         case UA_TYPES_LOCALIZEDTEXT:
             size += UA_LocalizedText_calcSizeBinary((const UA_LocalizedText*)ptr);
             break;
@@ -988,12 +972,8 @@ size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType) {
         case UA_TYPES_DIAGNOSTICINFO:
             size += UA_DiagnosticInfo_calcSizeBinary((const UA_DiagnosticInfo*)ptr);
             break;
-        case UA_TYPES_STRING:
-        case UA_TYPES_BYTESTRING:
-        case UA_TYPES_XMLELEMENT:
-            size += UA_String_calcSizeBinary((const UA_String*)ptr);
-            break;
         default:
+            // UA_TYPES_QUALIFIEDNAME, UA_TYPES_STRING, UA_TYPES_BYTESTRING, UA_TYPES_XMLELEMENT:
             size += UA_calcSizeBinary((const void*)ptr, memberType);
         }
         ptr += memberType->memSize;
@@ -1036,26 +1016,20 @@ UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_B
             retval = UA_Byte_encodeBinary((const UA_Byte*)ptr, dst, offset);
             break;
         case UA_TYPES_INT16:
-            retval = UA_Int16_encodeBinary((const UA_Int16*)ptr, dst, offset);
-            break;
         case UA_TYPES_UINT16:
             retval = UA_UInt16_encodeBinary((const UA_UInt16*)ptr, dst, offset);
             break;
         case UA_TYPES_INT32:
         case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-            retval = UA_Int32_encodeBinary((const UA_Int32*)ptr, dst, offset);
-            break;
         case UA_TYPES_FLOAT:
-            retval = UA_Float_encodeBinary((const UA_Float*)ptr, dst, offset);
+        case UA_TYPES_STATUSCODE:
+            retval = UA_UInt32_encodeBinary((const UA_UInt32*)ptr, dst, offset);
             break;
         case UA_TYPES_INT64:
         case UA_TYPES_UINT64:
-        case UA_TYPES_DATETIME:
-            retval = UA_Int64_encodeBinary((const UA_Int64*)ptr, dst, offset);
-            break;
         case UA_TYPES_DOUBLE:
-            retval = UA_Double_encodeBinary((const UA_Double*)ptr, dst, offset);
+        case UA_TYPES_DATETIME:
+            retval = UA_UInt64_encodeBinary((const UA_UInt64*)ptr, dst, offset);
             break;
         case UA_TYPES_GUID:
             retval = UA_Guid_encodeBinary((const UA_Guid*)ptr, dst, offset);
@@ -1066,9 +1040,6 @@ UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_B
         case UA_TYPES_EXPANDEDNODEID:
             retval = UA_ExpandedNodeId_encodeBinary((const UA_ExpandedNodeId*)ptr, dst, offset);
             break;
-        case UA_TYPES_QUALIFIEDNAME:
-            retval = UA_QualifiedName_encodeBinary((const UA_QualifiedName*)ptr, dst, offset);
-            break;
         case UA_TYPES_LOCALIZEDTEXT:
             retval = UA_LocalizedText_encodeBinary((const UA_LocalizedText*)ptr, dst, offset);
             break;
@@ -1084,12 +1055,8 @@ UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_B
         case UA_TYPES_DIAGNOSTICINFO:
             retval = UA_DiagnosticInfo_encodeBinary((const UA_DiagnosticInfo*)ptr, dst, offset);
             break;
-        case UA_TYPES_STRING:
-        case UA_TYPES_BYTESTRING:
-        case UA_TYPES_XMLELEMENT:
-            retval = UA_String_encodeBinary((const UA_String*)ptr, dst, offset);
-            break;
         default:
+            // UA_TYPES_QUALIFIEDNAME, UA_TYPES_STRING, UA_TYPES_BYTESTRING, UA_TYPES_XMLELEMENT:
             retval = UA_encodeBinary((const void*)ptr, memberType, dst, offset);
         }
         ptr += memberType->memSize;
@@ -1113,9 +1080,14 @@ UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *ds
         if(member->isArray) {
             ptr += (member->padding >> 3);
             UA_Int32 *noElements = (UA_Int32*)ptr;
-            UA_Int32_decodeBinary(src, offset, noElements);
+            UA_Int32 tempNoElements;
+            retval |= UA_Int32_decodeBinary(src, offset, &tempNoElements);
+            if(retval)
+                continue;
             ptr += sizeof(UA_Int32) + (member->padding & 0x07);
-            retval = UA_Array_decodeBinary(src, offset, *noElements, (void**)ptr, memberType);
+            retval = UA_Array_decodeBinary(src, offset, tempNoElements, (void**)ptr, memberType);
+            if(retval == UA_STATUSCODE_GOOD)
+                *noElements = tempNoElements;
             ptr += sizeof(void*);
             continue;
         }
@@ -1139,19 +1111,15 @@ UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *ds
             break;
         case UA_TYPES_INT32:
         case UA_TYPES_UINT32:
-        case UA_TYPES_STATUSCODE:
-            retval = UA_Int32_decodeBinary(src, offset, (UA_Int32*)ptr);
-            break;
         case UA_TYPES_FLOAT:
-            retval = UA_Float_decodeBinary(src, offset, (UA_Float*)ptr);
+        case UA_TYPES_STATUSCODE:
+            retval = UA_UInt32_decodeBinary(src, offset, (UA_UInt32*)ptr);
             break;
         case UA_TYPES_INT64:
         case UA_TYPES_UINT64:
-        case UA_TYPES_DATETIME:
-            retval = UA_Int64_decodeBinary(src, offset, (UA_Int64*)ptr);
-            break;
         case UA_TYPES_DOUBLE:
-            retval = UA_Double_decodeBinary(src, offset, (UA_Double*)ptr);
+        case UA_TYPES_DATETIME:
+            retval = UA_UInt64_decodeBinary(src, offset, (UA_UInt64*)ptr);
             break;
         case UA_TYPES_GUID:
             retval = UA_Guid_decodeBinary(src, offset, (UA_Guid*)ptr);
@@ -1162,9 +1130,6 @@ UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *ds
         case UA_TYPES_EXPANDEDNODEID:
             retval = UA_ExpandedNodeId_decodeBinary(src, offset, (UA_ExpandedNodeId*)ptr);
             break;
-        case UA_TYPES_QUALIFIEDNAME:
-            retval = UA_QualifiedName_decodeBinary(src, offset, (UA_QualifiedName*)ptr);
-            break;
         case UA_TYPES_LOCALIZEDTEXT:
             retval = UA_LocalizedText_decodeBinary(src, offset, (UA_LocalizedText*)ptr);
             break;
@@ -1180,12 +1145,8 @@ UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *ds
         case UA_TYPES_DIAGNOSTICINFO:
             retval = UA_DiagnosticInfo_decodeBinary(src, offset, (UA_DiagnosticInfo*)ptr);
             break;
-        case UA_TYPES_STRING:
-        case UA_TYPES_BYTESTRING:
-        case UA_TYPES_XMLELEMENT:
-            retval = UA_String_decodeBinary(src, offset, (UA_String*)ptr);
-            break;
         default:
+            // UA_TYPES_QUALIFIEDNAME, UA_TYPES_STRING, UA_TYPES_BYTESTRING, UA_TYPES_XMLELEMENT:
             retval = UA_decodeBinary(src, offset, (void*)ptr, memberType);
         }
         ptr += memberType->memSize;
@@ -1254,7 +1215,9 @@ UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, size_t *offset, UA
         retval = UA_decodeBinary(src, offset, (void*)ptr, dataType);
         ptr += dataType->memSize;
     }
-    if(retval != UA_STATUSCODE_GOOD)
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_Array_delete(*dst, dataType, i);
+        *dst = UA_NULL;
+    }
     return retval;
 }

+ 55 - 3
src/ua_util.h

@@ -1,9 +1,25 @@
 #ifndef UA_UTIL_H_
 #define UA_UTIL_H_
 
+#ifndef UA_AMALGAMATE
+# include "ua_config.h"
+#endif
+
 #ifndef __USE_POSIX
-#define __USE_POSIX
+# define __USE_POSIX
+#endif
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+# define _POSIX_C_SOURCE 199309L
 #endif
+#ifndef _BSD_SOURCE
+# define _BSD_SOURCE
+#endif
+
+/*********************/
+/* Memory Management */
+/*********************/
+
 #include <stdlib.h> // malloc, free
 #include <string.h> // memcpy
 #include <assert.h> // assert
@@ -14,6 +30,7 @@
 # include <alloca.h>
 #endif
 
+#define UA_NULL ((void *)0)
 
 // subtract from nodeids to get from the encoding to the content
 #define UA_ENCODINGOFFSET_XML 1
@@ -21,11 +38,10 @@
 
 #define UA_assert(ignore) assert(ignore)
 
-#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_calloc(num, size) calloc(num, 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)
@@ -36,4 +52,40 @@
 # define UA_alloca(SIZE) alloca(SIZE)
 #endif
 
+/********************/
+/* System Libraries */
+/********************/
+
+#include <stdarg.h> // va_start, va_end
+#include <time.h>
+#include <stdio.h> // printf
+#include <inttypes.h>
+
+#ifdef _WIN32
+# include <windows.h>
+# undef SLIST_ENTRY
+# define RAND(SEED) (UA_UInt32)rand()
+#else
+# include <endian.h>
+# include <sys/time.h>
+# define RAND(SEED) (UA_UInt32)rand_r(SEED)
+#endif
+
+/*************************/
+/* External Dependencies */
+/*************************/
+
+#ifndef UA_AMALGAMATE
+# include "queue.h"
+#endif
+
+#ifdef UA_MULTITHREADING
+# define _LGPL_SOURCE
+# include <urcu.h>
+# include <urcu/wfcqueue.h>
+# include <urcu/compiler.h> // for caa_container_of
+# include <urcu/uatomic.h>
+# include <urcu/rculfhash.h>
+#endif
+
 #endif /* UA_UTIL_H_ */

+ 9 - 4
tests/CMakeLists.txt

@@ -1,3 +1,8 @@
+include_directories(${PROJECT_SOURCE_DIR}/include)
+include_directories(${PROJECT_SOURCE_DIR}/deps)
+include_directories(${PROJECT_SOURCE_DIR}/src)
+include_directories(${PROJECT_BINARY_DIR}/src_generated)
+
 find_package(Check REQUIRED)
 find_package(Threads REQUIRED)
 
@@ -12,11 +17,11 @@ endif(MULTITHREADING)
 # the unit test are built directly on the open62541 object files. so they can
 # access symbols that are hidden/not exported to the shared library
 
-add_executable(check_builtin $<TARGET_OBJECTS:open62541-objects> check_builtin.c)
+add_executable(check_builtin check_builtin.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_builtin ${LIBS})
 add_test(builtin ${CMAKE_CURRENT_BINARY_DIR}/check_builtin)
 
-add_executable(check_memory $<TARGET_OBJECTS:open62541-objects> check_memory.c)
+add_executable(check_memory check_memory.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_memory ${LIBS})
 add_test(memory ${CMAKE_CURRENT_BINARY_DIR}/check_memory)
 
@@ -28,11 +33,11 @@ add_test(memory ${CMAKE_CURRENT_BINARY_DIR}/check_memory)
 # target_link_libraries(check_base64 ${LIBS})
 # add_test(base64 ${CMAKE_CURRENT_BINARY_DIR}/check_base64)
 
-add_executable(check_services_view $<TARGET_OBJECTS:open62541-objects> check_services_view.c)
+add_executable(check_services_view check_services_view.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_services_view ${LIBS})
 add_test(services_view ${CMAKE_CURRENT_BINARY_DIR}/check_services_view)
 
-add_executable(check_nodestore $<TARGET_OBJECTS:open62541-objects> check_nodestore.c)
+add_executable(check_nodestore check_nodestore.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_nodestore ${LIBS})
 add_test(nodestore ${CMAKE_CURRENT_BINARY_DIR}/check_nodestore)
 

+ 75 - 62
tests/check_builtin.c

@@ -278,9 +278,9 @@ START_TEST(UA_Variant_calcSizeFixedSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
     arg.type = &UA_TYPES[UA_TYPES_INT32];
 #define ARRAY_LEN 8
-	arg.storage.data.arrayLength = ARRAY_LEN;
+	arg.arrayLength = ARRAY_LEN;
 	UA_Int32 *data[ARRAY_LEN];
-	arg.storage.data.dataPtr = (void *)data;
+	arg.dataPtr = (void *)data;
 
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
@@ -297,12 +297,12 @@ START_TEST(UA_Variant_calcSizeVariableSizeArrayShallReturnEncodingSize) {
 	UA_Variant_init(&arg);
 	arg.type = &UA_TYPES[UA_TYPES_STRING];
 #define ARRAY_LEN 3
-	arg.storage.data.arrayLength = ARRAY_LEN;
+	arg.arrayLength = ARRAY_LEN;
 	UA_String strings[3];
 	strings[0] = (UA_String) {-1, UA_NULL };
 	strings[1] = (UA_String) {3, (UA_Byte *)"PLT" };
 	strings[2] = (UA_String) {47, UA_NULL };
-	arg.storage.data.dataPtr   = (void *)strings;
+	arg.dataPtr   = (void *)strings;
 	// when
 	UA_UInt32 encodingSize = UA_Variant_calcSizeBinary(&arg);
 	// then
@@ -564,6 +564,22 @@ START_TEST(UA_Double_decodeShallGiveMinusTwo) {
 }
 END_TEST
 
+START_TEST(UA_Double_decodeShallGive2147483648) {
+	// given
+	size_t pos = 0;
+	UA_Byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x41 }; //2147483648
+	UA_ByteString src = { 8, data }; // 1
+	UA_Double dst;
+	// when
+	UA_StatusCode retval = UA_Double_decodeBinary(&src, &pos, &dst);
+	// then
+	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+	ck_assert_int_eq(pos, 8);
+	ck_assert(2147483647.9999999 <= dst);
+	ck_assert(dst <= 2147483648.00000001);
+}
+END_TEST
+
 START_TEST(UA_String_decodeShallAllocateMemoryAndCopyString) {
 	// given
 	size_t pos = 0;
@@ -671,7 +687,7 @@ END_TEST
 START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
 	// given
 	size_t pos = 0;
-	UA_Byte data[] = { UA_TYPES_IDS[UA_TYPES_INT32], 0xFF, 0x00, 0x00, 0x00 };
+	UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric, 0xFF, 0x00, 0x00, 0x00 };
 	UA_ByteString src = { 5, data };
 	UA_Variant dst;
 	// when
@@ -681,8 +697,8 @@ START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArr
 	ck_assert_int_eq(pos, 5);
 	//ck_assert_ptr_eq((const void *)dst.type, (const void *)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
-	ck_assert_int_eq(dst.storage.data.arrayLength, 1);
-	ck_assert_int_eq(*(UA_Int32 *)dst.storage.data.dataPtr, 255);
+	ck_assert_int_eq(dst.arrayLength, -1);
+	ck_assert_int_eq(*(UA_Int32 *)dst.dataPtr, 255);
 	// finally
 	UA_Variant_deleteMembers(&dst);
 }
@@ -691,7 +707,7 @@ END_TEST
 START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
 	// given
 	size_t pos = 0;
-	UA_Byte data[] = { UA_TYPES_IDS[UA_TYPES_INT32] | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
+	UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
                        0xFF, 0xFF };
 	UA_ByteString src = { 13, data };
@@ -703,9 +719,9 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
 	ck_assert_int_eq(pos, 1+4+2*4);
 	//ck_assert_ptr_eq((const (void*))dst.type, (const void*)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     ck_assert_int_eq((uintptr_t)dst.type,(uintptr_t)&UA_TYPES[UA_TYPES_INT32]);
-	ck_assert_int_eq(dst.storage.data.arrayLength, 2);
-	ck_assert_int_eq(((UA_Int32 *)dst.storage.data.dataPtr)[0], 255);
-	ck_assert_int_eq(((UA_Int32 *)dst.storage.data.dataPtr)[1], -1);
+	ck_assert_int_eq(dst.arrayLength, 2);
+	ck_assert_int_eq(((UA_Int32 *)dst.dataPtr)[0], 255);
+	ck_assert_int_eq(((UA_Int32 *)dst.dataPtr)[1], -1);
 	// finally
 	UA_Variant_deleteMembers(&dst);
 }
@@ -714,7 +730,7 @@ END_TEST
 START_TEST(UA_Variant_decodeWithOutDeleteMembersShallFailInCheckMem) {
 	// given
 	size_t pos = 0;
-	UA_Byte data[] = { UA_TYPES_IDS[UA_TYPES_INT32] | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
+	UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
 	UA_ByteString src = { 13, data };
 	UA_Variant dst;
@@ -730,7 +746,7 @@ END_TEST
 START_TEST(UA_Variant_decodeWithTooSmallSourceShallReturnWithError) {
 	// given
 	size_t pos = 0;
-	UA_Byte data[] = { UA_TYPES_IDS[UA_TYPES_INT32] | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
+	UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
 	UA_ByteString src = { 4, data };
 
@@ -1135,9 +1151,9 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
     src.hasVariant = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
 	src.value.type = &UA_TYPES[UA_TYPES_INT32];
-	src.value.storage.data.arrayLength  = 1; // one element (encoded as not an array)
+	src.value.arrayLength  = -1; // one element (encoded as not an array)
 	UA_Int32  vdata  = 45;
-	src.value.storage.data.dataPtr = (void *)&vdata;
+	src.value.dataPtr = (void *)&vdata;
 
 	UA_Byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1198,7 +1214,7 @@ START_TEST(UA_DateTime_toStringShallWorkOnExample) {
 	// when
 	UA_DateTime_toString(src, &dst);
 	// then
-	ck_assert_int_eq(dst.data[0], ' ');
+	ck_assert_int_eq(dst.data[0], '0');
 	ck_assert_int_eq(dst.data[1], '4');
 	ck_assert_int_eq(dst.data[2], '/');
 	ck_assert_int_eq(dst.data[3], '1');
@@ -1215,8 +1231,7 @@ START_TEST(UA_ExtensionObject_copyShallWorkOnExample) {
 	UA_ExtensionObject_init(&value);
 	UA_ExtensionObject_init(&valueCopied);
 
-	value.typeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-	value.typeId.identifier.numeric = UA_TYPES_IDS[UA_TYPES_BYTE];
+	value.typeId = UA_TYPES[UA_TYPES_BYTE].typeId;
 	value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED;
 	value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
 	value.body.data   = data;
@@ -1298,6 +1313,7 @@ START_TEST(UA_DiagnosticInfo_copyShallWorkOnExample) {
 	UA_DiagnosticInfo_init(&innerValue);
     value.hasInnerDiagnosticInfo = UA_TRUE;
 	value.innerDiagnosticInfo = &innerValue;
+    value.hasAdditionalInfo = UA_TRUE;
 	value.additionalInfo = testString;
 
 	//when
@@ -1425,10 +1441,8 @@ START_TEST(UA_LocalizedText_copycstringShallWorkOnInputExample) {
 	UA_StatusCode ret = UA_LocalizedText_copycstring(src, &dst);
 	// then
 	ck_assert_int_eq(ret, UA_STATUSCODE_GOOD);
-	ck_assert_int_eq('e', dst.locale.data[0]);
-	ck_assert_int_eq('n', dst.locale.data[1]);
 	ck_assert_int_eq('1', dst.text.data[4]);
-	ck_assert_int_eq(2, dst.locale.length);
+	ck_assert_int_eq(0, dst.locale.length);
 	ck_assert_int_eq(7, dst.text.length);
 	// finally
 	UA_LocalizedText_deleteMembers(&dst);
@@ -1465,25 +1479,25 @@ START_TEST(UA_Variant_copyShallWorkOnSingleValueExample) {
 	UA_Variant value, copiedValue;
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
-	value.storage.data.dataPtr = UA_malloc(sizeof(UA_String));
-	*((UA_String*)value.storage.data.dataPtr) = testString;
+	value.dataPtr = UA_malloc(sizeof(UA_String));
+	*((UA_String*)value.dataPtr) = testString;
     value.type = &UA_TYPES[UA_TYPES_STRING];
-	value.storage.data.arrayLength = 1;
+	value.arrayLength = 1;
 
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 
 	//then
-	UA_String copiedString = *(UA_String*)(copiedValue.storage.data.dataPtr);
+	UA_String copiedString = *(UA_String*)(copiedValue.dataPtr);
 	for(UA_Int32 i = 0;i < 5;i++)
 		ck_assert_int_eq(copiedString.data[i], testString.data[i]);
 	ck_assert_int_eq(copiedString.length, testString.length);
 
-	ck_assert_int_eq(value.storage.data.arrayDimensionsSize, copiedValue.storage.data.arrayDimensionsSize);
-	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
+	ck_assert_int_eq(value.arrayDimensionsSize, copiedValue.arrayDimensionsSize);
+	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
 
 	//finally
-	((UA_String*)value.storage.data.dataPtr)->data = UA_NULL; // the string is statically allocated. do not free it.
+	((UA_String*)value.dataPtr)->data = UA_NULL; // the string is statically allocated. do not free it.
 	UA_Variant_deleteMembers(&value);
 	UA_Variant_deleteMembers(&copiedValue);
 }
@@ -1504,32 +1518,32 @@ START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
 
-	value.storage.data.arrayLength = 3;
-	value.storage.data.dataPtr = (void *)srcArray;
-	value.storage.data.arrayDimensionsSize = 1;
-	value.storage.data.arrayDimensions = dimensions;
+	value.arrayLength = 3;
+	value.dataPtr = (void *)srcArray;
+	value.arrayDimensionsSize = 1;
+	value.arrayDimensions = dimensions;
 	value.type = &UA_TYPES[UA_TYPES_STRING];
 
 	//when
 	UA_Variant_copy(&value, &copiedValue);
 
 	//then
-	UA_Int32 i1 = value.storage.data.arrayDimensions[0];
-	UA_Int32 i2 = copiedValue.storage.data.arrayDimensions[0];
+	UA_Int32 i1 = value.arrayDimensions[0];
+	UA_Int32 i2 = copiedValue.arrayDimensions[0];
 	ck_assert_int_eq(i1, i2);
 
 	for(UA_Int32 i = 0;i < 3;i++) {
 		for(UA_Int32 j = 0;j < 6;j++) {
-			ck_assert_int_eq(((UA_String *)value.storage.data.dataPtr)[i].data[j],
-					((UA_String *)copiedValue.storage.data.dataPtr)[i].data[j]);
+			ck_assert_int_eq(((UA_String *)value.dataPtr)[i].data[j],
+					((UA_String *)copiedValue.dataPtr)[i].data[j]);
 		}
-		ck_assert_int_eq(((UA_String *)value.storage.data.dataPtr)[i].length,
-				((UA_String *)copiedValue.storage.data.dataPtr)[i].length);
+		ck_assert_int_eq(((UA_String *)value.dataPtr)[i].length,
+				((UA_String *)copiedValue.dataPtr)[i].length);
 	}
-	ck_assert_int_eq(((UA_String *)copiedValue.storage.data.dataPtr)[0].data[2], 'o');
-	ck_assert_int_eq(((UA_String *)copiedValue.storage.data.dataPtr)[0].data[3], 'p');
-	ck_assert_int_eq(value.storage.data.arrayDimensionsSize, copiedValue.storage.data.arrayDimensionsSize);
-	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
+	ck_assert_int_eq(((UA_String *)copiedValue.dataPtr)[0].data[2], 'o');
+	ck_assert_int_eq(((UA_String *)copiedValue.dataPtr)[0].data[3], 'p');
+	ck_assert_int_eq(value.arrayDimensionsSize, copiedValue.arrayDimensionsSize);
+	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
 
 	//finally
 	UA_Variant_deleteMembers(&value);
@@ -1557,10 +1571,10 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 	UA_Variant_init(&value);
 	UA_Variant_init(&copiedValue);
 
-	value.storage.data.arrayLength = 6;
-	value.storage.data.dataPtr     = srcArray;
-	value.storage.data.arrayDimensionsSize = 2;
-	value.storage.data.arrayDimensions       = dimensions;
+	value.arrayLength = 6;
+	value.dataPtr     = srcArray;
+	value.arrayDimensionsSize = 2;
+	value.arrayDimensions     = dimensions;
 	value.type = &UA_TYPES[UA_TYPES_INT32];
 
 	//when
@@ -1568,28 +1582,28 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 
 	//then
 	//1st dimension
-	UA_Int32 i1 = value.storage.data.arrayDimensions[0];
-	UA_Int32 i2 = copiedValue.storage.data.arrayDimensions[0];
+	UA_Int32 i1 = value.arrayDimensions[0];
+	UA_Int32 i2 = copiedValue.arrayDimensions[0];
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, dim1);
 
 
 	//2nd dimension
-	i1 = value.storage.data.arrayDimensions[1];
-	i2 = copiedValue.storage.data.arrayDimensions[1];
+	i1 = value.arrayDimensions[1];
+	i2 = copiedValue.arrayDimensions[1];
 	ck_assert_int_eq(i1, i2);
 	ck_assert_int_eq(i1, dim2);
 
 
 	for(UA_Int32 i = 0;i < 6;i++) {
-		i1 = ((UA_Int32 *)value.storage.data.dataPtr)[i];
-		i2 = ((UA_Int32 *)copiedValue.storage.data.dataPtr)[i];
+		i1 = ((UA_Int32 *)value.dataPtr)[i];
+		i2 = ((UA_Int32 *)copiedValue.dataPtr)[i];
 		ck_assert_int_eq(i1, i2);
 		ck_assert_int_eq(i2, i);
 	}
 
-	ck_assert_int_eq(value.storage.data.arrayDimensionsSize, copiedValue.storage.data.arrayDimensionsSize);
-	ck_assert_int_eq(value.storage.data.arrayLength, copiedValue.storage.data.arrayLength);
+	ck_assert_int_eq(value.arrayDimensionsSize, copiedValue.arrayDimensionsSize);
+	ck_assert_int_eq(value.arrayLength, copiedValue.arrayLength);
 
 	//finally
 	UA_Variant_deleteMembers(&value);
@@ -1601,13 +1615,11 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	UA_Int32 val = 42;
 	UA_VariableAttributes varAttr;
 	UA_VariableAttributes_init(&varAttr);
-    varAttr.dataType.identifierType = UA_NODEIDTYPE_NUMERIC;
-	varAttr.dataType.identifier.numeric = UA_TYPES_IDS[UA_TYPES_INT32];
+	varAttr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
 	UA_Variant_init(&varAttr.value);
 	varAttr.value.type = &UA_TYPES[UA_TYPES_INT32];
-    UA_NODEID_ASSIGN(varAttr.value.typeId, 0, UA_TYPES_IDS[UA_TYPES_INT32]);
-	varAttr.value.storage.data.dataPtr = &val;
-	varAttr.value.storage.data.arrayLength = 1;
+	varAttr.value.dataPtr = &val;
+	varAttr.value.arrayLength = -1;
 	varAttr.userWriteMask = 41;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DATATYPE;
 	varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
@@ -1615,7 +1627,7 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	/* wrap it into a extension object attributes */
 	UA_ExtensionObject extensionObject;
 	UA_ExtensionObject_init(&extensionObject);
-	extensionObject.typeId.identifier.numeric = UA_TYPES_IDS[UA_TYPES_VARIABLEATTRIBUTES];
+	extensionObject.typeId = UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES].typeId;
 	UA_Byte extensionData[50];
 	extensionObject.body = (UA_ByteString){.data = extensionData, .length=UA_VariableAttributes_calcSizeBinary(&varAttr)};
 	size_t posEncode = 0;
@@ -1641,7 +1653,7 @@ START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 	posDecode = 0;
 	UA_VariableAttributes_decodeBinary(&extensionObjectDecoded.body, &posDecode, &varAttrDecoded);
 	ck_assert_uint_eq(41, varAttrDecoded.userWriteMask);
-	ck_assert_int_eq(1, varAttrDecoded.value.storage.data.arrayLength);
+	ck_assert_int_eq(-1, varAttrDecoded.value.arrayLength);
 
     // finally
     UA_ExtensionObject_deleteMembers(&extensionObjectDecoded);
@@ -1693,6 +1705,7 @@ static Suite *testSuite_builtin(void) {
 	tcase_add_test(tc_decode, UA_Double_decodeShallGiveOne);
 	tcase_add_test(tc_decode, UA_Double_decodeShallGiveZero);
 	tcase_add_test(tc_decode, UA_Double_decodeShallGiveMinusTwo);
+	tcase_add_test(tc_decode, UA_Double_decodeShallGive2147483648);
 	tcase_add_test(tc_decode, UA_Byte_encode_test);
 	tcase_add_test(tc_decode, UA_String_decodeShallAllocateMemoryAndCopyString);
 	tcase_add_test(tc_decode, UA_String_decodeWithNegativeSizeShallNotAllocateMemoryAndNullPtr);
@@ -1756,7 +1769,7 @@ int main(void) {
 
 	s  = testSuite_builtin();
 	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);

+ 8 - 8
tests/check_memory.c

@@ -62,14 +62,14 @@ START_TEST(encodeShallYieldDecode) {
 	// when
 	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]);
+	ck_assert_msg(retval == UA_STATUSCODE_GOOD, "messages differ idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric);
 	retval = UA_ByteString_newMembers(&msg2, UA_calcSizeBinary(obj2, &UA_TYPES[_i]));
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	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,nodeid=%i", _i, UA_TYPES_IDS[_i]);
+	ck_assert_msg(UA_ByteString_equal(&msg1, &msg2) == UA_TRUE, "messages differ idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric);
 
 	// finally
 	UA_delete(obj1, &UA_TYPES[_i]);
@@ -133,7 +133,7 @@ START_TEST(decodeScalarBasicTypeFromRandomBufferShallSucceed) {
 		obj1 = UA_new(&UA_TYPES[_i]);
 		retval |= UA_decodeBinary(&msg1, &pos, obj1, &UA_TYPES[_i]);
 		//then
-		ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Decoding %d from random buffer", UA_TYPES_IDS[_i]);
+		ck_assert_msg(retval == UA_STATUSCODE_GOOD, "Decoding %d from random buffer", UA_TYPES[_i].typeId.identifier.numeric);
 		// finally
 		UA_delete(obj1, &UA_TYPES[_i]);
 	}
@@ -180,17 +180,17 @@ int main(void) {
 
 	Suite *s  = suite_create("testMemoryHandling");
 	TCase *tc = tcase_create("Empty Objects");
-	tcase_add_loop_test(tc, newAndEmptyObjectShallBeDeleted, UA_TYPES_BOOLEAN, UA_TYPES_EVENTNOTIFICATIONLIST);
+	tcase_add_loop_test(tc, newAndEmptyObjectShallBeDeleted, UA_TYPES_BOOLEAN, UA_TYPES_COUNT - 1);
 	tcase_add_test(tc, arrayCopyShallMakeADeepCopy);
-	tcase_add_loop_test(tc, encodeShallYieldDecode, UA_TYPES_BOOLEAN, UA_TYPES_EVENTNOTIFICATIONLIST);
+	tcase_add_loop_test(tc, encodeShallYieldDecode, UA_TYPES_BOOLEAN, UA_TYPES_COUNT - 1);
 	suite_add_tcase(s, tc);
 	tc = tcase_create("Truncated Buffers");
-	tcase_add_loop_test(tc, decodeShallFailWithTruncatedBufferButSurvive, UA_TYPES_BOOLEAN, UA_TYPES_EVENTNOTIFICATIONLIST);
+	tcase_add_loop_test(tc, decodeShallFailWithTruncatedBufferButSurvive, UA_TYPES_BOOLEAN, UA_TYPES_COUNT - 1);
 	suite_add_tcase(s, tc);
 
 	tc = tcase_create("Fuzzing with Random Buffers");
-	tcase_add_loop_test(tc, decodeScalarBasicTypeFromRandomBufferShallSucceed, UA_TYPES_BOOLEAN, UA_TYPES_GUID);
-	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_TYPES_NODEID, UA_TYPES_EVENTNOTIFICATIONLIST);
+	tcase_add_loop_test(tc, decodeScalarBasicTypeFromRandomBufferShallSucceed, UA_TYPES_BOOLEAN, UA_TYPES_DOUBLE);
+	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_TYPES_NODEID, UA_TYPES_COUNT - 1);
 	suite_add_tcase(s, tc);
 
 	sr = srunner_create(s);

+ 2 - 2
tools/.coverity.sh

@@ -5,8 +5,8 @@
 # of the day to the coverity scan service
 #
 
-COMMITS=`git log --since=today.midnight --oneline | wc -l`
-
+git fetch origin coverity_scan
+COMMITS=`git log --oneline --since=today.midnight | wc -l`
 if [[ "$COMMITS" -le "1" ]]; then
     #first commit a day - push changes to branch coverity_scan
     git clone -b coverity_scan https://$GITAUTH@github.com/acplt/open62541

+ 2 - 2
tools/.deployDoxygen.sh

@@ -5,8 +5,8 @@
 # Doxygen docs to open62541-www
 #
 
-COMMITS=`git log --since=today.midnight --oneline | wc -l`
-
+git fetch origin coverity_scan
+COMMITS=`git log --oneline --since=today.midnight | wc -l`
 if [[ "$COMMITS" -le "1" ]]; then
    git clone --depth=50 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
    cd open62541-www

+ 89 - 0
tools/amalgamate.py

@@ -0,0 +1,89 @@
+from __future__ import print_function
+import re
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('outfile', help='outfile w/o extension')
+parser.add_argument('inputs', nargs='*', action='store', help='input filenames')
+args = parser.parse_args()
+
+outname = args.outfile.split("/")[-1]
+pos = outname.find(".")
+if pos > 0:
+    outname = outname[:pos]
+include_re = re.compile("^#include ([\"<].*[\">]).*$")
+guard_re = re.compile("^#(?:(?:ifndef|define) [A-Z_]+_H_|endif /\* [A-Z_]+_H_ \*/)")
+includes = []
+
+is_c = False
+
+for fname in args.inputs:
+    if("util.h" in fname):
+        is_c = True
+        continue
+    with open(fname) as infile:
+        for line in infile:
+            res = include_re.match(line)
+            if res:
+                inc = res.group(1)
+                if not inc in includes and not inc[0] == '"':
+                    includes.append(inc)
+
+file = open(args.outfile, 'w')
+file.write('''/*
+ * Copyright (C) 2014 the contributors as stated in the AUTHORS file
+ *
+ * This file is part of open62541. open62541 is free software: you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser General
+ * Public License, version 3 (as published by the Free Software Foundation) with
+ * a static linking exception as stated in the LICENSE file provided with
+ * open62541.
+ *
+ * open62541 is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ */
+
+/* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES */\n\n''')
+
+if not is_c:
+    file.write('''#ifndef %s
+#define %s
+
+#ifdef __cplusplus
+extern "C" {
+#endif\n\n''' % (outname.upper() + "_H_", outname.upper() + "_H_") )
+
+if not is_c:
+    for inc in includes:
+        file.write("#include " + inc + "\n")
+else:
+    file.write("#define UA_AMALGAMATE\n")
+    file.write('''#ifndef UA_DYNAMIC_LINKING
+# define UA_DYNAMIC_LINKING
+#endif\n\n''')
+    for fname in args.inputs:
+        if "ua_config.h" in fname or "ua_util.h" in fname:
+            with open(fname) as infile:
+                for line in infile:
+                    file.write(line)
+    file.write("#include \"" + outname + ".h\"\n")
+
+for fname in args.inputs:
+    if not "util.h" in fname:
+        with open(fname) as infile:
+            for line in infile:
+                inc_res = include_re.match(line)
+                guard_res = guard_re.match(line)
+                if not inc_res and not guard_res:
+                    file.write(line)
+
+if not is_c:
+    file.write('''
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* %s */''' % (outname.upper() + "_H_"))
+file.close()

+ 4 - 0
tools/certs/create_self-signed.py

@@ -1,6 +1,7 @@
 import sys
 import os
 import shutil
+import socket
 
 if len(sys.argv) < 2:
     sys.exit('Usage: %s directory to output certificates' % sys.argv[0])
@@ -10,6 +11,9 @@ if not os.path.exists(sys.argv[1]):
     
 os.chdir(os.path.dirname(os.path.abspath(__file__)))
 
+
+os.environ['HOSTNAME'] = socket.gethostname()
+
 os.system("""openssl genrsa -out ca.key 2048""")
 os.system("""openssl req \
 	-x509 \

+ 5 - 1
tools/certs/localhost.cnf

@@ -12,6 +12,8 @@ RANDFILE		= $ENV::HOME/.rnd
 #oid_file		= $ENV::HOME/.oid
 oid_section		= new_oids
 
+hostname = ${ENV::HOSTNAME}
+
 # To use this configuration file with the "-extfile" option of the
 # "openssl x509" utility, name here the section containing the
 # X.509v3 extensions to use:
@@ -224,8 +226,10 @@ subjectAltName = @alt_names
 
 [ alt_names ]
 DNS.1 = localhost
+DNS.2 = ${hostname}
 IP.1 = 127.0.0.1
-URI.1 = urn:localhost:open6251:open62541Server
+IP.2 = 0.0.0.0
+URI.1 = urn:unconfigured:open62541:open62541Server
 
 [ v3_ca ]
 

+ 98 - 29
tools/generate_datatypes.py

@@ -8,6 +8,7 @@ import re
 from lxml import etree
 import itertools
 import argparse
+from pprint import pprint
 
 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,
@@ -19,13 +20,12 @@ zero_copy = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16", "UA_I
 # 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)
-]
+builtin_types = ["UA_Boolean", "UA_SByte", "UA_Byte", "UA_Int16", "UA_UInt16",
+                 "UA_Int32", "UA_UInt32", "UA_Int64", "UA_UInt64", "UA_Float",
+                 "UA_Double", "UA_String", "UA_DateTime", "UA_Guid", "UA_ByteString",
+                 "UA_XmlElement", "UA_NodeId", "UA_ExpandedNodeId", "UA_StatusCode",
+                 "UA_QualifiedName", "UA_LocalizedText", "UA_ExtensionObject", "UA_DataValue",
+                 "UA_Variant", "UA_DiagnosticInfo"]
 
 excluded_types = ["UA_NodeIdType", "UA_InstanceNode", "UA_TypeNode", "UA_Node", "UA_ObjectNode",
                   "UA_ObjectTypeNode", "UA_VariableNode", "UA_VariableTypeNode", "UA_ReferenceTypeNode",
@@ -33,6 +33,31 @@ excluded_types = ["UA_NodeIdType", "UA_InstanceNode", "UA_TypeNode", "UA_Node",
                   "UA_SamplingIntervalDiagnosticsDataType", "UA_SessionSecurityDiagnosticsDataType",
                   "UA_SubscriptionDiagnosticsDataType", "UA_SessionDiagnosticsDataType"]
 
+minimal_types = ["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", "FindServersRequest", "FindServersResponse",
+                 "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",
+                 "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse"]
+
 class TypeDescription(object):
     def __init__(self, name, nodeid, namespaceid):
         self.name = name # without the UA_ prefix
@@ -77,8 +102,33 @@ class BuiltinType(object):
     def typedef_c(self):
         pass
 
-    def typelayout_c(self, namespace_0, outname):
-        return "{.memSize = sizeof(" + self.name + "), " + \
+    def typelayout_c(self, namespace_0, description, outname):
+        if description == None:
+            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
+        else:
+            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % \
+                     (description.namespaceid, description.nodeid)
+        if self.name in ["UA_String", "UA_ByteString", "UA_XmlElement"]:
+            return "{.typeId = " + typeid + \
+                ".memSize = sizeof(" + self.name + "), " + \
+                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
+                ".padding = offsetof(UA_String, data) - sizeof(UA_Int32), .isArray = UA_TRUE }}, " + \
+                ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
+
+        if self.name == "UA_QualifiedName":
+            return "{.typeId = " + typeid + \
+                ".memSize = sizeof(UA_QualifiedName), " + \
+                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".membersSize = 2, .members = {" + \
+                "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
+                ".padding = 0, .isArray = UA_FALSE }," + \
+                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
+                ".padding = offsetof(UA_QualifiedName, name) - sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
+                ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
+                
+        return "{.typeId = " + typeid + \
+            ".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") + \
@@ -109,12 +159,17 @@ class EnumerationType(object):
             ",\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, " + \
+    def typelayout_c(self, namespace_0, description, outname):
+        if description == None:
+            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
+        else:
+            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
+        return "{.typeId = " + typeid + \
+            ".memSize = sizeof(" + self.name + "), " +\
+            ".namespaceZero = UA_TRUE, " + \
+            ".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())
+            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
 
     def functions_c(self, typeTableName):
         return '''#define %s_new (%s*)UA_Int32_new
@@ -140,11 +195,15 @@ class OpaqueType(object):
     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 typelayout_c(self, namespace_0, description, outname):
+        if description == None:
+            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
+        else:
+            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
+        return "{.typeId = " + typeid + \
+            ".memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+            ".namespaceZero = UA_TRUE, .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTESTRING," + \
+            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_BYTESTRING }"
 
     def functions_c(self, typeTableName):
         return '''#define %s_new UA_ByteString_new
@@ -201,8 +260,13 @@ class StructType(object):
                 returnstr += "    " + member.memberType.name + " " +name + ";\n"
         return returnstr + "} " + self.name + ";"
 
-    def typelayout_c(self, namespace_0, outname):
-        layout = "{.memSize = sizeof(" + self.name + "), "+ \
+    def typelayout_c(self, namespace_0, description, outname):
+        if description == None:
+            typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
+        else:
+            typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
+        layout = "{.typeId = "+ typeid + \
+                 ".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() \
@@ -266,6 +330,8 @@ def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
             return True
         if name in excluded_types:
             return True
+        if outname == "ua_types" and not name[3:] in minimal_types:
+            return True
         if "Test" in name: # skip all test types
             return True
         if re.search("NodeId$", name) != None:
@@ -419,7 +485,6 @@ extern "C" {
 ''')
 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():
@@ -438,7 +503,7 @@ printh('''
 #ifdef __cplusplus
 } // extern "C"
 #endif\n
-#endif''')
+#endif /* %s_GENERATED_H_ */''' % outname.upper())
 
 printc('''/**
 * @file ''' + outname + '''_generated.c
@@ -455,13 +520,17 @@ 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) + ",")
+    if args.typedescriptions:
+        td = typedescriptions[t.name]
+    else:
+        td = None
+    printc(t.typelayout_c(args.namespace_id == 0, td, 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("};")
+# 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 - 5
tools/generate_nodeids.py

@@ -32,11 +32,6 @@ 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):