Browse Source

Merge branch 'master' into dev

Conflicts:
	CMakeLists.txt
	README.md
	examples/server.c
	src/server/ua_securechannel_manager.c
	src/server/ua_server.c
	src/server/ua_server_binary.c
	src/server/ua_server_internal.h
	src/server/ua_server_worker.c
	src/server/ua_services_session.c
	src/server/ua_session_manager.c
	src/ua_session.c
	tools/pyUANamespace/generate_open62541CCode.py
	tools/pyUANamespace/logger.py
	tools/pyUANamespace/open62541_MacroHelper.py
	tools/pyUANamespace/ua_builtin_types.py
	tools/pyUANamespace/ua_constants.py
	tools/pyUANamespace/ua_namespace.py
	tools/pyUANamespace/ua_node_types.py
Julius Pfrommer 9 years ago
parent
commit
b125569533
49 changed files with 1753 additions and 24348 deletions
  1. 23 14
      .travis.yml
  2. 74 74
      CMakeLists.txt
  3. 7 6
      README.md
  4. 15 27
      examples/logger_stdout.c
  5. 2 2
      examples/logger_stdout.h
  6. 32 18
      examples/networklayer_tcp.c
  7. 2 2
      examples/networklayer_tcp.h
  8. 2 2
      examples/networklayer_udp.c
  9. 105 50
      examples/server.c
  10. 6 3
      examples/server.cpp
  11. 7 7
      examples/server_simple.c
  12. 0 1
      examples/server_udp.c
  13. 6 2
      include/ua_client.h
  14. 9 0
      src/ua_config.h.in
  15. 23 25
      include/ua_log.h
  16. 65 16
      include/ua_server.h
  17. 41 81
      include/ua_types.h
  18. 50 26
      src/client/ua_client.c
  19. 2 2
      src/server/ua_nodestore_hash.inc
  20. 54 45
      src/server/ua_securechannel_manager.c
  21. 1 0
      src/server/ua_securechannel_manager.h
  22. 339 265
      src/server/ua_server.c
  23. 44 13
      src/server/ua_server_addressspace.c
  24. 51 28
      src/server/ua_server_binary.c
  25. 6 5
      src/server/ua_server_internal.h
  26. 137 91
      src/server/ua_server_worker.c
  27. 44 36
      src/server/ua_services_attribute.c
  28. 1 6
      src/server/ua_services_discovery.c
  29. 13 8
      src/server/ua_services_nodemanagement.c
  30. 58 91
      src/server/ua_services_session.c
  31. 145 108
      src/server/ua_services_view.c
  32. 38 79
      src/server/ua_session_manager.c
  33. 8 13
      src/server/ua_session_manager.h
  34. 28 2
      src/ua_connection.c
  35. 51 21
      src/ua_securechannel.c
  36. 10 3
      src/ua_securechannel.h
  37. 7 65
      src/ua_session.c
  38. 7 10
      src/ua_session.h
  39. 108 40
      src/ua_types.c
  40. 1 1
      src/ua_types_encoding_binary.c
  41. 15 1
      src/ua_util.h
  42. 19 17
      tests/CMakeLists.txt
  43. 16 4
      tests/testing_networklayers.c
  44. 0 20
      tools/.deployDoxygen.sh
  45. 59 0
      tools/.deployGH.sh
  46. 13 5
      tools/amalgamate.py
  47. 6 2
      tools/certs/create_self-signed.py
  48. 3 3
      tools/generate_datatypes.py
  49. 0 23008
      tools/schema/Opc.Ua.NodeSet2.xml

+ 23 - 14
.travis.yml

@@ -29,33 +29,48 @@ before_install:
 script:
 script:
 - echo "Checking the applicability of patches"
 - echo "Checking the applicability of patches"
 - # ./tools/.checkPorts.sh
 - # ./tools/.checkPorts.sh
-- echo "Testing builds"
+- echo "Documentation and certificate build"
 - mkdir -p build
 - mkdir -p build
 - cd build
 - cd build
+- cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_DOCUMENTATION=ON -DGENERATE_SELFSIGNED=ON ..
+- make -j doc
+- make selfsigned
+- cp -r doc ..
+- cp server_cert.der ..
+- echo "Testing builds"
+- cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Cross compile release build for MinGW 32 bit"
 - echo "Cross compile release build for MinGW 32 bit"
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - make -j
 - make -j
 - cp ../README.md .
 - cp ../README.md .
-- zip open62541-win32.zip README.md exampleServer.exe exampleClient.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
+- cp ../LICENSE .
+- cp ../AUTHORS .
+- cp -r ../doc .
+- cp ../server_cert.der .
+- zip -r open62541-win32.zip doc server_cert.der LICENSE AUTHORS README.md server_static.exe server.exe client.exe client_static.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
 - cp open62541-win32.zip ..
 - cp open62541-win32.zip ..
 - cd .. && rm build -rf && mkdir -p build && cd build
 - cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Cross compile release build for MinGW 64 bit"
 - echo "Cross compile release build for MinGW 64 bit"
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw64.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw64.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - make -j
 - make -j
 - cp ../README.md .
 - cp ../README.md .
-- zip open62541-win64.zip README.md exampleServer.exe exampleClient.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
+- cp ../LICENSE .
+- cp ../AUTHORS .
+- cp -r ../doc .
+- cp ../server_cert.der .
+- zip -r open62541-win64.zip doc server_cert.der LICENSE AUTHORS README.md server_static.exe server.exe client.exe client_static.exe libopen62541.dll libopen62541.dll.a open62541.h open62541.c
 - cp open62541-win64.zip ..
 - cp open62541-win64.zip ..
 - cd .. && rm build -rf && mkdir -p build && cd build
 - cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Cross compile release build for 32-bit linux"
 - echo "Cross compile release build for 32-bit linux"
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-gcc-m32.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-gcc-m32.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - make -j
 - make -j
-- tar -pczf open62541-linux32.tar.gz ../README.md exampleServer exampleClient libopen62541.so open62541.h open62541.c
+- tar -pczf open62541-linux32.tar.gz ../doc ../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.so open62541.h open62541.c
 - cp open62541-linux32.tar.gz ..
 - cp open62541-linux32.tar.gz ..
 - cd .. && rm build -rf && mkdir -p build && cd build
 - cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Compile release build for 64-bit linux"
 - echo "Compile release build for 64-bit linux"
 - cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_AMALGAMATION=ON -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_AMALGAMATION=ON -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - make -j
 - make -j
-- tar -pczf open62541-linux64.tar.gz ../README.md exampleServer exampleClient libopen62541.so open62541.h open62541.c
+- tar -pczf open62541-linux64.tar.gz ../doc ../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.so open62541.h open62541.c
 - cp open62541-linux64.tar.gz ..
 - cp open62541-linux64.tar.gz ..
 - cp open62541.h .. #copy single file-release
 - cp open62541.h .. #copy single file-release
 - cp open62541.c .. #copy single file-release
 - cp open62541.c .. #copy single file-release
@@ -74,15 +89,9 @@ script:
 - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEMO_NODESET=ON -DBUILD_UNIT_TESTS=ON -DENABLE_COVERAGE=ON ..
 - cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEMO_NODESET=ON -DBUILD_UNIT_TESTS=ON -DENABLE_COVERAGE=ON ..
 - make -j && make test
 - make -j && make test
 - coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../
 - coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../
-- cd .. && rm build -rf && mkdir -p build && cd build
-- echo "Documentation build"
-- cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_DOCUMENTATION=ON ..
-- make -j
-- echo "Generate documentation"
-- make -j doc
-- cd ..
+- cd .. 
 after_success:
 after_success:
-- ./tools/.deployDoxygen.sh
+- ./tools/.deployGH.sh
 - ./tools/.coverity.sh
 - ./tools/.coverity.sh
 before_deploy:
 before_deploy:
 - rm build -rf && mkdir -p build && cd build
 - rm build -rf && mkdir -p build && cd build
@@ -93,7 +102,7 @@ before_deploy:
 - export PATH=$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/
 - export PATH=$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-rpi64.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-rpi64.cmake -DENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
 - make -j
 - make -j
-- tar -pczf open62541-raspberrypi.tar.gz ../README.md exampleServer exampleClient libopen62541.so open62541.h open62541.c
+- tar -pczf open62541-raspberrypi.tar.gz ../doc ../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.so open62541.h open62541.c
 - cp open62541-raspberrypi.tar.gz ..
 - cp open62541-raspberrypi.tar.gz ..
 - cd ..
 - cd ..
 deploy:
 deploy:

+ 74 - 74
CMakeLists.txt

@@ -2,12 +2,23 @@ cmake_minimum_required(VERSION 2.8.8)
 # set(CMAKE_VERBOSE_MAKEFILE ON)
 # set(CMAKE_VERBOSE_MAKEFILE ON)
 
 
 project(open62541 C)
 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})
+
+find_package(Git)
+if(GIT_FOUND)
+    execute_process(COMMAND ${GIT_EXECUTABLE} describe --abbrev=7 --dirty --always --tags RESULT_VARIABLE res_var OUTPUT_VARIABLE GIT_COM_ID )
+    if( NOT ${res_var} EQUAL 0 )
+        set( GIT_COMMIT_ID "git commit id unknown")
+        message( WARNING "Git failed (not a repo, or no tags). Build will not contain git revision info." )
+    else()
+        string( REPLACE "\n" "" GIT_COMMIT_ID ${GIT_COM_ID} )
+    endif()
+else()
+    set( GIT_COMMIT_ID "unknown (git not found!)")
+    message( WARNING "Git not found. Build will not contain git revision info." )
+endif()
+add_definitions("-DVERSION=${GIT_COMMIT_ID}")
+
+MESSAGE (STATUS "Git version: "  ${GIT_COMMIT_ID})
 
 
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
 
 
@@ -34,9 +45,9 @@ if(CMAKE_COMPILER_IS_GNUCC OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
         set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
         set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
 	endif()
 	endif()
     if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
     if(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR CMAKE_BUILD_TYPE STREQUAL "Release")
-        add_definitions(-flto)
-        set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -flto -s")
-        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto -s")
+#        add_definitions(-flto)
+        set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -s")
+        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s")
     endif()
     endif()
     option(ENABLESUBSCRIPTIONS "Enable compilation of subscription and monitoring support." OFF)
     option(ENABLESUBSCRIPTIONS "Enable compilation of subscription and monitoring support." OFF)
     if (ENABLESUBSCRIPTIONS)
     if (ENABLESUBSCRIPTIONS)
@@ -50,11 +61,12 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
-                     ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h
                      ${PROJECT_SOURCE_DIR}/include/ua_connection.h
                      ${PROJECT_SOURCE_DIR}/include/ua_connection.h
                      ${PROJECT_SOURCE_DIR}/include/ua_log.h
                      ${PROJECT_SOURCE_DIR}/include/ua_log.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server.h
-                     ${PROJECT_SOURCE_DIR}/include/ua_client.h)
+                     ${PROJECT_SOURCE_DIR}/include/ua_client.h
+                     ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h 
+                     ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h)
 set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
 set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
                      ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
@@ -89,7 +101,9 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.c
-                ${PROJECT_SOURCE_DIR}/src/client/ua_client.c)
+                ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
+                ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c 
+                ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
                 ##TODO: make client stuff optional
                 ##TODO: make client stuff optional
 
 
 ## generate code from xml definitions
 ## generate code from xml definitions
@@ -127,32 +141,11 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_nodeids.py
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_nodeids.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
 
 
-option(LOADGENERATEDNS "Generate and load UA XML Namespace 0 definition" OFF)
-if(LOADGENERATEDNS)
-add_definitions(-DLOADGENERATEDNS)
-add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h
-                   ## Note: currently only Opc.Ua.NodeSet2.xml is included in the generated header. You can extend the call to include any number of XML files as parameters.
-                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.NodeSet2.xml ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h
-                   DEPENDS ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py  
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py  
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/open62541_MacroHelper.py  
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_builtin_types.py  
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_constants.py  
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_namespace.py  
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_node_types.py
-)
-else()
-add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h
-                   COMMAND touch ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h
-		   DEPENDS
-)
-endif()
-
 ## logging
 ## logging
 set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")
 set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")
 
 
 ## multithreading
 ## multithreading
-option(ENABLE_MULTITHREADING "Enable multithreading" OFF)
+option(ENABLE_MULTITHREADING "Enable multithreading (experimental)" OFF)
 if(ENABLE_MULTITHREADING)
 if(ENABLE_MULTITHREADING)
     add_definitions(-DUA_MULTITHREADING)
     add_definitions(-DUA_MULTITHREADING)
     find_package(Threads REQUIRED)
     find_package(Threads REQUIRED)
@@ -161,8 +154,13 @@ else()
     list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.c)
     list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.c)
 endif()
 endif()
 
 
+option(ENABLE_EXTERNAL_NAMESPACES "Enable namespace handling by an external component (experimental)" OFF)
+if(ENABLE_EXTERNAL_NAMESPACES)
+    add_definitions(-DUA_EXTERNAL_NAMESPACES)
+endif()
+
 ## set the precompiler flags
 ## set the precompiler flags
-configure_file("src/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
+configure_file("include/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
 
 
 ## extensions
 ## extensions
 option(EXTENSION_UDP "Enable udp extension" OFF)
 option(EXTENSION_UDP "Enable udp extension" OFF)
@@ -180,29 +178,24 @@ if(EXTENSION_STATELESS)
 	add_definitions(-DEXTENSION_STATELESS)
 	add_definitions(-DEXTENSION_STATELESS)
 endif()
 endif()
 
 
-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()
-
 option(ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
 option(ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
-add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h
+               PRE_BUILD
+               COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${GIT_COMMIT_ID} ${CMAKE_CURRENT_BINARY_DIR}/open62541.h ${exported_headers}
+
+
+               DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${exported_headers} ${internal_headers})
+
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.c
                PRE_BUILD
                PRE_BUILD
-               COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.h ${exported_headers}
-                                                                              ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h
-                                                                              ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h
-               COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
+
+               COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${GIT_COMMIT_ID} ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
                               ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
                               ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
-                                                                              ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c
-                                                                              ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
-               DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${exported_headers} ${internal_headers}
-                       ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
-                       ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h
-                       ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
+
+               DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${PROJECT_BINARY_DIR}/src_generated/ua_config.h ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources})
 
 
 if(ENABLE_AMALGAMATION)
 if(ENABLE_AMALGAMATION)
-    add_custom_target(amalgamation ALL DEPENDS ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c)
+    add_custom_target(amalgamation ALL DEPENDS ${PROJECT_BINARY_DIR}/open62541.h)
     add_library(open62541-object OBJECT ${PROJECT_BINARY_DIR}/open62541.c)
     add_library(open62541-object OBJECT ${PROJECT_BINARY_DIR}/open62541.c)
     include_directories(${PROJECT_BINARY_DIR})
     include_directories(${PROJECT_BINARY_DIR})
 else()
 else()
@@ -213,8 +206,10 @@ else()
     include_directories(${PROJECT_SOURCE_DIR}/src)
     include_directories(${PROJECT_SOURCE_DIR}/src)
     include_directories(${PROJECT_BINARY_DIR}/src_generated)
     include_directories(${PROJECT_BINARY_DIR}/src_generated)
 endif()
 endif()
+target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING)
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
-if(WIN32 AND ENABLE_AMALGAMATION)
+target_compile_definitions(open62541 PRIVATE -DUA_DYNAMIC_LINKING)
+if(WIN32)
     target_link_libraries(open62541 ws2_32) #since networklayer_tcp is linked into the amalgate
     target_link_libraries(open62541 ws2_32) #since networklayer_tcp is linked into the amalgate
 endif()
 endif()
 
 
@@ -239,21 +234,23 @@ endif()
 option(BUILD_EXAMPLESERVER "Build the example server" OFF)
 option(BUILD_EXAMPLESERVER "Build the example server" OFF)
 if(BUILD_EXAMPLESERVER)
 if(BUILD_EXAMPLESERVER)
     set(server_source $<TARGET_OBJECTS:open62541-object>)
     set(server_source $<TARGET_OBJECTS:open62541-object>)
-    if(NOT ENABLE_AMALGAMATION)
-        list(APPEND server_source examples/networklayer_tcp.c examples/logger_stdout.c)
-    endif()
-    add_executable(exampleServer examples/server.c ${server_source})
-    add_executable(exampleServer_simple examples/server_simple.c ${server_source})
+    add_executable(server_static examples/server.c ${server_source})
+    add_executable(server_simple examples/server_simple.c ${server_source})
+    add_executable(server examples/server.c)
+	target_link_libraries(server open62541)
     if(WIN32)
     if(WIN32)
-        target_link_libraries(exampleServer ws2_32)
-        target_link_libraries(exampleServer_simple ws2_32)
+        target_link_libraries(server_static ws2_32)
+        target_link_libraries(server_simple ws2_32)
+        target_link_libraries(server ws2_32)
     else()
     else()
-        target_link_libraries(exampleServer rt)
-        target_link_libraries(exampleServer_simple rt)
+        target_link_libraries(server_static rt)
+        target_link_libraries(server_simple rt)
+        target_link_libraries(server rt)
     endif()
     endif()
     if(ENABLE_MULTITHREADING)
     if(ENABLE_MULTITHREADING)
-        target_link_libraries(exampleServer urcu-cds urcu urcu-common pthread)
-        target_link_libraries(exampleServer_simple urcu-cds urcu urcu-common pthread)
+        target_link_libraries(server_static urcu-cds urcu urcu-common pthread)
+        target_link_libraries(server_simple urcu-cds urcu urcu-common pthread)
+        target_link_libraries(server urcu-cds urcu urcu-common pthread)
     endif()
     endif()
 endif()
 endif()
 
 
@@ -261,6 +258,7 @@ endif()
 option(GENERATE_SELFSIGNED "Generate self-signed certificates" OFF)
 option(GENERATE_SELFSIGNED "Generate self-signed certificates" OFF)
 if(GENERATE_SELFSIGNED)
 if(GENERATE_SELFSIGNED)
     message(STATUS "Enabling self-signed certificates")
     message(STATUS "Enabling self-signed certificates")
+    find_package(OpenSSL REQUIRED)
     add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/localhost.der
     add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/localhost.der
                               ${PROJECT_BINARY_DIR}/ca.crt
                               ${PROJECT_BINARY_DIR}/ca.crt
                    COMMAND python ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py ${PROJECT_BINARY_DIR}
                    COMMAND python ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py ${PROJECT_BINARY_DIR}
@@ -274,22 +272,24 @@ option(BUILD_EXAMPLECLIENT "Build a test client" OFF)
 if(BUILD_EXAMPLECLIENT)
 if(BUILD_EXAMPLECLIENT)
 	add_definitions(-DBENCHMARK)
 	add_definitions(-DBENCHMARK)
     set(client_source $<TARGET_OBJECTS:open62541-object>)
     set(client_source $<TARGET_OBJECTS:open62541-object>)
-    if(NOT ENABLE_AMALGAMATION)
-        list(APPEND client_source examples/networklayer_tcp.c examples/logger_stdout.c)
-    endif()
-	add_executable(exampleClient examples/client.c ${client_source})
+	add_executable(client_static examples/client.c ${client_source})
+	add_executable(client examples/client.c)
+	target_link_libraries(client open62541)
     if(WIN32)
     if(WIN32)
-        target_link_libraries(exampleClient ws2_32)
+        target_link_libraries(client_static ws2_32)
+        target_link_libraries(client ws2_32)
     else()
     else()
-        target_link_libraries(exampleClient rt)
+        target_link_libraries(client_static rt)
+        target_link_libraries(client rt)
     endif()
     endif()
     if(ENABLE_MULTITHREADING)
     if(ENABLE_MULTITHREADING)
-        target_link_libraries(exampleClient urcu-cds urcu urcu-common pthread)
+        target_link_libraries(client_static urcu-cds urcu urcu-common pthread)
+        target_link_libraries(client urcu-cds urcu urcu-common pthread)
     endif()
     endif()
     if(EXTENSION_STATELESS)
     if(EXTENSION_STATELESS)
-        add_executable(statelessClient examples/client_stateless.c ${client_source})
+        add_executable(client_stateless examples/client_stateless.c ${client_source})
         if(ENABLE_MULTITHREADING)
         if(ENABLE_MULTITHREADING)
-            target_link_libraries(statelessClient urcu-cds urcu urcu-common pthread)
+            target_link_libraries(client_stateless urcu-cds urcu urcu-common pthread)
         endif()
         endif()
     endif()
     endif()
 endif()
 endif()

+ 7 - 6
README.md

@@ -19,6 +19,8 @@ For discussion and help, you can use
 - our [IRC channel](http://webchat.freenode.net/?channels=%23open62541)
 - our [IRC channel](http://webchat.freenode.net/?channels=%23open62541)
 - the [bugtracker](https://github.com/acplt/open62541/issues)
 - the [bugtracker](https://github.com/acplt/open62541/issues)
 
 
+Auomated builds of 50 last single-file distributions are available [here](http://open62541.org/releases)
+
 ### Contribute to open62541
 ### Contribute to open62541
 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:
 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)
 - [Report bugs](https://github.com/acplt/open62541/issues)
@@ -50,15 +52,13 @@ int main(int argc, char** argv)
     UA_Server_setLogger(server, Logger_Stdout_new());
     UA_Server_setLogger(server, Logger_Stdout_new());
     UA_Server_addNetworkLayer(server,
     UA_Server_addNetworkLayer(server,
         ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
         ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
-    UA_UInt16 nsIndex = UA_Server_addNamespace(server, 
-                                  UA_ServerConfig_standard.Application_applicationURI);
 
 
     /* add a variable node */
     /* add a variable node */
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(nsIndex, "the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(nsIndex, "the.answer");
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
@@ -78,7 +78,7 @@ int main(int argc, char** argv)
 
 
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
 {
 {
-    UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
+    UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
     UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
     UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
                                              "opc.tcp://localhost:16664");
                                              "opc.tcp://localhost:16664");
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
@@ -91,7 +91,8 @@ int main(int argc, char *argv[])
     UA_ReadRequest_init(&req);
     UA_ReadRequest_init(&req);
     req.nodesToRead = UA_ReadValueId_new();
     req.nodesToRead = UA_ReadValueId_new();
     req.nodesToReadSize = 1;
     req.nodesToReadSize = 1;
-    req.nodesToRead[0].nodeId = UA_NODEID_STRING(1, "the.answer");
+    /* copy the nodeid-string to the heap (deleted with the req) */
+    req.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     req.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     req.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
 
 
     UA_ReadResponse resp = UA_Client_read(client, &req);
     UA_ReadResponse resp = UA_Client_read(client, &req);

+ 15 - 27
examples/logger_stdout.c

@@ -15,39 +15,27 @@ static void print_time(void) {
 	UA_ByteString_deleteMembers(&str);
 	UA_ByteString_deleteMembers(&str);
 }
 }
 
 
-#define LOG_FUNCTION(LEVEL) \
-	static void log_##LEVEL(UA_LoggerCategory category, const char *msg, ...) { \
-        printf("[");                                                    \
-		print_time();                                                   \
-        va_list ap;                                                     \
-        va_start(ap, msg);                                              \
-        printf("] " #LEVEL "/%s\t", UA_LoggerCategoryNames[category]);  \
-        vprintf(msg, ap);                                               \
-        printf("\n");                                                   \
-        va_end(ap);                                                     \
-	}
+const char *LogLevelNames[6] = {"trace", "debug", "info", "warning", "error", "fatal"};
+const char *LogCategoryNames[4] = {"communication", "server", "client", "userland"};
 
 
-#if defined(__GNUC__) || defined(__clang__)
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic push
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #endif
 #endif
-LOG_FUNCTION(trace)
-LOG_FUNCTION(debug)
-LOG_FUNCTION(info)
-LOG_FUNCTION(warning)
-LOG_FUNCTION(error)
-LOG_FUNCTION(fatal)
-#if defined(__GNUC__) || defined(__clang__)
+static void Logger_Stdout(UA_LogLevel level, UA_LogCategory category, const char *msg, ...) {
+    printf("[");
+    print_time();
+    va_list ap;
+    va_start(ap, msg);
+    printf("] %s/%s\t", LogLevelNames[level], LogCategoryNames[category]);
+    vprintf(msg, ap);
+    printf("\n");
+    va_end(ap);
+}
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic pop
 #pragma GCC diagnostic pop
 #endif
 #endif
 
 
 UA_Logger Logger_Stdout_new(void) {
 UA_Logger Logger_Stdout_new(void) {
-	return (UA_Logger){
-		.log_trace = log_trace,
-		.log_debug = log_debug,
-		.log_info = log_info,
-		.log_warning = log_warning,
-		.log_error = log_error,
-		.log_fatal = log_fatal
-	};
+	return Logger_Stdout;
 }
 }

+ 2 - 2
examples/logger_stdout.h

@@ -14,6 +14,6 @@
 #endif
 #endif
 
 
 /** Initialises the logger for the current thread. */
 /** Initialises the logger for the current thread. */
-UA_Logger Logger_Stdout_new(void);
+UA_EXPORT UA_Logger Logger_Stdout_new(void);
 
 
-#endif /* LOGGER_STDOUT_H_ */
+#endif /* LOGGER_STDOUT_H_ */

+ 32 - 18
examples/networklayer_tcp.c

@@ -47,11 +47,11 @@ static UA_StatusCode socket_write(UA_Connection *connection, const UA_ByteString
         do {
         do {
 #ifdef _WIN32
 #ifdef _WIN32
             n = send((SOCKET)connection->sockfd, (const char*)buf->data, buf->length, 0);
             n = send((SOCKET)connection->sockfd, (const char*)buf->data, buf->length, 0);
-            if(n < 0 && WSAGetLastError() != WSAEINTR)
+            if(n < 0 && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK)
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
 #else
 #else
             n = send(connection->sockfd, (const char*)buf->data, buf->length, MSG_NOSIGNAL);
             n = send(connection->sockfd, (const char*)buf->data, buf->length, MSG_NOSIGNAL);
-            if(n == -1L && errno != EINTR)
+            if(n == -1L && errno != EINTR && errno != EAGAIN)
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
 #endif
 #endif
         } while (n == -1L);
         } while (n == -1L);
@@ -62,12 +62,14 @@ static UA_StatusCode socket_write(UA_Connection *connection, const UA_ByteString
 
 
 static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
 static UA_StatusCode socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-	if(response->data == UA_NULL)
+	if(response->data == NULL)
         retval = connection->getBuffer(connection, response, connection->localConf.recvBufferSize);
         retval = connection->getBuffer(connection, response, connection->localConf.recvBufferSize);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
     struct timeval tmptv = {0, timeout * 1000};
     struct timeval tmptv = {0, timeout * 1000};
-    setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval));
+    if(0 != setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval))){
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
     int ret = recv(connection->sockfd, (char*)response->data, response->length, 0);
     int ret = recv(connection->sockfd, (char*)response->data, response->length, 0);
 	if(ret == 0) {
 	if(ret == 0) {
 		connection->releaseBuffer(connection, response);
 		connection->releaseBuffer(connection, response);
@@ -214,6 +216,9 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
     socket_close(connection);
     socket_close(connection);
     ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)connection->handle;
     ServerNetworkLayerTCP *layer = (ServerNetworkLayerTCP*)connection->handle;
     struct DeleteList *d = malloc(sizeof(struct DeleteList));
     struct DeleteList *d = malloc(sizeof(struct DeleteList));
+    if(!d){
+        return;
+    }
     d->connection = connection;
     d->connection = connection;
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     while(1) {
     while(1) {
@@ -257,13 +262,13 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, U
     layer->logger = logger;
     layer->logger = logger;
 #ifdef _WIN32
 #ifdef _WIN32
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket, code: %d",
+        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error opening socket, code: %d",
                        WSAGetLastError());
                        WSAGetLastError());
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
 #else
 #else
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error opening socket");
+        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error opening socket");
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     } 
     } 
 #endif
 #endif
@@ -274,19 +279,19 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, U
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval,
                   SO_REUSEADDR, (const char *)&optval,
                   sizeof(optval)) == -1) {
                   sizeof(optval)) == -1) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during setting of socket options");
+        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error during setting of socket options");
         CLOSESOCKET(layer->serversockfd);
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
     if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
     if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
             sizeof(serv_addr)) < 0) {
-        UA_LOG_WARNING((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Error during socket binding");
+        UA_LOG_WARNING((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Error during socket binding");
         CLOSESOCKET(layer->serversockfd);
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
     socket_set_nonblocking(layer->serversockfd);
     socket_set_nonblocking(layer->serversockfd);
     listen(layer->serversockfd, MAXBACKLOG);
     listen(layer->serversockfd, MAXBACKLOG);
-    UA_LOG_INFO((*layer->logger), UA_LOGGERCATEGORY_COMMUNICATION, "Listening on %.*s",
+    UA_LOG_INFO((*layer->logger), UA_LOGCATEGORY_COMMUNICATION, "Listening on %.*s",
                 layer->discoveryUrl.length, layer->discoveryUrl.data);
                 layer->discoveryUrl.length, layer->discoveryUrl.data);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
@@ -329,7 +334,7 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
 #endif
 #endif
     removeMappings(layer, deletes);
     removeMappings(layer, deletes);
     setFDSet(layer);
     setFDSet(layer);
-    struct timeval tmptv = {0, timeout * 1000};
+    struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
     UA_Int32 resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
     UA_WorkItem *items;
     UA_WorkItem *items;
     if(resultsize < 0 || !(items = malloc(sizeof(UA_WorkItem)*(resultsize+1)))) {
     if(resultsize < 0 || !(items = malloc(sizeof(UA_WorkItem)*(resultsize+1)))) {
@@ -396,6 +401,9 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
         j++;
         j++;
     }
     }
 
 
+    if(buf.data)
+        free(buf.data);
+
     /* free the array if there is no work */
     /* free the array if there is no work */
     if(j == 0) {
     if(j == 0) {
         free(items);
         free(items);
@@ -431,10 +439,11 @@ static UA_Int32 ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Work
 /* run only when the server is stopped */
 /* run only when the server is stopped */
 static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
 static void ServerNetworkLayerTCP_delete(ServerNetworkLayerTCP *layer) {
     UA_String_deleteMembers(&layer->discoveryUrl);
     UA_String_deleteMembers(&layer->discoveryUrl);
+    removeMappings(layer, layer->deletes);
+    freeConnections(NULL, layer->deletes);
     for(size_t i = 0; i < layer->mappingsSize; i++)
     for(size_t i = 0; i < layer->mappingsSize; i++)
         free(layer->mappings[i].connection);
         free(layer->mappings[i].connection);
     free(layer->mappings);
     free(layer->mappings);
-    freeConnections(NULL, layer->deletes);
     free(layer);
     free(layer);
 }
 }
 
 
@@ -445,7 +454,13 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UIn
     wVersionRequested = MAKEWORD(2, 2);
     wVersionRequested = MAKEWORD(2, 2);
     WSAStartup(wVersionRequested, &wsaData);
     WSAStartup(wVersionRequested, &wsaData);
 #endif
 #endif
+    UA_ServerNetworkLayer nl;
+    memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
+
     ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
     ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
+    if(!layer){
+        return nl;
+    }
     layer->conf = conf;
     layer->conf = conf;
     layer->mappingsSize = 0;
     layer->mappingsSize = 0;
     layer->mappings = NULL;
     layer->mappings = NULL;
@@ -455,7 +470,6 @@ UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UIn
     gethostname(hostname, 255);
     gethostname(hostname, 255);
     UA_String_copyprintf("opc.tcp://%s:%d", &layer->discoveryUrl, hostname, port);
     UA_String_copyprintf("opc.tcp://%s:%d", &layer->discoveryUrl, hostname, port);
 
 
-    UA_ServerNetworkLayer nl;
     nl.nlHandle = layer;
     nl.nlHandle = layer;
     nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerTCP_start;
     nl.start = (UA_StatusCode (*)(void*, UA_Logger *logger))ServerNetworkLayerTCP_start;
     nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16))ServerNetworkLayerTCP_getWork;
     nl.getWork = (UA_Int32 (*)(void*, UA_WorkItem**, UA_UInt16))ServerNetworkLayerTCP_getWork;
@@ -475,11 +489,11 @@ UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger
 
 
     size_t urlLength = strlen(endpointUrl);
     size_t urlLength = strlen(endpointUrl);
     if(urlLength < 11 || urlLength >= 512) {
     if(urlLength < 11 || urlLength >= 512) {
-        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url size invalid");
+        UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Server url size invalid");
         return connection;
         return connection;
     }
     }
     if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) {
     if(strncmp(endpointUrl, "opc.tcp://", 10) != 0) {
-        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Server url does not begin with opc.tcp://");
+        UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Server url does not begin with opc.tcp://");
         return connection;
         return connection;
     }
     }
 
 
@@ -492,7 +506,7 @@ UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger
         }
         }
     }
     }
     if(port == 0) {
     if(port == 0) {
-        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Port invalid");
+        UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Port invalid");
         return connection;
         return connection;
     }
     }
 
 
@@ -509,12 +523,12 @@ UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger
 #else
 #else
     if((connection.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
     if((connection.sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
 #endif
 #endif
-        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Could not create socket");
+        UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Could not create socket");
         return connection;
         return connection;
     }
     }
     struct hostent *server = gethostbyname(hostname);
     struct hostent *server = gethostbyname(hostname);
     if(server == NULL) {
     if(server == NULL) {
-        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "DNS lookup of %s failed", hostname);
+        UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "DNS lookup of %s failed", hostname);
         return connection;
         return connection;
     }
     }
     struct sockaddr_in server_addr;
     struct sockaddr_in server_addr;
@@ -523,7 +537,7 @@ UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger
     server_addr.sin_family = AF_INET;
     server_addr.sin_family = AF_INET;
     server_addr.sin_port = htons(port);
     server_addr.sin_port = htons(port);
     if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
     if(connect(connection.sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
-        UA_LOG_WARNING((*logger), UA_LOGGERCATEGORY_COMMUNICATION, "Connection failed");
+        UA_LOG_WARNING((*logger), UA_LOGCATEGORY_COMMUNICATION, "Connection failed");
         return connection;
         return connection;
     }
     }
     connection.state = UA_CONNECTION_OPENING;
     connection.state = UA_CONNECTION_OPENING;

+ 2 - 2
examples/networklayer_tcp.h

@@ -18,8 +18,8 @@ extern "C" {
 #endif
 #endif
 
 
 /** @brief Create the TCP networklayer and listen to the specified port */
 /** @brief Create the TCP networklayer and listen to the specified port */
-UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
-UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger);
+UA_EXPORT UA_ServerNetworkLayer ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+UA_EXPORT UA_Connection ClientNetworkLayerTCP_connect(char *endpointUrl, UA_Logger *logger);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"

+ 2 - 2
examples/networklayer_udp.c

@@ -78,12 +78,12 @@ static void writeCallbackUDP(UDPConnection *handle, UA_ByteStringArray gather_bu
 	}
 	}
 	struct sockaddr_in *sin = NULL;
 	struct sockaddr_in *sin = NULL;
 	if (handle->from.sa_family == AF_INET) {
 	if (handle->from.sa_family == AF_INET) {
-#if defined(__GNUC__) || defined(__clang__)
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic push
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
 #pragma GCC diagnostic ignored "-Wcast-align"
 #endif
 #endif
 	    sin = (struct sockaddr_in *) &(handle->from);
 	    sin = (struct sockaddr_in *) &(handle->from);
-#if defined(__GNUC__) || defined(__clang__)
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic pop
 #pragma GCC diagnostic pop
 #endif
 #endif
 	} else {
 	} else {

+ 105 - 50
examples/server.c

@@ -8,6 +8,8 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
+#include <unistd.h> //access
+
 #define __USE_XOPEN2K
 #define __USE_XOPEN2K
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
 # include <pthread.h>
 # include <pthread.h>
@@ -33,7 +35,13 @@ UA_Logger logger;
 /*************************/
 /*************************/
 /* Read-only data source */
 /* Read-only data source */
 /*************************/
 /*************************/
-static UA_StatusCode readTimeData(void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+static UA_StatusCode readTimeData(void *handle, UA_Boolean sourceTimeStamp,
+                                  const UA_NumericRange *range, UA_DataValue *value) {
+    if(range) {
+        value->hasStatus = UA_TRUE;
+        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
+        return UA_STATUSCODE_GOOD;
+    }
 	UA_DateTime *currentTime = UA_DateTime_new();
 	UA_DateTime *currentTime = UA_DateTime_new();
 	if(!currentTime)
 	if(!currentTime)
 		return UA_STATUSCODE_BADOUTOFMEMORY;
 		return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -52,7 +60,8 @@ static UA_StatusCode readTimeData(void *handle, UA_Boolean sourceTimeStamp, UA_D
 }
 }
 
 
 static void releaseTimeData(void *handle, UA_DataValue *value) {
 static void releaseTimeData(void *handle, UA_DataValue *value) {
-	UA_DateTime_delete((UA_DateTime*)value->value.data);
+    if(value->hasValue)
+        UA_DateTime_delete((UA_DateTime*)value->value.data);
 }
 }
 
 
 /*****************************/
 /*****************************/
@@ -60,7 +69,14 @@ static void releaseTimeData(void *handle, UA_DataValue *value) {
 /*      Only on Linux        */
 /*      Only on Linux        */
 /*****************************/
 /*****************************/
 FILE* temperatureFile = NULL;
 FILE* temperatureFile = NULL;
-static UA_StatusCode readTemperature(void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+static UA_StatusCode readTemperature(void *handle, UA_Boolean sourceTimeStamp,
+                                     const UA_NumericRange *range, UA_DataValue *value) {
+    if(range) {
+        value->hasStatus = UA_TRUE;
+        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
+        return UA_STATUSCODE_GOOD;
+    }
+
 	UA_Double* currentTemperature = UA_Double_new();
 	UA_Double* currentTemperature = UA_Double_new();
 
 
 	if(!currentTemperature)
 	if(!currentTemperature)
@@ -69,7 +85,7 @@ static UA_StatusCode readTemperature(void *handle, UA_Boolean sourceTimeStamp, U
 	fseek(temperatureFile, 0, SEEK_SET);
 	fseek(temperatureFile, 0, SEEK_SET);
 
 
 	if(fscanf(temperatureFile, "%lf", currentTemperature) != 1){
 	if(fscanf(temperatureFile, "%lf", currentTemperature) != 1){
-		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "Can not parse temperature");
+		UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "Can not parse temperature");
 		exit(1);
 		exit(1);
 	}
 	}
 
 
@@ -85,7 +101,8 @@ static UA_StatusCode readTemperature(void *handle, UA_Boolean sourceTimeStamp, U
 }
 }
 
 
 static void releaseTemperature(void *handle, UA_DataValue *value) {
 static void releaseTemperature(void *handle, UA_DataValue *value) {
-	UA_Double_delete((UA_Double*)value->value.data);
+    if(value->hasValue)
+        UA_Double_delete((UA_Double*)value->value.data);
 }
 }
 
 
 /*************************/
 /*************************/
@@ -98,7 +115,14 @@ FILE* triggerFile = NULL;
 FILE* ledFile = NULL;
 FILE* ledFile = NULL;
 UA_Boolean ledStatus = 0;
 UA_Boolean ledStatus = 0;
 
 
-static UA_StatusCode readLedStatus(void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+static UA_StatusCode readLedStatus(void *handle, UA_Boolean sourceTimeStamp,
+                                   const UA_NumericRange *range, UA_DataValue *value) {
+    if(range) {
+        value->hasStatus = UA_TRUE;
+        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
+        return UA_STATUSCODE_GOOD;
+    }
+
 	/* In order to reduce blocking time, we could alloc memory for every read
 	/* In order to reduce blocking time, we could alloc memory for every read
        and return a copy of the data. */
        and return a copy of the data. */
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
@@ -118,6 +142,8 @@ static UA_StatusCode readLedStatus(void *handle, UA_Boolean sourceTimeStamp, UA_
 }
 }
 
 
 static void releaseLedStatus(void *handle, UA_DataValue *value) {
 static void releaseLedStatus(void *handle, UA_DataValue *value) {
+    if(!value->hasValue)
+        return;
 	/* If we allocated memory for a specific read, free the content of the
 	/* If we allocated memory for a specific read, free the content of the
        variantdata. */
        variantdata. */
 	value->value.arrayLength = -1;
 	value->value.arrayLength = -1;
@@ -127,7 +153,10 @@ static void releaseLedStatus(void *handle, UA_DataValue *value) {
 #endif
 #endif
 }
 }
 
 
-static UA_StatusCode writeLedStatus(void *handle, const UA_Variant *data) {
+static UA_StatusCode writeLedStatus(void *handle, const UA_Variant *data, const UA_NumericRange *range) {
+    if(range)
+        return UA_STATUSCODE_BADINDEXRANGEINVALID;
+    
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
 	pthread_rwlock_wrlock(&writeLock);
 	pthread_rwlock_wrlock(&writeLock);
 #endif
 #endif
@@ -151,12 +180,8 @@ static UA_StatusCode writeLedStatus(void *handle, const UA_Variant *data) {
 	return UA_STATUSCODE_GOOD;
 	return UA_STATUSCODE_GOOD;
 }
 }
 
 
-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) {
 static void stopHandler(int sign) {
-	printf("Received Ctrl-C\n");
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Received Ctrl-C\n");
 	running = 0;
 	running = 0;
 }
 }
 
 
@@ -164,7 +189,7 @@ static UA_ByteString loadCertificate(void) {
 	UA_ByteString certificate = UA_STRING_NULL;
 	UA_ByteString certificate = UA_STRING_NULL;
 	FILE *fp = NULL;
 	FILE *fp = NULL;
 	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
 	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
-	fp=fopen("localhost.der", "rb");
+	fp=fopen("server_cert.der", "rb");
 
 
 	if(!fp) {
 	if(!fp) {
         errno = 0; // we read errno also from the tcp layer...
         errno = 0; // we read errno also from the tcp layer...
@@ -198,12 +223,6 @@ int main(int argc, char** argv) {
     UA_Server_setServerCertificate(server, certificate);
     UA_Server_setServerCertificate(server, certificate);
     UA_ByteString_deleteMembers(&certificate);
     UA_ByteString_deleteMembers(&certificate);
 	UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 	UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-    UA_UInt16 nsIndex = UA_Server_addNamespace(server, UA_ServerConfig_standard.Application_applicationURI);
-
-	// print the status every 2 sec
-	UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
-			.work.methodCall = {.method = printLedStatus, .data = NULL} };
-	UA_Server_addRepeatedWorkItem(server, &work, 2000, NULL);
 
 
 	// add node with the datetime data source
 	// add node with the datetime data source
 	UA_DataSource dateDataSource = (UA_DataSource)
 	UA_DataSource dateDataSource = (UA_DataSource)
@@ -211,50 +230,52 @@ int main(int argc, char** argv) {
 		.read = readTimeData,
 		.read = readTimeData,
 		.release = releaseTimeData,
 		.release = releaseTimeData,
 		.write = NULL};
 		.write = NULL};
-	const UA_QualifiedName dateName = UA_QUALIFIEDNAME(nsIndex, "current time");
+	const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
 	UA_Server_addDataSourceVariableNode(server, dateDataSource, dateName, UA_NODEID_NULL,
 	UA_Server_addDataSourceVariableNode(server, dateDataSource, dateName, UA_NODEID_NULL,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
 
-	if(!(temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))){
-		UA_LOG_WARNING(logger, UA_LOGGERCATEGORY_USERLAND, "[Linux specific] Can not open temperature file, no temperature node will be added");
-	} else {
-		// add node with the datetime data source
+	//cpu temperature monitoring for linux machines
+	if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))){
+		// add node with the data source
 		UA_DataSource temperatureDataSource = (UA_DataSource)
 		UA_DataSource temperatureDataSource = (UA_DataSource)
     	    {.handle = NULL,
     	    {.handle = NULL,
 			.read = readTemperature,
 			.read = readTemperature,
 			.release = releaseTemperature,
 			.release = releaseTemperature,
 			.write = NULL};
 			.write = NULL};
-		const UA_QualifiedName ledName = UA_QUALIFIEDNAME(nsIndex, "cpu temperature");
-		UA_Server_addDataSourceVariableNode(server, temperatureDataSource, ledName, UA_NODEID_NULL, 
+		const UA_QualifiedName tempName = UA_QUALIFIEDNAME(1, "cpu temperature");
+		UA_Server_addDataSourceVariableNode(server, temperatureDataSource, tempName, UA_NODEID_NULL,
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
                                             UA_NODEID_NUMERIC(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};
-	const UA_QualifiedName statusName = UA_QUALIFIEDNAME(0, "status LED");
-	UA_Server_addDataSourceVariableNode(server, ledStatusDataSource, statusName, UA_NODEID_NULL,
-                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+	//LED control for rpi
+	if(  access("/sys/class/leds/led0/trigger", F_OK ) != -1
+	  || access("/sys/class/leds/led0/brightness", F_OK ) != -1){
+        if (	(triggerFile = fopen("/sys/class/leds/led0/trigger", "w"))
+            && 	(ledFile = fopen("/sys/class/leds/led0/brightness", "w"))) {
+            //setting led mode to manual
+            fprintf(triggerFile, "%s", "none");
+            fflush(triggerFile);
+
+            //turning off led initially
+            fprintf(ledFile, "%s", "1");
+            fflush(ledFile);
+
+            // add node with the LED status data source
+            UA_DataSource ledStatusDataSource = (UA_DataSource)
+                {.handle = NULL,
+                .read = readLedStatus,
+                .release = releaseLedStatus,
+                .write = writeLedStatus};
+            const UA_QualifiedName statusName = UA_QUALIFIEDNAME(0, "status LED");
+            UA_Server_addDataSourceVariableNode(server, ledStatusDataSource, statusName, UA_NODEID_NULL,
+                                                UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                                UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+        }else{
+            UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "[Raspberry Pi] LED file exist, but I have no access (try to run server with sudo)");
+        }
+    }
 
 
 	// add a static variable node to the adresspace
 	// add a static variable node to the adresspace
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Variant *myIntegerVariant = UA_Variant_new();
@@ -267,6 +288,40 @@ int main(int argc, char** argv) {
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
 
 
+   /**************/
+   /* Demo Nodes */
+   /**************/
+
+#define DEMOID 50000
+   UA_Server_addObjectNode(server,UA_QUALIFIEDNAME(1, "Demo"), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+
+#define SCALARID 50001
+   UA_Server_addObjectNode(server,UA_QUALIFIEDNAME(1, "Scalar"), UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+
+#define ARRAYID 50002
+   UA_Server_addObjectNode(server,UA_QUALIFIEDNAME(1, "Array"), UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+
+   UA_UInt32 id = 51000; //running id in namespace 0
+   for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
+       if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
+           continue;
+       //add a scalar node for every built-in type
+        void *value = UA_new(&UA_TYPES[type]);
+        UA_Variant *variant = UA_Variant_new();
+        UA_Variant_setScalar(variant, value, &UA_TYPES[type]);
+        char name[15];
+        sprintf(name, "%02d", type);
+        UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, name);
+        UA_Server_addVariableNode(server, variant, myIntegerName, UA_NODEID_NUMERIC(1, ++id),
+                                  UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+
+        //add an array node for every built-in type
+        UA_Variant *arrayvar = UA_Variant_new();
+        UA_Variant_setArray(arrayvar, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
+        UA_Server_addVariableNode(server, arrayvar, myIntegerName, UA_NODEID_NUMERIC(1, ++id),
+                                  UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+   }
+
 	//start server
 	//start server
 	UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
 	UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
 
 

+ 6 - 3
examples/server.cpp

@@ -3,6 +3,7 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
  */
 #include <iostream>
 #include <iostream>
+#include <cstring>
 
 
 #ifdef NOT_AMALGATED
 #ifdef NOT_AMALGATED
 # include "ua_server.h"
 # include "ua_server.h"
@@ -22,11 +23,13 @@ using namespace std;
 
 
 int main()
 int main()
 {
 {
-	UA_Server *server = UA_Server_new();
+    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 
 
-	// add a variable node to the adresspace
-    UA_Server_addNamespace(server, "myApplicationNamespace");
+    UA_Logger logger = Logger_Stdout_new();
+    UA_Server_setLogger(server, logger);
+
+    // add a variable node to the adresspace
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);

+ 7 - 7
examples/server_simple.c

@@ -32,7 +32,7 @@ static UA_ByteString loadCertificate(void) {
     UA_ByteString certificate = UA_STRING_NULL;
     UA_ByteString certificate = UA_STRING_NULL;
 	FILE *fp = NULL;
 	FILE *fp = NULL;
 	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
 	//FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
-	fp=fopen("localhost.der", "rb");
+	fp=fopen("server_cert.der", "rb");
 
 
 	if(!fp) {
 	if(!fp) {
         errno = 0; // we read errno also from the tcp layer...
         errno = 0; // we read errno also from the tcp layer...
@@ -54,7 +54,7 @@ static UA_ByteString loadCertificate(void) {
 }
 }
 
 
 static void testCallback(UA_Server *server, void *data) {
 static void testCallback(UA_Server *server, void *data) {
-    logger.log_info(UA_LOGGERCATEGORY_USERLAND, "testcallback");
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "testcallback");
 }
 }
 
 
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
@@ -67,7 +67,6 @@ int main(int argc, char** argv) {
     UA_Server_setServerCertificate(server, certificate);
     UA_Server_setServerCertificate(server, certificate);
     UA_ByteString_deleteMembers(&certificate);
     UA_ByteString_deleteMembers(&certificate);
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
     UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-    UA_Server_addNamespace(server, UA_ServerConfig_standard.Application_applicationURI);
 
 
     UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
     UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
                         .work.methodCall = {.method = testCallback, .data = NULL} };
                         .work.methodCall = {.method = testCallback, .data = NULL} };
@@ -83,12 +82,13 @@ int main(int argc, char** argv) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
     UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
                               myIntegerNodeId, parentNodeId, parentReferenceNodeId);
-    
+
+/*
 #ifdef BENCHMARK
 #ifdef BENCHMARK
     UA_UInt32 nodeCount = 50;
     UA_UInt32 nodeCount = 50;
     char str[32];
     char str[32];
     for(UA_UInt32 i = 0;i<nodeCount;i++) {
     for(UA_UInt32 i = 0;i<nodeCount;i++) {
-        /* scalar */
+        // scalar
         void *data = UA_new(&UA_TYPES[i]);
         void *data = UA_new(&UA_TYPES[i]);
         UA_Variant *variant = UA_Variant_new();
         UA_Variant *variant = UA_Variant_new();
         UA_Variant_setScalar(variant, data, &UA_TYPES[i]);
         UA_Variant_setScalar(variant, data, &UA_TYPES[i]);
@@ -99,7 +99,7 @@ int main(int argc, char** argv) {
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
 
-        /* array */
+        // array
         data = UA_Array_new(&UA_TYPES[i], 10);
         data = UA_Array_new(&UA_TYPES[i], 10);
         variant = UA_Variant_new();
         variant = UA_Variant_new();
         UA_Variant_setArray(variant, data, 10, &UA_TYPES[i]);
         UA_Variant_setArray(variant, data, 10, &UA_TYPES[i]);
@@ -111,7 +111,7 @@ int main(int argc, char** argv) {
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
     }
     }
 #endif
 #endif
-
+*/
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
 	UA_Server_delete(server);
 	UA_Server_delete(server);
 
 

+ 0 - 1
examples/server_udp.c

@@ -28,7 +28,6 @@ int main(int argc, char** argv) {
 
 
 	UA_Server *server = UA_Server_new();
 	UA_Server *server = UA_Server_new();
     UA_Server_addNetworkLayer(server, ServerNetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664));
     UA_Server_addNetworkLayer(server, ServerNetworkLayerUDP_new(UA_ConnectionConfig_standard, 16664));
-    UA_Server_addNamespace(server, "myApplicationNamespace");
 
 
 	// add a variable node to the adresspace
 	// add a variable node to the adresspace
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Variant *myIntegerVariant = UA_Variant_new();

+ 6 - 2
include/ua_client.h

@@ -22,17 +22,21 @@ typedef UA_Connection (*UA_ConnectClientConnection)(char *endpointUrl, UA_Logger
 
 
 typedef struct UA_ClientConfig {
 typedef struct UA_ClientConfig {
     UA_Int32 timeout; //sync response timeout
     UA_Int32 timeout; //sync response timeout
+    UA_Int32 secureChannelLifeTime; // lifetime in ms (then the channel needs to be renewed)
+    UA_Int32 timeToRenewSecureChannel; //time in ms  before expiration to renew the secure channel
     UA_ConnectionConfig localConnectionConfig;
     UA_ConnectionConfig localConnectionConfig;
 } UA_ClientConfig;
 } UA_ClientConfig;
 
 
-extern const UA_ClientConfig UA_ClientConfig_standard;
+extern UA_EXPORT const UA_ClientConfig UA_ClientConfig_standard;
 UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config, UA_Logger logger);
 UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config, UA_Logger logger);
 
 
-void UA_Client_delete(UA_Client* client);
+UA_EXPORT void UA_Client_delete(UA_Client* client);
 
 
 UA_StatusCode UA_EXPORT UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connFunc, char *endpointUrl);
 UA_StatusCode UA_EXPORT UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connFunc, char *endpointUrl);
 UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client);
 UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client);
 
 
+UA_StatusCode UA_EXPORT UA_Client_renewSecureChannel(UA_Client *client);
+
 /* Attribute Service Set */
 /* Attribute Service Set */
 UA_ReadResponse UA_EXPORT UA_Client_read(UA_Client *client, UA_ReadRequest *request);
 UA_ReadResponse UA_EXPORT UA_Client_read(UA_Client *client, UA_ReadRequest *request);
 UA_WriteResponse UA_EXPORT UA_Client_write(UA_Client *client, UA_WriteRequest *request);
 UA_WriteResponse UA_EXPORT UA_Client_write(UA_Client *client, UA_WriteRequest *request);

+ 9 - 0
src/ua_config.h.in

@@ -29,4 +29,13 @@
 #  endif
 #  endif
 #endif
 #endif
 
 
+/*	Define your own htoleXX and leXXtoh here if needed.
+	Otherwise the ones defined in endian.h are used		*/
+//	#define htole16(x)	{...}(x)
+//	#define htole32(x)	{...}(x)
+//	#define htole64(x)	{...}(x)
+//	#define le16toh(x)	{...}(x)
+//	#define le32toh(x)	{...}(x)
+//	#define le64toh(x)	{...}(x)
+
 #endif /* UA_CONFIG_H_ */
 #endif /* UA_CONFIG_H_ */

+ 23 - 25
include/ua_log.h

@@ -23,8 +23,6 @@ extern "C" {
 #include "ua_config.h"
 #include "ua_config.h"
 
 
 /**
 /**
- * @ingroup server
- *
  * @defgroup logging Logging
  * @defgroup logging Logging
  *
  *
  * @brief Custom logging solutions can be "plugged in" with this interface
  * @brief Custom logging solutions can be "plugged in" with this interface
@@ -32,62 +30,62 @@ extern "C" {
  * @{
  * @{
  */
  */
 
 
-typedef enum UA_LoggerCategory {
-    UA_LOGGERCATEGORY_COMMUNICATION,
-    UA_LOGGERCATEGORY_SERVER,
-    UA_LOGGERCATEGORY_CLIENT,
-    UA_LOGGERCATEGORY_USERLAND
-} UA_LoggerCategory;
-
-extern UA_EXPORT const char *UA_LoggerCategoryNames[4];
-
-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, ...);
-} UA_Logger;
+typedef enum {
+    UA_LOGLEVEL_TRACE,
+    UA_LOGLEVEL_DEBUG,
+    UA_LOGLEVEL_INFO,
+    UA_LOGLEVEL_WARNING,
+    UA_LOGLEVEL_ERROR,
+    UA_LOGLEVEL_FATAL
+} UA_LogLevel;
+
+typedef enum {
+    UA_LOGCATEGORY_COMMUNICATION,
+    UA_LOGCATEGORY_SERVER,
+    UA_LOGCATEGORY_CLIENT,
+    UA_LOGCATEGORY_USERLAND
+} UA_LogCategory;
+    
+typedef void (*UA_Logger)(UA_LogLevel level, UA_LogCategory category, const char *msg, ...);
 
 
 #if UA_LOGLEVEL <= 100
 #if UA_LOGLEVEL <= 100
 #define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do { \
 #define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do { \
-        if(LOGGER.log_trace) LOGGER.log_trace(CATEGORY, __VA_ARGS__); } while(0)
+        if(LOGGER) LOGGER(UA_LOGLEVEL_TRACE, CATEGORY, __VA_ARGS__); } while(0)
 #else
 #else
 #define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do {} while(0)
 #define UA_LOG_TRACE(LOGGER, CATEGORY, ...) do {} while(0)
 #endif
 #endif
 
 
 #if UA_LOGLEVEL <= 200
 #if UA_LOGLEVEL <= 200
 #define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do { \
 #define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do { \
-        if(LOGGER.log_debug) LOGGER.log_debug(CATEGORY, __VA_ARGS__); } while(0)
+        if(LOGGER) LOGGER(UA_LOGLEVEL_DEBUG, CATEGORY, __VA_ARGS__); } while(0)
 #else
 #else
 #define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do {} while(0)
 #define UA_LOG_DEBUG(LOGGER, CATEGORY, ...) do {} while(0)
 #endif
 #endif
 
 
 #if UA_LOGLEVEL <= 300
 #if UA_LOGLEVEL <= 300
 #define UA_LOG_INFO(LOGGER, CATEGORY, ...) do { \
 #define UA_LOG_INFO(LOGGER, CATEGORY, ...) do { \
-        if(LOGGER.log_info) LOGGER.log_info(CATEGORY, __VA_ARGS__); } while(0)
+        if(LOGGER) LOGGER(UA_LOGLEVEL_INFO, CATEGORY, __VA_ARGS__); } while(0)
 #else
 #else
 #define UA_LOG_INFO(LOGGER, CATEGORY, ...) do {} while(0)
 #define UA_LOG_INFO(LOGGER, CATEGORY, ...) do {} while(0)
 #endif
 #endif
 
 
 #if UA_LOGLEVEL <= 400
 #if UA_LOGLEVEL <= 400
 #define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do { \
 #define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do { \
-        if(LOGGER.log_warning) LOGGER.log_warning(CATEGORY, __VA_ARGS__); } while(0)
+        if(LOGGER) LOGGER(UA_LOGLEVEL_WARNING, CATEGORY, __VA_ARGS__); } while(0)
 #else
 #else
 #define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do {} while(0)
 #define UA_LOG_WARNING(LOGGER, CATEGORY, ...) do {} while(0)
 #endif
 #endif
 
 
 #if UA_LOGLEVEL <= 500
 #if UA_LOGLEVEL <= 500
 #define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do { \
 #define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do { \
-        if(LOGGER.log_error) LOGGER.log_error(CATEGORY, __VA_ARGS__); } while(0)
+        if(LOGGER) LOGGER(UA_LOGLEVEL_ERROR, CATEGORY, __VA_ARGS__); } while(0)
 #else
 #else
 #define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do {} while(0)
 #define UA_LOG_ERROR(LOGGER, CATEGORY, ...) do {} while(0)
 #endif
 #endif
 
 
 #if UA_LOGLEVEL <= 600
 #if UA_LOGLEVEL <= 600
 #define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do { \
 #define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do { \
-        if(LOGGER.log_fatal) LOGGER.log_fatal(CATEGORY, __VA_ARGS__); } while(0)
+        if(LOGGER) LOGGER(UA_LOGLEVEL_FATAL, CATEGORY, __VA_ARGS__); } while(0)
 #else
 #else
 #define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do {} while(0)
 #define UA_LOG_FATAL(LOGGER, CATEGORY, ...) do {} while(0)
 #endif
 #endif

+ 65 - 16
include/ua_server.h

@@ -44,7 +44,7 @@ typedef struct UA_ServerConfig {
     char*       Application_applicationName;
     char*       Application_applicationName;
 } UA_ServerConfig;
 } UA_ServerConfig;
 
 
-extern const UA_ServerConfig UA_ServerConfig_standard;
+extern UA_EXPORT const UA_ServerConfig UA_ServerConfig_standard;
 
 
 struct UA_Server;
 struct UA_Server;
 typedef struct UA_Server UA_Server;
 typedef struct UA_Server UA_Server;
@@ -55,7 +55,7 @@ void UA_EXPORT UA_Server_delete(UA_Server *server);
 
 
 /** Sets the logger used by the server */
 /** Sets the logger used by the server */
 void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
 void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
-UA_Logger UA_EXPORT * UA_Server_getLogger(UA_Server *server);
+UA_Logger UA_EXPORT UA_Server_getLogger(UA_Server *server);
 
 
 /**
 /**
  * Runs the main loop of the server. In each iteration, this calls into the
  * Runs the main loop of the server. In each iteration, this calls into the
@@ -73,22 +73,67 @@ UA_Logger UA_EXPORT * UA_Server_getLogger(UA_Server *server);
  */
  */
 UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
 UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
 
 
-/** @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.
+/**
+ * The prologue part of UA_Server_run (no need to use if you call UA_Server_run)
+ */
+UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
+/**
+ * The epilogue part of UA_Server_run (no need to use if you call UA_Server_run)
+ */
+UA_StatusCode UA_EXPORT UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads);
+/**
+ * One iteration of UA_Server_run (no need to use if you call UA_Server_run)
+ */
+UA_StatusCode UA_EXPORT UA_Server_run_getAndProcessWork(UA_Server *server, UA_Boolean *running);
+
+
+/**
+ * Datasources are the interface to local data providers. 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
  * It is expected that the read and release callbacks are implemented. The write
  * callback can be set to null.
  * callback can be set to null.
- **/
+ */
 typedef struct {
 typedef struct {
-    void *handle;
-    UA_StatusCode (*read)(void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value);
+    void *handle; ///> A custom pointer to reuse the same datasource functions for multiple sources
+
+    /**
+     * Read current data from the data source
+     *
+     * @param handle An optional pointer to user-defined data for the specific data source
+     * @param includeSourceTimeStamp If true, then the datasource is expected to set the source
+     *        timestamp in the returned value
+     * @param range If not null, then the datasource shall return only a selection of the (nonscalar)
+     *        data. Set UA_STATUSCODE_BADINDEXRANGEINVALID in the value if this does not apply.
+     * @param value The (non-null) DataValue that is returned to the client. The data source sets the
+     *        read data, the result status and optionally a sourcetimestamp.
+     * @return Returns a status code for logging. Error codes intended for the original caller are set
+     *         in the value. If an error is returned, then no releasing of the value is done.
+     */
+    UA_StatusCode (*read)(void *handle, UA_Boolean includeSourceTimeStamp, const UA_NumericRange *range,
+                          UA_DataValue *value);
+
+    /**
+     * Release data that was allocated during a read (and/or release locks in the data source)
+     *
+     * @param handle An optional pointer to user-defined data for the specific data source
+     * @param value The DataValue that was used for a successful read.
+     */
     void (*release)(void *handle, UA_DataValue *value);
     void (*release)(void *handle, UA_DataValue *value);
-    UA_StatusCode (*write)(void *handle, const UA_Variant *data);
+
+    /**
+     * Write into a data source. The write member of UA_DataSource can be empty if the operation
+     * is unsupported.
+     *
+     * @param handle An optional pointer to user-defined data for the specific data source
+     * @param data The data to be written into the data source
+     * @param range An optional data range. If the data source is scalar or does not support writing
+     *        of ranges, then an error code is returned.
+     * @return Returns a status code that is returned to the user
+     */
+    UA_StatusCode (*write)(void *handle, const UA_Variant *data, const UA_NumericRange *range);
 } UA_DataSource;
 } UA_DataSource;
 
 
 /** @brief Add a new namespace to the server. Returns the index of the new namespace */
 /** @brief Add a new namespace to the server. Returns the index of the new namespace */
@@ -101,13 +146,17 @@ UA_StatusCode UA_EXPORT
 UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_QualifiedName browseName, 
 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_NodeId nodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId);
 
 
+UA_StatusCode UA_EXPORT
+UA_Server_addObjectNode(UA_Server *server, const UA_QualifiedName browseName,
+                        UA_NodeId nodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                        const UA_NodeId typeDefinition);
+
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
 UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
                                     const UA_QualifiedName browseName, UA_NodeId nodeId,
                                     const UA_QualifiedName browseName, UA_NodeId nodeId,
                                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId);
                                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId);
 
 
-/** Work that is run in the main loop (singlethreaded) or dispatched to a worker
-    thread. */
+/** Work that is run in the main loop (singlethreaded) or dispatched to a worker thread */
 typedef struct UA_WorkItem {
 typedef struct UA_WorkItem {
     enum {
     enum {
         UA_WORKITEMTYPE_NOTHING,
         UA_WORKITEMTYPE_NOTHING,
@@ -197,7 +246,7 @@ typedef struct {
      *
      *
      * @param workItems When the returned integer is positive, *workItems points
      * @param workItems When the returned integer is positive, *workItems points
      * to an array of WorkItems of the returned size.
      * to an array of WorkItems of the returned size.
-     * @param timeout The timeout during which an event must arrive.
+     * @param timeout The timeout during which an event must arrive in microseconds
      * @return The size of the returned workItems array. If the result is
      * @return The size of the returned workItems array. If the result is
      * negative, an error has occured.
      * negative, an error has occured.
      */
      */

+ 41 - 81
include/ua_types.h

@@ -263,16 +263,12 @@ typedef struct UA_DiagnosticInfo {
     struct UA_DiagnosticInfo *innerDiagnosticInfo;
     struct UA_DiagnosticInfo *innerDiagnosticInfo;
 } UA_DiagnosticInfo;
 } UA_DiagnosticInfo;
 
 
-#ifndef SWIG
 #define UA_TYPE_HANDLING_FUNCTIONS(TYPE)                             \
 #define UA_TYPE_HANDLING_FUNCTIONS(TYPE)                             \
     TYPE UA_EXPORT * TYPE##_new(void);                               \
     TYPE UA_EXPORT * TYPE##_new(void);                               \
     void UA_EXPORT TYPE##_init(TYPE * p);                            \
     void UA_EXPORT TYPE##_init(TYPE * p);                            \
     void UA_EXPORT TYPE##_delete(TYPE * p);                          \
     void UA_EXPORT TYPE##_delete(TYPE * p);                          \
     void UA_EXPORT TYPE##_deleteMembers(TYPE * p);                   \
     void UA_EXPORT TYPE##_deleteMembers(TYPE * p);                   \
     UA_StatusCode UA_EXPORT TYPE##_copy(const TYPE *src, TYPE *dst);
     UA_StatusCode UA_EXPORT TYPE##_copy(const TYPE *src, TYPE *dst);
-#else
-#define UA_TYPE_HANDLING_FUNCTIONS(TYPE)
-#endif
 
 
 /* Functions for all types */
 /* Functions for all types */
 UA_TYPE_HANDLING_FUNCTIONS(UA_Boolean)
 UA_TYPE_HANDLING_FUNCTIONS(UA_Boolean)
@@ -321,22 +317,17 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_DiagnosticInfo)
 /* Custom functions for the builtin datatypes */
 /* Custom functions for the builtin datatypes */
 /**********************************************/
 /**********************************************/
 
 
-#ifdef __cplusplus
-#define CPP_ONLY(STR) STR
-#else
-#define CPP_ONLY(STR)
-#endif
-
 /* String */
 /* String */
 /** Copy a (zero terminated) char-array into a UA_String. Memory for the string data is
 /** Copy a (zero terminated) char-array into a UA_String. Memory for the string data is
     allocated. If the memory cannot be allocated, a null-string is returned. */
     allocated. If the memory cannot be allocated, a null-string is returned. */
-UA_String UA_EXPORT UA_String_fromChars(char const *src);
+UA_String UA_EXPORT UA_String_fromChars(char const src[]);
+
 #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
 #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
-#define UA_STRING(CHARS) (const UA_String) {strlen(CHARS), (UA_Byte*)CHARS }
+#define UA_STRING(CHARS) (UA_String) {strlen(CHARS), (UA_Byte*)CHARS }
 #define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
 #define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
 
 
 /** Printf a char-array into a UA_String. Memory for the string data is allocated. */
 /** Printf a char-array into a UA_String. Memory for the string data is allocated. */
-UA_StatusCode UA_EXPORT UA_String_copyprintf(char const *fmt, UA_String *dst, ...);
+UA_StatusCode UA_EXPORT UA_String_copyprintf(char const fmt[], UA_String *dst, ...);
 
 
 /** Compares two strings */
 /** Compares two strings */
 UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
 UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
@@ -385,56 +376,23 @@ UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 /** Is the nodeid a null-nodeid? */
 /** Is the nodeid a null-nodeid? */
 UA_Boolean UA_EXPORT UA_NodeId_isNull(const UA_NodeId *p);
 UA_Boolean UA_EXPORT UA_NodeId_isNull(const UA_NodeId *p);
 
 
-#ifndef __cplusplus
-#define UA_NODEID_NUMERIC(NS_INDEX, NUMERICID) (UA_NodeId) {           \
-        .namespaceIndex = NS_INDEX,                                    \
-        .identifierType = UA_NODEIDTYPE_NUMERIC,                       \
-        .identifier.numeric = NUMERICID }
-
-#define UA_NODEID_STRING(NS_INDEX, CHARS) (const UA_NodeId) {          \
-        .namespaceIndex = NS_INDEX,                                    \
-        .identifierType = UA_NODEIDTYPE_STRING,                        \
-        .identifier.string = UA_STRING(CHARS) }
-    
-#define UA_NODEID_STRING_ALLOC(NS_INDEX, CHARS) (const UA_NodeId) {    \
-        .namespaceIndex = NS_INDEX,                                    \
-        .identifierType = UA_NODEIDTYPE_STRING,                        \
-        .identifier.string = UA_STRING_ALLOC(CHARS) }
-
-#define UA_NODEID_GUID(NS_INDEX, GUID) (UA_NodeId) {                   \
-        .namespaceIndex = NS_INDEX,                                    \
-        .identifierType = UA_NODEIDTYPE_GUID,                          \
-        .identifier.guid = GUID }
-
-#define UA_NODEID_BYTESTRING(NS_INDEX, CHARS) (const UA_NodeId) {      \
-        .namespaceIndex = NS_INDEX,                                    \
-        .identifierType = UA_NODEIDTYPE_BYTESTRING,                    \
-        .identifier.byteString = UA_STRING(CHARS) }
-
-#define UA_NODEID_BYTESTRING_ALLOC(NS_INDEX, CHARS) (const UA_NodeId) {\
-        .namespaceIndex = NS_INDEX,                                    \
-        .identifierType = UA_NODEIDTYPE_BYTESTRING,                    \
-        .identifier.byteString = UA_STRING_ALLOC(CHARS) }
-#else
-#define UA_NODEID_NUMERIC(NS_INDEX, NUMERICID) (UA_NodeId) {    \
-        NS_INDEX, UA_NodeId::UA_NODEIDTYPE_NUMERIC, NUMERICID }
-
-#define UA_NODEID_STRING(NS_INDEX, CHARS) (const UA_NodeId) {           \
-        NS_INDEX, UA_NodeId::UA_NODEIDTYPE_STRING, UA_STRING(CHARS) }
-
-#define UA_NODEID_STRING_ALLOC(NS_INDEX, CHARS) (const UA_NodeId) {     \
-        NS_INDEX, UA_NodeId::UA_NODEIDTYPE_STRING, UA_STRING_ALLOC(CHARS) }
-
-#define UA_NODEID_GUID(NS_INDEX, GUID) (UA_NodeId) {    \
-        NS_INDEX, UA_NodeId::UA_NODEIDTYPE_GUID, GUID }
-
-#define UA_NODEID_BYTESTRING(NS_INDEX, CHARS) (const UA_NodeId) {       \
-        NS_INDEX, UA_NodeId::UA_NODEIDTYPE_BYTESTRING, UA_STRING(CHARS) }
-
-#define UA_NODEID_BYTESTRING_ALLOC(NS_INDEX, CHARS) (const UA_NodeId) { \
-        NS_INDEX, UA_NodeId::UA_NODEIDTYPE_BYTESTRING, UA_STRING_ALLOC(CHARS) }
-#endif
-
+UA_NodeId UA_EXPORT UA_NodeId_fromInteger(UA_UInt16 nsIndex, UA_Int32 identifier);
+UA_NodeId UA_EXPORT UA_NodeId_fromCharString(UA_UInt16 nsIndex, char identifier[]);
+UA_NodeId UA_EXPORT UA_NodeId_fromCharStringCopy(UA_UInt16 nsIndex, char const identifier[]);
+UA_NodeId UA_EXPORT UA_NodeId_fromString(UA_UInt16 nsIndex, UA_String identifier);
+UA_NodeId UA_EXPORT UA_NodeId_fromStringCopy(UA_UInt16 nsIndex, UA_String identifier);
+UA_NodeId UA_EXPORT UA_NodeId_fromGuid(UA_UInt16 nsIndex, UA_Guid identifier);
+UA_NodeId UA_EXPORT UA_NodeId_fromCharByteString(UA_UInt16 nsIndex, char identifier[]);
+UA_NodeId UA_EXPORT UA_NodeId_fromCharByteStringCopy(UA_UInt16 nsIndex, char const identifier[]);
+UA_NodeId UA_EXPORT UA_NodeId_fromByteString(UA_UInt16 nsIndex, UA_ByteString identifier);
+UA_NodeId UA_EXPORT UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteString identifier);
+
+#define UA_NODEID_NUMERIC(NS_INDEX, NUMERICID) UA_NodeId_fromInteger(NS_INDEX, NUMERICID)
+#define UA_NODEID_STRING(NS_INDEX, CHARS) UA_NodeId_fromCharString(NS_INDEX, CHARS)
+#define UA_NODEID_STRING_ALLOC(NS_INDEX, CHARS) UA_NodeId_fromCharStringCopy(NS_INDEX, CHARS)
+#define UA_NODEID_GUID(NS_INDEX, GUID) UA_NodeId_fromGuid(NS_INDEX, GUID)
+#define UA_NODEID_BYTESTRING(NS_INDEX, CHARS) UA_NodeId_fromCharByteString(NS_INDEX, CHARS)
+#define UA_NODEID_BYTESTRING_ALLOC(NS_INDEX, CHARS) UA_NodeId_fromCharStringCopy(NS_INDEX, CHARS)
 #define UA_NODEID_NULL UA_NODEID_NUMERIC(0,0)
 #define UA_NODEID_NULL UA_NODEID_NUMERIC(0,0)
 
 
 /* ExpandedNodeId */
 /* ExpandedNodeId */
@@ -452,9 +410,9 @@ UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
         .namespaceIndex = NS_INDEX, .name = UA_STRING_ALLOC(CHARS) }
         .namespaceIndex = NS_INDEX, .name = UA_STRING_ALLOC(CHARS) }
 
 
 /* LocalizedText */
 /* LocalizedText */
-#define UA_LOCALIZEDTEXT(LOCALE, TEXT) (const UA_LocalizedText) {     \
+#define UA_LOCALIZEDTEXT(LOCALE, TEXT) (const UA_LocalizedText) {       \
         .locale = UA_STRING(LOCALE), .text = UA_STRING(TEXT) }
         .locale = UA_STRING(LOCALE), .text = UA_STRING(TEXT) }
-#define UA_LOCALIZEDTEXT_ALLOC(LOCALE, TEXT) (UA_LocalizedText) {             \
+#define UA_LOCALIZEDTEXT_ALLOC(LOCALE, TEXT) (UA_LocalizedText) {       \
         .locale = UA_STRING_ALLOC(LOCALE), .text = UA_STRING_ALLOC(TEXT) }
         .locale = UA_STRING_ALLOC(LOCALE), .text = UA_STRING_ALLOC(TEXT) }
 
 
 /* Variant */
 /* Variant */
@@ -466,7 +424,7 @@ UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
  * @param v The variant
  * @param v The variant
  * @return Does the variant contain a scalar value.
  * @return Does the variant contain a scalar value.
  */
  */
-UA_Boolean UA_EXPORT UA_Variant_isScalar(UA_Variant *v);
+UA_Boolean UA_EXPORT UA_Variant_isScalar(const UA_Variant *v);
     
     
 /**
 /**
  * Set the variant to a scalar value that already resides in memory. The value takes on the
  * Set the variant to a scalar value that already resides in memory. The value takes on the
@@ -515,33 +473,35 @@ UA_StatusCode UA_EXPORT UA_Variant_setArrayCopy(UA_Variant *v, const void *array
                                                 const UA_DataType *type);
                                                 const UA_DataType *type);
 
 
 /**
 /**
- * Copy the variant, but use only a subset of the (multidimensional) array. Returns an error code if
- * the variant is no array or if the indicated range does not fit.
+ * Copy the variant, but use only a subset of the (multidimensional) array into a variant. Returns
+ * an error code if the variant is not an 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);
 UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, UA_NumericRange range);
 
 
 /**
 /**
- * Insert a range of data into an existing variant of the dimensionality. This overwrites data in
- * the variant. The inserted data is managed by the variant (members are deleted with it).
+ * Insert a range of data into an existing variant. The data array can't be reused afterwards if it
+ * contains types without a fixed size (e.g. strings) since they take on the lifetime of the
+ * variant.
  *
  *
  * @param v The variant
  * @param v The variant
- * @param data The data array. Obviously the type must match the variant and the length the range.
+ * @param dataArray The data array. The type must match the variant
+ * @param dataarraySize The length of the data array. This is checked to match the range size.
  * @param range The range of where the new data is inserted
  * @param range The range of where the new data is inserted
  * @return Indicates whether the operation succeeded or returns an error code
  * @return Indicates whether the operation succeeded or returns an error code
  */
  */
-UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *data, const UA_NumericRange range);
+UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_Int32 dataArraySize,
+                                            const UA_NumericRange range);
 
 
 /**
 /**
- * Copies the variant and inserts data from the range. The inserted data is managed by the variant
- * (members are deleted with it).
+ * Deep-copy a range of data into an existing variant.
  *
  *
- * @param src The source variant
- * @param dst The target variant
- * @param data The data array. Obviously the type must match the variant and the length the range.
+ * @param v The variant
+ * @param dataArray The data array. The type must match the variant
+ * @param dataarraySize The length of the data array. This is checked to match the range size.
  * @param range The range of where the new data is inserted
  * @param range The range of where the new data is inserted
  * @return Indicates whether the operation succeeded or returns an error code
  * @return Indicates whether the operation succeeded or returns an error code
  */
  */
-UA_StatusCode UA_EXPORT UA_Variant_setCopyRange(const UA_Variant *src, UA_Variant *dst, void *data,
+UA_StatusCode UA_EXPORT UA_Variant_setRangeCopy(UA_Variant *v, const void *dataArray, UA_Int32 dataArraySize,
                                                 const UA_NumericRange range);
                                                 const UA_NumericRange range);
 
 
 /****************************/
 /****************************/
@@ -565,8 +525,8 @@ typedef struct {
                                                   namespace may contain members from the same
                                                   namespace may contain members from the same
                                                   namespace or ns0 only.*/
                                                   namespace or ns0 only.*/
     UA_Byte padding UA_BITFIELD(5); /**< How much padding is there before this member element? For
     UA_Byte padding UA_BITFIELD(5); /**< How much padding is there before this member element? For
-                                         arrays this is split into 2 bytes padding for for the
-                                         length index (max 4 bytes) and 3 bytes padding for the
+                                         arrays this is split into 2 bytes padding before the
+                                         length index (max 4 bytes) and 3 bytes padding before the
                                          pointer (max 8 bytes) */
                                          pointer (max 8 bytes) */
     UA_Boolean isArray UA_BITFIELD(1); ///< The member is an array of the given type
     UA_Boolean isArray UA_BITFIELD(1); ///< The member is an array of the given type
 } UA_DataTypeMember;
 } UA_DataTypeMember;
@@ -575,7 +535,7 @@ struct UA_DataType {
     UA_NodeId typeId; ///< The nodeid of the type
     UA_NodeId typeId; ///< The nodeid of the type
     ptrdiff_t memSize UA_BITFIELD(16); ///< Size of the struct in memory
     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_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 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 fixedSize UA_BITFIELD(1); ///< The type (and its members) contains no pointers
     UA_Boolean zeroCopyable UA_BITFIELD(1); ///< Can the type be copied directly off the stream?
     UA_Boolean zeroCopyable UA_BITFIELD(1); ///< Can the type be copied directly off the stream?
     UA_Byte membersSize; ///< How many members does the type have?
     UA_Byte membersSize; ///< How many members does the type have?

+ 50 - 26
src/client/ua_client.c

@@ -1,3 +1,4 @@
+#include <ua_types_generated.h>
 #include "ua_client.h"
 #include "ua_client.h"
 #include "ua_nodeids.h"
 #include "ua_nodeids.h"
 #include "ua_types.h"
 #include "ua_types.h"
@@ -29,11 +30,13 @@ struct UA_Client {
     /* Config */
     /* Config */
     UA_Logger logger;
     UA_Logger logger;
     UA_ClientConfig config;
     UA_ClientConfig config;
+    UA_DateTime scExpiresAt;
 };
 };
 
 
-const UA_ClientConfig UA_ClientConfig_standard =
-    { 5 /* ms receive timout */, {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
-                                  .maxMessageSize = 65536, .maxChunkCount = 1}};
+const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
+    { 5 /* ms receive timout */, 30000, 2000,
+      {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
+       .maxMessageSize = 65536, .maxChunkCount = 1}};
 
 
 UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
 UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
     UA_Client *client = UA_malloc(sizeof(UA_Client));
     UA_Client *client = UA_malloc(sizeof(UA_Client));
@@ -47,6 +50,8 @@ UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
     client->sequenceNumber = 0;
     client->sequenceNumber = 0;
     client->requestId = 0;
     client->requestId = 0;
 
 
+    client->scExpiresAt = 0;
+
     /* Secure Channel */
     /* Secure Channel */
     UA_ChannelSecurityToken_deleteMembers(&client->securityToken);
     UA_ChannelSecurityToken_deleteMembers(&client->securityToken);
     UA_ByteString_init(&client->clientNonce);
     UA_ByteString_init(&client->clientNonce);
@@ -126,7 +131,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
+static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     UA_ByteString_deleteMembers(&client->clientNonce); // if the handshake is repeated
     UA_ByteString_deleteMembers(&client->clientNonce); // if the handshake is repeated
     UA_ByteString_newMembers(&client->clientNonce, 1);
     UA_ByteString_newMembers(&client->clientNonce, 1);
     client->clientNonce.data[0] = 0;
     client->clientNonce.data[0] = 0;
@@ -149,13 +154,15 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
     UA_OpenSecureChannelRequest opnSecRq;
     UA_OpenSecureChannelRequest opnSecRq;
     UA_OpenSecureChannelRequest_init(&opnSecRq);
     UA_OpenSecureChannelRequest_init(&opnSecRq);
     opnSecRq.requestHeader.timestamp = UA_DateTime_now();
     opnSecRq.requestHeader.timestamp = UA_DateTime_now();
-    UA_ByteString_copy(&client->clientNonce, &opnSecRq.clientNonce);
-    opnSecRq.requestedLifetime = 30000;
-    opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
-    opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
-    opnSecRq.requestHeader.authenticationToken.identifier.numeric = 10;
-    opnSecRq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
-    opnSecRq.requestHeader.authenticationToken.namespaceIndex = 10;
+    opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
+    opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
+    if(renew) {
+        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
+    } else {
+        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
+        UA_ByteString_copy(&client->clientNonce, &opnSecRq.clientNonce);
+        opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
+    }
 
 
     messageHeader.messageHeader.messageSize =
     messageHeader.messageHeader.messageSize =
         UA_SecureConversationMessageHeader_calcSizeBinary(&messageHeader) +
         UA_SecureConversationMessageHeader_calcSizeBinary(&messageHeader) +
@@ -202,9 +209,9 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
     UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader);
     UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader);
     UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
     UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
     UA_NodeId_decodeBinary(&reply, &offset, &requestType);
     UA_NodeId_decodeBinary(&reply, &offset, &requestType);
-
-    if(!UA_NodeId_equal(&requestType, &UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
-                                                         UA_ENCODINGOFFSET_BINARY))) {
+    UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
+                                                  UA_ENCODINGOFFSET_BINARY);
+    if(!UA_NodeId_equal(&requestType, &expectedRequest)) {
         client->connection.releaseBuffer(&client->connection, &reply);
         client->connection.releaseBuffer(&client->connection, &reply);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_NodeId_deleteMembers(&requestType);
         UA_NodeId_deleteMembers(&requestType);
@@ -213,10 +220,11 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
 
 
     UA_OpenSecureChannelResponse response;
     UA_OpenSecureChannelResponse response;
     UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
     UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
+    client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000;
     client->connection.releaseBuffer(&client->connection, &reply);
     client->connection.releaseBuffer(&client->connection, &reply);
     retval = response.responseHeader.serviceResult;
     retval = response.responseHeader.serviceResult;
 
 
-    if(retval == UA_STATUSCODE_GOOD) {
+    if(!renew && retval == UA_STATUSCODE_GOOD) {
         UA_ChannelSecurityToken_copy(&response.securityToken, &client->securityToken);
         UA_ChannelSecurityToken_copy(&response.securityToken, &client->securityToken);
         UA_ByteString_deleteMembers(&client->serverNonce); // if the handshake is repeated
         UA_ByteString_deleteMembers(&client->serverNonce); // if the handshake is repeated
         UA_ByteString_copy(&response.serverNonce, &client->serverNonce);
         UA_ByteString_copy(&response.serverNonce, &client->serverNonce);
@@ -233,8 +241,16 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client) {
 static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *requestType,
 static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *requestType,
                                void *response, const UA_DataType *responseType, UA_Client *client,
                                void *response, const UA_DataType *responseType, UA_Client *client,
                                UA_Boolean sendOnly) {
                                UA_Boolean sendOnly) {
+
+    //check if sc needs to be renewed
+    if(client->scExpiresAt-UA_DateTime_now() <= client->config.timeToRenewSecureChannel * 10000){ //less than 3 seconds left to expire -> renew
+        UA_Client_renewSecureChannel(client);
+    }
+
     if(response)
     if(response)
         UA_init(response, responseType);
         UA_init(response, responseType);
+    else
+        return;
 
 
     UA_NodeId_copy(&client->authenticationToken, &request->authenticationToken);
     UA_NodeId_copy(&client->authenticationToken, &request->authenticationToken);
 
 
@@ -265,7 +281,8 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     UA_ByteString message;
     UA_ByteString message;
     UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message, msgHeader.messageHeader.messageSize);
     UA_StatusCode retval = client->connection.getBuffer(&client->connection, &message, msgHeader.messageHeader.messageSize);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        // todo
+        // todo: print error message
+        return;
     }
     }
 
 
     size_t offset = 0;
     size_t offset = 0;
@@ -276,19 +293,22 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     retval |= UA_NodeId_encodeBinary(&requestId, &message, &offset);
     retval |= UA_NodeId_encodeBinary(&requestId, &message, &offset);
     retval |= UA_encodeBinary(request, requestType, &message, &offset);
     retval |= UA_encodeBinary(request, requestType, &message, &offset);
 
 
-    retval = client->connection.write(&client->connection, &message);
-    client->connection.releaseBuffer(&client->connection, &message);
-
-    //TODO: rework to get return value
-    if(sendOnly)
-        return;
+    retval |= client->connection.write(&client->connection, &message);
 
 
     UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response;
     UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response;
+
+    client->connection.releaseBuffer(&client->connection, &message);
+
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
+        //send failed
         respHeader->serviceResult = retval;
         respHeader->serviceResult = retval;
         return;
         return;
     }
     }
 
 
+    //TODO: rework to get return value
+    if(sendOnly)
+        return;
+
     /* Response */
     /* Response */
     UA_ByteString reply;
     UA_ByteString reply;
     UA_ByteString_init(&reply);
     UA_ByteString_init(&reply);
@@ -306,9 +326,9 @@ static void sendReceiveRequest(UA_RequestHeader *request, const UA_DataType *req
     retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
     retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
     UA_NodeId responseId;
     UA_NodeId responseId;
     retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId);
     retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId);
-
-    if(!UA_NodeId_equal(&responseId, &UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
-                                                       UA_ENCODINGOFFSET_BINARY))) {
+    UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
+                                                 UA_ENCODINGOFFSET_BINARY);
+    if(!UA_NodeId_equal(&responseId, &expectedNodeId)) {
         client->connection.releaseBuffer(&client->connection, &reply);
         client->connection.releaseBuffer(&client->connection, &reply);
         UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
         UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
         respHeader->serviceResult = retval;
         respHeader->serviceResult = retval;
@@ -494,7 +514,7 @@ UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection co
     client->connection.localConf = client->config.localConnectionConfig;
     client->connection.localConf = client->config.localConnectionConfig;
     UA_StatusCode retval = HelAckHandshake(client);
     UA_StatusCode retval = HelAckHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
     if(retval == UA_STATUSCODE_GOOD)
-        retval = SecureChannelHandshake(client);
+        retval = SecureChannelHandshake(client, UA_FALSE);
     if(retval == UA_STATUSCODE_GOOD)
     if(retval == UA_STATUSCODE_GOOD)
         retval = EndpointsHandshake(client);
         retval = EndpointsHandshake(client);
     if(retval == UA_STATUSCODE_GOOD)
     if(retval == UA_STATUSCODE_GOOD)
@@ -512,6 +532,10 @@ UA_StatusCode UA_Client_disconnect(UA_Client *client) {
     return retval;
     return retval;
 }
 }
 
 
+UA_StatusCode UA_Client_renewSecureChannel(UA_Client *client) {
+    return SecureChannelHandshake(client, UA_TRUE);
+}
+
 UA_ReadResponse UA_Client_read(UA_Client *client, UA_ReadRequest *request) {
 UA_ReadResponse UA_Client_read(UA_Client *client, UA_ReadRequest *request) {
     UA_ReadResponse response;
     UA_ReadResponse response;
     synchronousRequest(request, &UA_TYPES[UA_TYPES_READREQUEST], &response,
     synchronousRequest(request, &UA_TYPES[UA_TYPES_READREQUEST], &response,

+ 2 - 2
src/server/ua_nodestore_hash.inc

@@ -18,12 +18,12 @@ static hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
     static const uint32_t n  = 0xe6546b64;
     static const uint32_t n  = 0xe6546b64;
     hash_t hash = seed;
     hash_t hash = seed;
     /* Somce compilers emit a warning when casting from a byte array to ints. */
     /* Somce compilers emit a warning when casting from a byte array to ints. */
-#if defined(__GNUC__) || defined(__clang__)
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic push
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wcast-align"
 #pragma GCC diagnostic ignored "-Wcast-align"
 #endif
 #endif
     blocks = (const uint32_t *)data;
     blocks = (const uint32_t *)data;
-#if defined(__GNUC__) || defined(__clang__)
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic pop
 #pragma GCC diagnostic pop
 #endif
 #endif
     for(int32_t i = 0;i < nblocks;i++) {
     for(int32_t i = 0;i < nblocks;i++) {

+ 54 - 45
src/server/ua_securechannel_manager.c

@@ -14,69 +14,79 @@ UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_UInt3
 }
 }
 
 
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
-    channel_list_entry *current, *next = LIST_FIRST(&cm->channels);
-    while(next) {
-        current = next;
-        next = LIST_NEXT(current, pointers);
+    channel_list_entry *current = LIST_FIRST(&cm->channels);
+    while(current) {
         LIST_REMOVE(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_SecureChannel_deleteMembersCleanup(&current->channel);
         UA_free(current);
         UA_free(current);
+        current = LIST_FIRST(&cm->channels);
+    }
+}
+
+void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime now) {
+    channel_list_entry *entry = LIST_FIRST(&cm->channels);
+    /* remove channels that were not renewed or who have no connection attached */
+    while(entry) {
+        if(entry->channel.securityToken.createdAt +
+            (10000 * entry->channel.securityToken.revisedLifetime) > now &&
+            entry->channel.connection) {
+            entry = LIST_NEXT(entry, pointers);
+        }
+        else {
+            channel_list_entry *next = LIST_NEXT(entry, pointers);
+            LIST_REMOVE(entry, pointers);
+            UA_SecureChannel_deleteMembersCleanup(&entry->channel);
+            UA_free(entry);
+            entry = next;
+        }
     }
     }
 }
 }
 
 
 UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
 UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
                                            const UA_OpenSecureChannelRequest *request,
                                            const UA_OpenSecureChannelRequest *request,
-                                           UA_OpenSecureChannelResponse *response)
-{
+                                           UA_OpenSecureChannelResponse *response) {
     switch(request->securityMode) {
     switch(request->securityMode) {
+    case UA_MESSAGESECURITYMODE_NONE:
+        break;
     case UA_MESSAGESECURITYMODE_INVALID:
     case UA_MESSAGESECURITYMODE_INVALID:
-        response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURITYMODEREJECTED;
-        return response->responseHeader.serviceResult;
-
-        // fall through and handle afterwards
-    /* case UA_MESSAGESECURITYMODE_NONE: */
-    /*     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce); */
-    /*     break; */
-
     case UA_MESSAGESECURITYMODE_SIGN:
     case UA_MESSAGESECURITYMODE_SIGN:
     case UA_MESSAGESECURITYMODE_SIGNANDENCRYPT:
     case UA_MESSAGESECURITYMODE_SIGNANDENCRYPT:
+    default:
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURITYMODEREJECTED;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURITYMODEREJECTED;
         return response->responseHeader.serviceResult;
         return response->responseHeader.serviceResult;
-
-    default:
-        // do nothing
-        break;
     }
     }
 
 
     channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
     channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
-    if(!entry) return UA_STATUSCODE_BADOUTOFMEMORY;
-    UA_SecureChannel_init(&entry->channel);
+    if(!entry)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
+    UA_SecureChannel_init(&entry->channel);
     response->responseHeader.stringTableSize = 0;
     response->responseHeader.stringTableSize = 0;
     response->responseHeader.timestamp       = UA_DateTime_now();
     response->responseHeader.timestamp       = UA_DateTime_now();
+    response->serverProtocolVersion = 0;
 
 
-    entry->channel.connection = conn;
-    conn->channel = &entry->channel;
     entry->channel.securityToken.channelId       = cm->lastChannelId++;
     entry->channel.securityToken.channelId       = cm->lastChannelId++;
     entry->channel.securityToken.tokenId         = cm->lastTokenId++;
     entry->channel.securityToken.tokenId         = cm->lastTokenId++;
     entry->channel.securityToken.createdAt       = UA_DateTime_now();
     entry->channel.securityToken.createdAt       = UA_DateTime_now();
     entry->channel.securityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
     entry->channel.securityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
                                                    cm->maxChannelLifetime : request->requestedLifetime;
                                                    cm->maxChannelLifetime : request->requestedLifetime;
+    //FIXME: pragmatic workaround to get clients requesting lifetime of 0 working
+    if(entry->channel.securityToken.revisedLifetime == 0) {
+        entry->channel.securityToken.revisedLifetime = cm->maxChannelLifetime;
+        //FIXME: I'd log it, but there is no pointer to the logger
+        // printf("Warning: client requests token lifetime of 0 in OpenSecureChannelRequest setting it to %llu\n", cm->maxChannelLifetime);
+    }
 
 
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
     entry->channel.serverAsymAlgSettings.securityPolicyUri =
     entry->channel.serverAsymAlgSettings.securityPolicyUri =
         UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
         UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
-    LIST_INSERT_HEAD(&cm->channels, entry, pointers);
 
 
-    response->serverProtocolVersion = 0;
     UA_SecureChannel_generateNonce(&entry->channel.serverNonce);
     UA_SecureChannel_generateNonce(&entry->channel.serverNonce);
     UA_ByteString_copy(&entry->channel.serverNonce, &response->serverNonce);
     UA_ByteString_copy(&entry->channel.serverNonce, &response->serverNonce);
     UA_ChannelSecurityToken_copy(&entry->channel.securityToken, &response->securityToken);
     UA_ChannelSecurityToken_copy(&entry->channel.securityToken, &response->securityToken);
-    conn->channel = &entry->channel;
+
+    UA_Connection_attachSecureChannel(conn, &entry->channel);
+    LIST_INSERT_HEAD(&cm->channels, entry, pointers);
 
 
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
@@ -93,13 +103,18 @@ UA_StatusCode UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_Conn
     channel->securityToken.createdAt       = UA_DateTime_now(); // todo: is wanted?
     channel->securityToken.createdAt       = UA_DateTime_now(); // todo: is wanted?
     channel->securityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
     channel->securityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
                                              cm->maxChannelLifetime : request->requestedLifetime;
                                              cm->maxChannelLifetime : request->requestedLifetime;
+    //FIXME: pragmatic workaround to get clients requesting lifetime of 0 working
+    if(channel->securityToken.revisedLifetime == 0){
+        channel->securityToken.revisedLifetime = cm->maxChannelLifetime;
+        //FIXME: I'd log it, but there is no pointer to the logger
+        // printf("Warning: client requests token lifetime of 0 in renewing SecureChannel setting it to %llu\n", cm->maxChannelLifetime);
+    }
 
 
     if(channel->serverNonce.data != UA_NULL)
     if(channel->serverNonce.data != UA_NULL)
         UA_ByteString_deleteMembers(&channel->serverNonce);
         UA_ByteString_deleteMembers(&channel->serverNonce);
     UA_SecureChannel_generateNonce(&channel->serverNonce);
     UA_SecureChannel_generateNonce(&channel->serverNonce);
     UA_ByteString_copy(&channel->serverNonce, &response->serverNonce);
     UA_ByteString_copy(&channel->serverNonce, &response->serverNonce);
     UA_ChannelSecurityToken_copy(&channel->securityToken, &response->securityToken);
     UA_ChannelSecurityToken_copy(&channel->securityToken, &response->securityToken);
-
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -113,21 +128,15 @@ UA_SecureChannel * UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_U
 }
 }
 
 
 UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
 UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
-    // TODO lock access
     channel_list_entry *entry;
     channel_list_entry *entry;
     LIST_FOREACH(entry, &cm->channels, pointers) {
     LIST_FOREACH(entry, &cm->channels, pointers) {
-        if(entry->channel.securityToken.channelId == channelId) {
-            UA_Connection *c = entry->channel.connection;
-            if(c) {
-                UA_Connection_detachSecureChannel(c);
-                c->close(c);
-            }
-            entry->channel.session = UA_NULL;
-            UA_SecureChannel_deleteMembers(&entry->channel);
-            LIST_REMOVE(entry, pointers);
-            UA_free(entry);
-            return UA_STATUSCODE_GOOD;
-        }
+        if(entry->channel.securityToken.channelId == channelId)
+            break;
     }
     }
-    return UA_STATUSCODE_BADINTERNALERROR;
+    if(!entry)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    LIST_REMOVE(entry, pointers);
+    UA_SecureChannel_deleteMembersCleanup(&entry->channel);
+    UA_free(entry);
+    return UA_STATUSCODE_GOOD;
 }
 }

+ 1 - 0
src/server/ua_securechannel_manager.h

@@ -25,6 +25,7 @@ UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_UInt3
                                            UA_UInt32 tokenLifetime, UA_UInt32 startChannelId,
                                            UA_UInt32 tokenLifetime, UA_UInt32 startChannelId,
                                            UA_UInt32 startTokenId);
                                            UA_UInt32 startTokenId);
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm);
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm);
+void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime now);
 UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
 UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
                                            const UA_OpenSecureChannelRequest *request,
                                            const UA_OpenSecureChannelRequest *request,
                                            UA_OpenSecureChannelResponse *response);
                                            UA_OpenSecureChannelResponse *response);

+ 339 - 265
src/server/ua_server.c

@@ -6,15 +6,14 @@
 #include "ua_services.h"
 #include "ua_services.h"
 #include "ua_nodeids.h"
 #include "ua_nodeids.h"
 
 
-const UA_ServerConfig UA_ServerConfig_standard = {
-        UA_TRUE,
-        UA_TRUE,
-        (char *[]){"user1","user2"},
-        (char *[]){"password","password1"},
-        2,
-        "urn:unconfigured:open62541:open62541Server",
-        "Unconfigured open62541 application"
-};
+const UA_EXPORT UA_ServerConfig UA_ServerConfig_standard = {
+    .Login_enableAnonymous = UA_TRUE,
+    .Login_enableUsernamePassword = UA_TRUE,
+    .Login_usernames = (char *[]){"user1","user2"},
+    .Login_passwords = (char *[]){"password","password1"},
+    .Login_loginsCount = 2,
+    .Application_applicationURI = "urn:unconfigured:open62541:open62541Server",
+    .Application_applicationName = "open62541" };
 
 
 /**********************/
 /**********************/
 /* Namespace Handling */
 /* Namespace Handling */
@@ -34,15 +33,15 @@ static void UA_ExternalNamespace_deleteMembers(UA_ExternalNamespace *ens) {
 /* Configuration */
 /* Configuration */
 /*****************/
 /*****************/
 
 
-UA_Logger * UA_Server_getLogger(UA_Server *server) {
-    return &server->logger;
+UA_Logger UA_Server_getLogger(UA_Server *server) {
+    return server->logger;
 }
 }
 
 
 void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
 void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
     UA_ServerNetworkLayer *newlayers =
     UA_ServerNetworkLayer *newlayers =
         UA_realloc(server->networkLayers, sizeof(UA_ServerNetworkLayer)*(server->networkLayersSize+1));
         UA_realloc(server->networkLayers, sizeof(UA_ServerNetworkLayer)*(server->networkLayersSize+1));
     if(!newlayers) {
     if(!newlayers) {
-        UA_LOG_ERROR(server->logger, UA_LOGGERCATEGORY_SERVER, "Networklayer added");
+        UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Networklayer added");
         return;
         return;
     }
     }
     server->networkLayers = newlayers;
     server->networkLayers = newlayers;
@@ -55,13 +54,16 @@ void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkL
         UA_String* newUrls = UA_realloc(server->description.discoveryUrls,
         UA_String* newUrls = UA_realloc(server->description.discoveryUrls,
                                         sizeof(UA_String)*(server->description.discoveryUrlsSize+1));
                                         sizeof(UA_String)*(server->description.discoveryUrlsSize+1));
         if(!newUrls) {
         if(!newUrls) {
-            UA_LOG_ERROR(server->logger, UA_LOGGERCATEGORY_SERVER, "Adding discoveryUrl");
+            UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Adding discoveryUrl");
             return;
             return;
         }
         }
         server->description.discoveryUrls = newUrls;
         server->description.discoveryUrls = newUrls;
         UA_String_copy(networkLayer.discoveryUrl,
         UA_String_copy(networkLayer.discoveryUrl,
                        &server->description.discoveryUrls[server->description.discoveryUrlsSize]);
                        &server->description.discoveryUrls[server->description.discoveryUrlsSize]);
         server->description.discoveryUrlsSize++;
         server->description.discoveryUrlsSize++;
+        for(UA_Int32 i = 0; i < server->endpointDescriptionsSize; i++)
+            if(!server->endpointDescriptions[i].endpointUrl.data)
+                UA_String_copy(networkLayer.discoveryUrl, &server->endpointDescriptions[i].endpointUrl);
     }
     }
 }
 }
 
 
@@ -113,60 +115,41 @@ void UA_Server_delete(UA_Server *server) {
     UA_free(server);
     UA_free(server);
 }
 }
 
 
-/**
- * Recurring cleanup. Removing unused and timed-out channels and sessions
- * Todo: make this thread-safe
- */
+/* Recurring cleanup. Removing unused and timed-out channels and sessions */
 static void UA_Server_cleanup(UA_Server *server, void *nothing) {
 static void UA_Server_cleanup(UA_Server *server, void *nothing) {
     UA_DateTime now = UA_DateTime_now();
     UA_DateTime now = UA_DateTime_now();
-    channel_list_entry *entry = LIST_FIRST(&server->secureChannelManager.channels);
-    /* remove channels that were not renewed or who have no connection attached */
-    while(entry) {
-        if(entry->channel.securityToken.createdAt +
-           (10000 * entry->channel.securityToken.revisedLifetime) > now &&
-           entry->channel.connection) {
-            entry = LIST_NEXT(entry, pointers);
-        } else {
-            channel_list_entry *next = LIST_NEXT(entry, pointers);
-            LIST_REMOVE(entry, pointers);
-            UA_Connection *c = entry->channel.connection;
-            if (c) {
-                UA_Connection_detachSecureChannel(c);
-                c->close(c);
-            }
-            UA_SecureChannel_detachSession(&entry->channel);
-            UA_SecureChannel_deleteMembers(&entry->channel);
-            UA_free(entry);
-            entry = next;
-        }
-    }
+    UA_SessionManager_cleanupTimedOut(&server->sessionManager, now);
+    UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, now);
+}
 
 
-    session_list_entry *sentry = LIST_FIRST(&server->sessionManager.sessions);
-    while(sentry) {
-        if(sentry->session.validTill < now) {
-            session_list_entry *next = LIST_NEXT(sentry, pointers);
-            LIST_REMOVE(sentry, pointers);
-            UA_SecureChannel_detachSession(sentry->session.channel);
-            UA_Session_deleteMembers(&sentry->session);
-            UA_free(sentry);
-            sentry = next;
-        }
-    }
+#define MANUFACTURER_NAME "open62541"
+#define PRODUCT_NAME "open62541 OPC UA Server"
+#define STRINGIFY(x) #x //some magic
+#define TOSTRING(x) STRINGIFY(x) //some magic
+#define SOFTWARE_VERSION TOSTRING(VERSION)
+#define BUILD_NUMBER "0"
+
+static void getBulidInfo(const UA_Server* server, UA_BuildInfo *buildInfo) {
+    buildInfo->productUri = UA_STRING_ALLOC(PRODUCT_URI);
+    buildInfo->manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME);
+    buildInfo->productName = UA_STRING_ALLOC(PRODUCT_NAME);
+    buildInfo->softwareVersion = UA_STRING_ALLOC(SOFTWARE_VERSION);
+    buildInfo->buildNumber = UA_STRING_ALLOC(BUILD_NUMBER);
+    buildInfo->buildDate = server->buildDate;
 }
 }
 
 
-static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp,
+                                const UA_NumericRange *range, UA_DataValue *value) {
+    if(range) {
+        value->hasStatus = UA_TRUE;
+        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
+        return UA_STATUSCODE_GOOD;
+    }
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     status->startTime   = ((const UA_Server*)handle)->startTime;
     status->startTime   = ((const UA_Server*)handle)->startTime;
     status->currentTime = UA_DateTime_now();
     status->currentTime = UA_DateTime_now();
     status->state       = UA_SERVERSTATE_RUNNING;
     status->state       = UA_SERVERSTATE_RUNNING;
-    status->buildInfo.productUri = UA_STRING("http://www.open62541.org");
-    status->buildInfo.manufacturerName = UA_STRING("open62541");
-    status->buildInfo.productName = UA_STRING("open62541 OPC UA Server");
-#define STRINGIFY(x) #x //some magic
-#define TOSTRING(x) STRINGIFY(x) //some magic
-    status->buildInfo.softwareVersion = UA_STRING(TOSTRING(OPEN62541_VERSION_MAJOR) "." TOSTRING(OPEN62541_VERSION_MINOR) "." TOSTRING(OPEN62541_VERSION_PATCH));
-    status->buildInfo.buildNumber = UA_STRING("0");
-    status->buildInfo.buildDate = ((const UA_Server*)handle)->buildDate;
+    getBulidInfo(((const UA_Server*)handle), &status->buildInfo);
     status->secondsTillShutdown = 0;
     status->secondsTillShutdown = 0;
 
 
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
@@ -183,13 +166,21 @@ static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp, UA_Dat
 }
 }
 
 
 static void releaseStatus(void *handle, UA_DataValue *value) {
 static void releaseStatus(void *handle, UA_DataValue *value) {
-    UA_free(value->value.data);
+    if(!value->hasValue)
+        return;
+    UA_ServerStatusDataType_delete((UA_ServerStatusDataType*)value->value.data);
     value->value.data = UA_NULL;
     value->value.data = UA_NULL;
     value->hasValue = UA_FALSE;
     value->hasValue = UA_FALSE;
     UA_DataValue_deleteMembers(value);
     UA_DataValue_deleteMembers(value);
 }
 }
 
 
-static UA_StatusCode readNamespaces(void *handle, UA_Boolean sourceTimestamp, UA_DataValue *value) {
+static UA_StatusCode readNamespaces(void *handle, UA_Boolean sourceTimestamp,
+                                    const UA_NumericRange *range, UA_DataValue *value) {
+    if(range) {
+        value->hasStatus = UA_TRUE;
+        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
+        return UA_STATUSCODE_GOOD;
+    }
     UA_Server *server = (UA_Server*)handle;
     UA_Server *server = (UA_Server*)handle;
     value->hasValue = UA_TRUE;
     value->hasValue = UA_TRUE;
     value->value.storageType = UA_VARIANT_DATA_NODELETE;
     value->value.storageType = UA_VARIANT_DATA_NODELETE;
@@ -206,16 +197,19 @@ static UA_StatusCode readNamespaces(void *handle, UA_Boolean sourceTimestamp, UA
 static void releaseNamespaces(void *handle, UA_DataValue *value) {
 static void releaseNamespaces(void *handle, UA_DataValue *value) {
 }
 }
 
 
-static UA_StatusCode readCurrentTime(void *handle, UA_Boolean sourceTimeStamp, UA_DataValue *value) {
+static UA_StatusCode readCurrentTime(void *handle, UA_Boolean sourceTimeStamp,
+                                     const UA_NumericRange *range, UA_DataValue *value) {
+    if(range) {
+        value->hasStatus = UA_TRUE;
+        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
+        return UA_STATUSCODE_GOOD;
+    }
     UA_DateTime *currentTime = UA_DateTime_new();
     UA_DateTime *currentTime = UA_DateTime_new();
     if(!currentTime)
     if(!currentTime)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
     *currentTime = UA_DateTime_now();
     *currentTime = UA_DateTime_now();
     value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
     value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
-    value->value.arrayLength = -1;
     value->value.data = currentTime;
     value->value.data = currentTime;
-    value->value.arrayDimensionsSize = -1;
-    value->value.arrayDimensions = NULL;
     value->hasValue = UA_TRUE;
     value->hasValue = UA_TRUE;
     if(sourceTimeStamp) {
     if(sourceTimeStamp) {
         value->hasSourceTimestamp = UA_TRUE;
         value->hasSourceTimestamp = UA_TRUE;
@@ -225,7 +219,8 @@ static UA_StatusCode readCurrentTime(void *handle, UA_Boolean sourceTimeStamp, U
 }
 }
 
 
 static void releaseCurrentTime(void *handle, UA_DataValue *value) {
 static void releaseCurrentTime(void *handle, UA_DataValue *value) {
-    UA_DateTime_delete((UA_DateTime*)value->value.data);
+    if(value->hasValue)
+        UA_DateTime_delete((UA_DateTime*)value->value.data);
 }
 }
 
 
 static void copyNames(UA_Node *node, char *name) {
 static void copyNames(UA_Node *node, char *name) {
@@ -239,8 +234,8 @@ static void addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid,
     copyNames((UA_Node*)datatype, name);
     copyNames((UA_Node*)datatype, name);
     datatype->nodeId.identifier.numeric = datatypeid;
     datatype->nodeId.identifier.numeric = datatypeid;
     UA_Server_addNode(server, (UA_Node*)datatype,
     UA_Server_addNode(server, (UA_Node*)datatype,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, parent),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+                      UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 }
 }
 
 
 static void addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid, UA_Int32 parent,
 static void addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid, UA_Int32 parent,
@@ -249,14 +244,13 @@ static void addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttyp
     copyNames((UA_Node*)objecttype, name);
     copyNames((UA_Node*)objecttype, name);
     objecttype->nodeId.identifier.numeric = objecttypeid;
     objecttype->nodeId.identifier.numeric = objecttypeid;
     UA_Server_addNode(server, (UA_Node*)objecttype,
     UA_Server_addNode(server, (UA_Node*)objecttype,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, parent),
-                      &UA_NODEID_NUMERIC(0, parentreference));
+                      UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      UA_NODEID_NUMERIC(0, parentreference));
 }
 }
 
 
 static UA_VariableTypeNode*
 static UA_VariableTypeNode*
 createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
 createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
-                       UA_Int32 parent, UA_Boolean abstract)
-{
+                       UA_Int32 parent, UA_Boolean abstract) {
     UA_VariableTypeNode *variabletype = UA_VariableTypeNode_new();
     UA_VariableTypeNode *variabletype = UA_VariableTypeNode_new();
     copyNames((UA_Node*)variabletype, name);
     copyNames((UA_Node*)variabletype, name);
     variabletype->nodeId.identifier.numeric = variabletypeid;
     variabletype->nodeId.identifier.numeric = variabletypeid;
@@ -268,19 +262,17 @@ createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
 static void addVariableTypeNode_organized(UA_Server *server, char* name, UA_UInt32 variabletypeid,
 static void addVariableTypeNode_organized(UA_Server *server, char* name, UA_UInt32 variabletypeid,
                                           UA_Int32 parent, UA_Boolean abstract) {
                                           UA_Int32 parent, UA_Boolean abstract) {
     UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
     UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
-
     UA_Server_addNode(server, (UA_Node*)variabletype,
     UA_Server_addNode(server, (UA_Node*)variabletype,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, parent),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+                      UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 }
 }
 
 
 static void addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletypeid,
 static void addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletypeid,
                                         UA_Int32 parent, UA_Boolean abstract) {
                                         UA_Int32 parent, UA_Boolean abstract) {
     UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
     UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
-
     UA_Server_addNode(server, (UA_Node*)variabletype,
     UA_Server_addNode(server, (UA_Node*)variabletype,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, parent),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 }
 }
 
 
 UA_Server * UA_Server_new(UA_ServerConfig config) {
 UA_Server * UA_Server_new(UA_ServerConfig config) {
@@ -299,7 +291,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 #endif
 #endif
 
 
     // logger
     // logger
-    server->logger = (UA_Logger){ UA_NULL, UA_NULL, UA_NULL, UA_NULL, UA_NULL, UA_NULL };
+    server->logger = UA_NULL;
 
 
     // random seed
     // random seed
     server->random_seed = (UA_UInt32)UA_DateTime_now();
     server->random_seed = (UA_UInt32)UA_DateTime_now();
@@ -321,9 +313,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     server->externalNamespacesSize = 0;
     server->externalNamespacesSize = 0;
     server->externalNamespaces = UA_NULL;
     server->externalNamespaces = UA_NULL;
 
 
-    server->namespaces = UA_String_new();
-    *server->namespaces = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
-    server->namespacesSize = 1;
+    /* ns0 and ns1 */
+    server->namespaces = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
+    server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
+    UA_String_copy(&server->description.applicationUri, &server->namespaces[1]);
+    server->namespacesSize = 2;
 
 
     server->endpointDescriptions = UA_NULL;
     server->endpointDescriptions = UA_NULL;
     server->endpointDescriptionsSize = 0;
     server->endpointDescriptionsSize = 0;
@@ -368,7 +362,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 
 
         server->endpointDescriptions = endpoint;
         server->endpointDescriptions = endpoint;
         server->endpointDescriptionsSize = 1;
         server->endpointDescriptionsSize = 1;
-    }
+    } 
 
 
 #define MAXCHANNELCOUNT 100
 #define MAXCHANNELCOUNT 100
 #define STARTCHANNELID 1
 #define STARTCHANNELID 1
@@ -427,17 +421,17 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 #define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
 #define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
     server->buildDate = (mktime(&ct) + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC;
     server->buildDate = (mktime(&ct) + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC;
 
 
-#ifndef LOADGENERATEDNS
     /**************/
     /**************/
     /* References */
     /* References */
     /**************/
     /**************/
-
+    
     /* bootstrap by manually inserting "references" and "hassubtype" */
     /* bootstrap by manually inserting "references" and "hassubtype" */
     UA_ReferenceTypeNode *references = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *references = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)references, "References");
     copyNames((UA_Node*)references, "References");
     references->nodeId.identifier.numeric = UA_NS0ID_REFERENCES;
     references->nodeId.identifier.numeric = UA_NS0ID_REFERENCES;
     references->isAbstract = UA_TRUE;
     references->isAbstract = UA_TRUE;
     references->symmetric  = UA_TRUE;
     references->symmetric  = UA_TRUE;
+    references->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "References");
     // this node has no parent??
     // this node has no parent??
     UA_NodeStore_insert(server->nodestore, (UA_Node*)references, UA_NULL);
     UA_NodeStore_insert(server->nodestore, (UA_Node*)references, UA_NULL);
 
 
@@ -456,8 +450,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->symmetric  = UA_FALSE;
     hierarchicalreferences->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hierarchicalreferences,
     UA_Server_addNode(server, (UA_Node*)hierarchicalreferences,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)nonhierarchicalreferences, "NonHierarchicalReferences");
     copyNames((UA_Node*)nonhierarchicalreferences, "NonHierarchicalReferences");
@@ -465,8 +459,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)nonhierarchicalreferences,
     UA_Server_addNode(server, (UA_Node*)nonhierarchicalreferences,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haschild, "HasChild");
     copyNames((UA_Node*)haschild, "HasChild");
@@ -474,8 +468,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     haschild->isAbstract = UA_TRUE;
     haschild->isAbstract = UA_TRUE;
     haschild->symmetric  = UA_FALSE;
     haschild->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)haschild,
     UA_Server_addNode(server, (UA_Node*)haschild,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)organizes, "Organizes");
     copyNames((UA_Node*)organizes, "Organizes");
@@ -484,8 +478,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     organizes->isAbstract = UA_FALSE;
     organizes->isAbstract = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)organizes,
     UA_Server_addNode(server, (UA_Node*)organizes,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haseventsource, "HasEventSource");
     copyNames((UA_Node*)haseventsource, "HasEventSource");
@@ -494,8 +488,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     haseventsource->isAbstract = UA_FALSE;
     haseventsource->isAbstract = UA_FALSE;
     haseventsource->symmetric  = UA_FALSE;
     haseventsource->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)haseventsource,
     UA_Server_addNode(server, (UA_Node*)haseventsource,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasmodellingrule, "HasModellingRule");
     copyNames((UA_Node*)hasmodellingrule, "HasModellingRule");
@@ -504,8 +498,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasmodellingrule->isAbstract = UA_FALSE;
     hasmodellingrule->isAbstract = UA_FALSE;
     hasmodellingrule->symmetric  = UA_FALSE;
     hasmodellingrule->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasmodellingrule,
     UA_Server_addNode(server, (UA_Node*)hasmodellingrule,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasencoding, "HasEncoding");
     copyNames((UA_Node*)hasencoding, "HasEncoding");
@@ -514,8 +508,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasencoding->isAbstract = UA_FALSE;
     hasencoding->isAbstract = UA_FALSE;
     hasencoding->symmetric  = UA_FALSE;
     hasencoding->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasencoding,
     UA_Server_addNode(server, (UA_Node*)hasencoding,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasdescription, "HasDescription");
     copyNames((UA_Node*)hasdescription, "HasDescription");
@@ -524,8 +518,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasdescription->isAbstract = UA_FALSE;
     hasdescription->isAbstract = UA_FALSE;
     hasdescription->symmetric  = UA_FALSE;
     hasdescription->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasdescription,
     UA_Server_addNode(server, (UA_Node*)hasdescription,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hastypedefinition, "HasTypeDefinition");
     copyNames((UA_Node*)hastypedefinition, "HasTypeDefinition");
@@ -534,8 +528,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hastypedefinition->isAbstract = UA_FALSE;
     hastypedefinition->isAbstract = UA_FALSE;
     hastypedefinition->symmetric  = UA_FALSE;
     hastypedefinition->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hastypedefinition,
     UA_Server_addNode(server, (UA_Node*)hastypedefinition,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)generatesevent, "GeneratesEvent");
     copyNames((UA_Node*)generatesevent, "GeneratesEvent");
@@ -544,8 +538,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     generatesevent->isAbstract = UA_FALSE;
     generatesevent->isAbstract = UA_FALSE;
     generatesevent->symmetric  = UA_FALSE;
     generatesevent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)generatesevent,
     UA_Server_addNode(server, (UA_Node*)generatesevent,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)aggregates, "Aggregates");
     copyNames((UA_Node*)aggregates, "Aggregates");
@@ -554,8 +548,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     aggregates->isAbstract = UA_TRUE;
     aggregates->isAbstract = UA_TRUE;
     aggregates->symmetric  = UA_FALSE;
     aggregates->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)aggregates,
     UA_Server_addNode(server, (UA_Node*)aggregates,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCHILD),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCHILD),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     // complete bootstrap of hassubtype
     // complete bootstrap of hassubtype
     ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
     ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
@@ -568,8 +562,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasproperty->isAbstract = UA_FALSE;
     hasproperty->isAbstract = UA_FALSE;
     hasproperty->symmetric  = UA_FALSE;
     hasproperty->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasproperty,
     UA_Server_addNode(server, (UA_Node*)hasproperty,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hascomponent, "HasComponent");
     copyNames((UA_Node*)hascomponent, "HasComponent");
@@ -578,8 +572,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hascomponent->isAbstract = UA_FALSE;
     hascomponent->isAbstract = UA_FALSE;
     hascomponent->symmetric  = UA_FALSE;
     hascomponent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hascomponent,
     UA_Server_addNode(server, (UA_Node*)hascomponent,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasnotifier, "HasNotifier");
     copyNames((UA_Node*)hasnotifier, "HasNotifier");
@@ -588,8 +582,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasnotifier->isAbstract = UA_FALSE;
     hasnotifier->isAbstract = UA_FALSE;
     hasnotifier->symmetric  = UA_FALSE;
     hasnotifier->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasnotifier,
     UA_Server_addNode(server, (UA_Node*)hasnotifier,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasorderedcomponent, "HasOrderedComponent");
     copyNames((UA_Node*)hasorderedcomponent, "HasOrderedComponent");
@@ -598,8 +592,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasorderedcomponent->isAbstract = UA_FALSE;
     hasorderedcomponent->isAbstract = UA_FALSE;
     hasorderedcomponent->symmetric  = UA_FALSE;
     hasorderedcomponent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasorderedcomponent,
     UA_Server_addNode(server, (UA_Node*)hasorderedcomponent,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasmodelparent, "HasModelParent");
     copyNames((UA_Node*)hasmodelparent, "HasModelParent");
@@ -608,8 +602,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasmodelparent->isAbstract = UA_FALSE;
     hasmodelparent->isAbstract = UA_FALSE;
     hasmodelparent->symmetric  = UA_FALSE;
     hasmodelparent->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hasmodelparent,
     UA_Server_addNode(server, (UA_Node*)hasmodelparent,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)fromstate, "FromState");
     copyNames((UA_Node*)fromstate, "FromState");
@@ -618,8 +612,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     fromstate->isAbstract = UA_FALSE;
     fromstate->isAbstract = UA_FALSE;
     fromstate->symmetric  = UA_FALSE;
     fromstate->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)fromstate,
     UA_Server_addNode(server, (UA_Node*)fromstate,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)tostate, "ToState");
     copyNames((UA_Node*)tostate, "ToState");
@@ -628,8 +622,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     tostate->isAbstract = UA_FALSE;
     tostate->isAbstract = UA_FALSE;
     tostate->symmetric  = UA_FALSE;
     tostate->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)tostate,
     UA_Server_addNode(server, (UA_Node*)tostate,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hascause, "HasCause");
     copyNames((UA_Node*)hascause, "HasCause");
@@ -638,9 +632,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hascause->isAbstract = UA_FALSE;
     hascause->isAbstract = UA_FALSE;
     hascause->symmetric  = UA_FALSE;
     hascause->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hascause,
     UA_Server_addNode(server, (UA_Node*)hascause,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
-
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+    
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haseffect, "HasEffect");
     copyNames((UA_Node*)haseffect, "HasEffect");
     haseffect->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "MayBeEffectedBy");
     haseffect->inverseName = UA_LOCALIZEDTEXT_ALLOC("", "MayBeEffectedBy");
@@ -648,8 +642,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     haseffect->isAbstract = UA_FALSE;
     haseffect->isAbstract = UA_FALSE;
     haseffect->symmetric  = UA_FALSE;
     haseffect->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)haseffect,
     UA_Server_addNode(server, (UA_Node*)haseffect,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hashistoricalconfiguration, "HasHistoricalConfiguration");
     copyNames((UA_Node*)hashistoricalconfiguration, "HasHistoricalConfiguration");
@@ -658,8 +652,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hashistoricalconfiguration->isAbstract = UA_FALSE;
     hashistoricalconfiguration->isAbstract = UA_FALSE;
     hashistoricalconfiguration->symmetric  = UA_FALSE;
     hashistoricalconfiguration->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)hashistoricalconfiguration,
     UA_Server_addNode(server, (UA_Node*)hashistoricalconfiguration,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 
     /*****************/
     /*****************/
     /* Basic Folders */
     /* Basic Folders */
@@ -674,22 +668,32 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)objects, "Objects");
     copyNames((UA_Node*)objects, "Objects");
     objects->nodeId.identifier.numeric = UA_NS0ID_OBJECTSFOLDER;
     objects->nodeId.identifier.numeric = UA_NS0ID_OBJECTSFOLDER;
     UA_Server_addNode(server, (UA_Node*)objects,
     UA_Server_addNode(server, (UA_Node*)objects,
-        &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
-        &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
 
     UA_ObjectNode *types = UA_ObjectNode_new();
     UA_ObjectNode *types = UA_ObjectNode_new();
     copyNames((UA_Node*)types, "Types");
     copyNames((UA_Node*)types, "Types");
     types->nodeId.identifier.numeric = UA_NS0ID_TYPESFOLDER;
     types->nodeId.identifier.numeric = UA_NS0ID_TYPESFOLDER;
     UA_Server_addNode(server, (UA_Node*)types,
     UA_Server_addNode(server, (UA_Node*)types,
-        &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
-        &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
 
     UA_ObjectNode *views = UA_ObjectNode_new();
     UA_ObjectNode *views = UA_ObjectNode_new();
     copyNames((UA_Node*)views, "Views");
     copyNames((UA_Node*)views, "Views");
     views->nodeId.identifier.numeric = UA_NS0ID_VIEWSFOLDER;
     views->nodeId.identifier.numeric = UA_NS0ID_VIEWSFOLDER;
     UA_Server_addNode(server, (UA_Node*)views,
     UA_Server_addNode(server, (UA_Node*)views,
-        &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
-        &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+
+    UA_ObjectNode *referencetypes = UA_ObjectNode_new();
+    copyNames((UA_Node*)referencetypes, "ReferenceTypes");
+    referencetypes->nodeId.identifier.numeric = UA_NS0ID_REFERENCETYPESFOLDER;
+    UA_Server_addNode(server, (UA_Node*)referencetypes,
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES));
 
 
     /**********************/
     /**********************/
     /* Basic Object Types */
     /* Basic Object Types */
@@ -699,8 +703,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)objecttypes, "ObjectTypes");
     copyNames((UA_Node*)objecttypes, "ObjectTypes");
     objecttypes->nodeId.identifier.numeric = UA_NS0ID_OBJECTTYPESFOLDER;
     objecttypes->nodeId.identifier.numeric = UA_NS0ID_OBJECTTYPESFOLDER;
     UA_Server_addNode(server, (UA_Node*)objecttypes,
     UA_Server_addNode(server, (UA_Node*)objecttypes,
-        &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-        &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
 
 
     addObjectTypeNode(server, "BaseObjectType", UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_ORGANIZES);
     addObjectTypeNode(server, "BaseObjectType", UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_ORGANIZES);
     addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
@@ -714,10 +718,13 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
     ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
     ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    addObjectTypeNode(server, "ServerType", UA_NS0ID_SERVERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerDiagnosticsType", UA_NS0ID_SERVERDIAGNOSTICSTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerDiagnosticsType", UA_NS0ID_SERVERDIAGNOSTICSTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerCapatilitiesType", UA_NS0ID_SERVERCAPABILITIESTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerCapatilitiesType", UA_NS0ID_SERVERCAPABILITIESTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerStatusType", UA_NS0ID_SERVERSTATUSTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerStatusType", UA_NS0ID_SERVERSTATUSTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
-
+    addObjectTypeNode(server, "BuildInfoType", UA_NS0ID_BUILDINFOTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
 
 
     /**************/
     /**************/
     /* Data Types */
     /* Data Types */
@@ -727,8 +734,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)datatypes, "DataTypes");
     copyNames((UA_Node*)datatypes, "DataTypes");
     datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
     datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
     UA_Server_addNode(server, (UA_Node*)datatypes,
     UA_Server_addNode(server, (UA_Node*)datatypes,
-                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-                      &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                      UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
     ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_DATATYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
     ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_DATATYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                  UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
                  UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
 
@@ -758,6 +765,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     addDataTypeNode(server, "QualifiedName", UA_NS0ID_QUALIFIEDNAME, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "QualifiedName", UA_NS0ID_QUALIFIEDNAME, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "LocalizedText", UA_NS0ID_LOCALIZEDTEXT, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "LocalizedText", UA_NS0ID_LOCALIZEDTEXT, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "Structure", UA_NS0ID_STRUCTURE, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "Structure", UA_NS0ID_STRUCTURE, UA_NS0ID_BASEDATATYPE);
+        addDataTypeNode(server, "ServerStatusDataType", UA_NS0ID_SERVERSTATUSDATATYPE, UA_NS0ID_STRUCTURE);
+        addDataTypeNode(server, "BuildInfo", UA_NS0ID_BUILDINFO, UA_NS0ID_STRUCTURE);
     addDataTypeNode(server, "DataValue", UA_NS0ID_DATAVALUE, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "DataValue", UA_NS0ID_DATAVALUE, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "DiagnosticInfo", UA_NS0ID_DIAGNOSTICINFO, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "DiagnosticInfo", UA_NS0ID_DIAGNOSTICINFO, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "Enumeration", UA_NS0ID_ENUMERATION, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "Enumeration", UA_NS0ID_ENUMERATION, UA_NS0ID_BASEDATATYPE);
@@ -767,8 +776,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    copyNames((UA_Node*)variabletypes, "VariableTypes");
    copyNames((UA_Node*)variabletypes, "VariableTypes");
    variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
    variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
    UA_Server_addNode(server, (UA_Node*)variabletypes,
    UA_Server_addNode(server, (UA_Node*)variabletypes,
-                     &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-                     &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+                     UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                     UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
    addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE, UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
    addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE, UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
@@ -783,8 +792,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    copyNames((UA_Node*)servernode, "Server");
    copyNames((UA_Node*)servernode, "Server");
    servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
    servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
    UA_Server_addNode(server, (UA_Node*)servernode,
    UA_Server_addNode(server, (UA_Node*)servernode,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+           UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
+   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
+       UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE));
 
 
    UA_VariableNode *namespaceArray = UA_VariableNode_new();
    UA_VariableNode *namespaceArray = UA_VariableNode_new();
    copyNames((UA_Node*)namespaceArray, "NamespaceArray");
    copyNames((UA_Node*)namespaceArray, "NamespaceArray");
@@ -796,8 +808,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    namespaceArray->minimumSamplingInterval = 1.0;
    namespaceArray->minimumSamplingInterval = 1.0;
    namespaceArray->historizing = UA_FALSE;
    namespaceArray->historizing = UA_FALSE;
    UA_Server_addNode(server, (UA_Node*)namespaceArray,
    UA_Server_addNode(server, (UA_Node*)namespaceArray,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+           UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                 UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                 UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
@@ -813,8 +825,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    serverArray->minimumSamplingInterval = 1.0;
    serverArray->minimumSamplingInterval = 1.0;
    serverArray->historizing = UA_FALSE;
    serverArray->historizing = UA_FALSE;
    UA_Server_addNode(server, (UA_Node*)serverArray,
    UA_Server_addNode(server, (UA_Node*)serverArray,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+           UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY),
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY),
                 UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                 UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
                 UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
@@ -823,8 +835,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    copyNames((UA_Node*)servercapablities, "ServerCapabilities");
    copyNames((UA_Node*)servercapablities, "ServerCapabilities");
    servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
    servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
    UA_Server_addNode(server, (UA_Node*)servercapablities,
    UA_Server_addNode(server, (UA_Node*)servercapablities,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE));
        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE));
 
 
@@ -839,126 +851,188 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    localeIdArray->minimumSamplingInterval = 1.0;
    localeIdArray->minimumSamplingInterval = 1.0;
    localeIdArray->historizing = UA_FALSE;
    localeIdArray->historizing = UA_FALSE;
    UA_Server_addNode(server, (UA_Node*)localeIdArray,
    UA_Server_addNode(server, (UA_Node*)localeIdArray,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
+           UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
            UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
            UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
 
-   UA_ObjectNode *serverdiagnostics = UA_ObjectNode_new();
-   copyNames((UA_Node*)serverdiagnostics, "ServerDiagnostics");
-   serverdiagnostics->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS;
-   UA_Server_addNode(server, (UA_Node*)serverdiagnostics,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
-   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE));
-
-   UA_VariableNode *enabledFlag = UA_VariableNode_new();
-   copyNames((UA_Node*)enabledFlag, "EnabledFlag");
-   enabledFlag->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG;
-   enabledFlag->value.variant.data = UA_Boolean_new(); //itialized as false
-   enabledFlag->value.variant.type = &UA_TYPES[UA_TYPES_BOOLEAN];
-   enabledFlag->valueRank = 1;
-   enabledFlag->minimumSamplingInterval = 1.0;
-   enabledFlag->historizing = UA_FALSE;
-   UA_Server_addNode(server, (UA_Node*)enabledFlag,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
-   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
-
-   UA_VariableNode *serverstatus = UA_VariableNode_new();
-   copyNames((UA_Node*)serverstatus, "ServerStatus");
-   serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
-   serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
-   serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus,
-       .release = releaseStatus, .write = UA_NULL};
-   UA_Server_addNode(server, (UA_Node*)serverstatus, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
-   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE));
-
-   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->value.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
-   state->value.variant.arrayLength = -1;
-   state->value.variant.data = stateEnum; // points into the other object.
-   UA_NodeStore_insert(server->nodestore, (UA_Node*)state, UA_NULL);
-   ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
-
-   UA_VariableNode *currenttime = UA_VariableNode_new();
-   copyNames((UA_Node*)currenttime, "CurrentTime");
-   currenttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
-   currenttime->valueSource = UA_VALUESOURCE_DATASOURCE;
-   currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
-       .release = releaseCurrentTime, .write = UA_NULL};
-   UA_Server_addNode(server, (UA_Node*)currenttime, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-           &UA_NODEID_NUMERIC(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_NUMERIC(1, DEMOID);
-   UA_Server_addNode(server, (UA_Node*)demo,
-           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
-   ADDREFERENCE(UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-
-#define SCALARID 991
-   UA_ObjectNode *scalar = UA_ObjectNode_new();
-   copyNames((UA_Node*)scalar, "Scalar");
-   scalar->nodeId = UA_NODEID_NUMERIC(1, SCALARID);
-   UA_Server_addNode(server, (UA_Node*)scalar,
-           &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
-   ADDREFERENCE(UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-
-#define ARRAYID 992
-   UA_ObjectNode *array = UA_ObjectNode_new();
-   copyNames((UA_Node*)array, "Arrays");
-   array->nodeId = UA_NODEID_NUMERIC(1, ARRAYID);
-   UA_Server_addNode(server, (UA_Node*)array,
-           &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID),
-           &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
-   ADDREFERENCE(UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
-           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-
-   UA_UInt32 id = 1000; //running id in namespace 1
-   for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
-       if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
-           continue;
-       //add a scalar node for every built-in type
-        void *value = UA_new(&UA_TYPES[type]);
-        UA_Variant *variant = UA_Variant_new();
-        UA_Variant_setScalar(variant, value, &UA_TYPES[type]);
-        char name[15];
-        sprintf(name, "%02d", type);
-        UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, name);
-        UA_Server_addVariableNode(server, variant, myIntegerName, UA_NODEID_NUMERIC(1, ++id),
-                                  UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
-
-        //add an array node for every built-in type
-        UA_Variant *arrayvar = UA_Variant_new();
-        UA_Variant_setArray(arrayvar, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
-        UA_Server_addVariableNode(server, arrayvar, myIntegerName, UA_NODEID_NUMERIC(1, ++id),
-                                  UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES));
-   }
-#endif
-#else
-  #include "ua_namespaceinit_generated.h"
-#endif
+   UA_VariableNode *maxBrowseContinuationPoints = UA_VariableNode_new();
+    copyNames((UA_Node*)maxBrowseContinuationPoints, "MaxBrowseContinuationPoints");
+    maxBrowseContinuationPoints->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS;
+    maxBrowseContinuationPoints->value.variant.data = UA_UInt16_new();
+    *((UA_UInt16*)maxBrowseContinuationPoints->value.variant.data) = MAXCONTINUATIONPOINTS;
+    maxBrowseContinuationPoints->value.variant.type = &UA_TYPES[UA_TYPES_UINT16];
+    UA_Server_addNode(server, (UA_Node*)maxBrowseContinuationPoints,
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+
+    UA_ObjectNode *serverdiagnostics = UA_ObjectNode_new();
+    copyNames((UA_Node*)serverdiagnostics, "ServerDiagnostics");
+    serverdiagnostics->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS;
+    UA_Server_addNode(server, (UA_Node*)serverdiagnostics,
+            UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+    ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE));
+
+    UA_VariableNode *enabledFlag = UA_VariableNode_new();
+     copyNames((UA_Node*)enabledFlag, "EnabledFlag");
+     enabledFlag->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG;
+     enabledFlag->value.variant.data = UA_Boolean_new(); //itialized as false
+     enabledFlag->value.variant.type = &UA_TYPES[UA_TYPES_BOOLEAN];
+     enabledFlag->valueRank = 1;
+     enabledFlag->minimumSamplingInterval = 1.0;
+     enabledFlag->historizing = UA_FALSE;
+     UA_Server_addNode(server, (UA_Node*)enabledFlag,
+             UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
+             UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY));
+     ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+             UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+
+     UA_VariableNode *serverstatus = UA_VariableNode_new();
+      copyNames((UA_Node*)serverstatus, "ServerStatus");
+      serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
+      serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
+      serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus,
+          .release = releaseStatus, .write = UA_NULL};
+      UA_Server_addNode(server, (UA_Node*)serverstatus, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+      ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE));
+
+      UA_VariableNode *starttime = UA_VariableNode_new();
+      copyNames((UA_Node*)starttime, "StartTime");
+      starttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
+      starttime->value.variant.storageType = UA_VARIANT_DATA_NODELETE;
+      starttime->value.variant.data = &server->startTime;
+      starttime->value.variant.type = &UA_TYPES[UA_TYPES_DATETIME];
+      UA_Server_addNode(server, (UA_Node*)starttime, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+      ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+      UA_VariableNode *currenttime = UA_VariableNode_new();
+      copyNames((UA_Node*)currenttime, "CurrentTime");
+      currenttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+      currenttime->valueSource = UA_VALUESOURCE_DATASOURCE;
+      currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
+          .release = releaseCurrentTime, .write = UA_NULL};
+      UA_Server_addNode(server, (UA_Node*)currenttime, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+      ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+      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->value.variant.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
+      state->value.variant.arrayLength = -1;
+      state->value.variant.data = stateEnum; // points into the other object.
+      UA_Server_addNode(server, (UA_Node*)state, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+      ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+      UA_VariableNode *buildinfo = UA_VariableNode_new();
+       copyNames((UA_Node*)buildinfo, "BuildInfo");
+       buildinfo->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO);
+       buildinfo->value.variant.data = UA_BuildInfo_new();
+       buildinfo->value.variant.type = &UA_TYPES[UA_TYPES_BUILDINFO];
+       getBulidInfo(server, (UA_BuildInfo*)buildinfo->value.variant.data);
+       UA_Server_addNode(server, (UA_Node*)buildinfo, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE));
+
+       UA_VariableNode *producturi = UA_VariableNode_new();
+       copyNames((UA_Node*)producturi, "ProductUri");
+       producturi->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI);
+       producturi->value.variant.data = UA_String_new();
+       *((UA_String*)producturi->value.variant.data) = UA_STRING_ALLOC(PRODUCT_URI);
+       producturi->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       UA_Server_addNode(server, (UA_Node*)producturi, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+       UA_VariableNode *manufacturername = UA_VariableNode_new();
+       copyNames((UA_Node*)manufacturername, "ManufacturererName");
+       manufacturername->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME);
+       manufacturername->value.variant.data = UA_String_new();
+       *((UA_String*)manufacturername->value.variant.data) = UA_STRING_ALLOC(MANUFACTURER_NAME);
+       manufacturername->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       UA_Server_addNode(server, (UA_Node*)manufacturername, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+       UA_VariableNode *productname = UA_VariableNode_new();
+       copyNames((UA_Node*)productname, "ProductName");
+       productname->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME);
+       productname->value.variant.data = UA_String_new();
+       *((UA_String*)productname->value.variant.data) = UA_STRING_ALLOC(PRODUCT_NAME);
+       productname->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       UA_Server_addNode(server, (UA_Node*)productname, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+       UA_VariableNode *softwareversion = UA_VariableNode_new();
+       copyNames((UA_Node*)softwareversion, "SoftwareVersion");
+       softwareversion->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION);
+       softwareversion->value.variant.data = UA_String_new();
+       *((UA_String*)softwareversion->value.variant.data) = UA_STRING_ALLOC(SOFTWARE_VERSION);
+       softwareversion->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       UA_Server_addNode(server, (UA_Node*)softwareversion, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+       UA_VariableNode *buildnumber = UA_VariableNode_new();
+       copyNames((UA_Node*)buildnumber, "BuildNumber");
+       buildnumber->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER);
+       buildnumber->value.variant.data = UA_String_new();
+       *((UA_String*)buildnumber->value.variant.data) = UA_STRING_ALLOC(BUILD_NUMBER);
+       buildnumber->value.variant.type = &UA_TYPES[UA_TYPES_STRING];
+       UA_Server_addNode(server, (UA_Node*)buildnumber, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+       UA_VariableNode *builddate = UA_VariableNode_new();
+       copyNames((UA_Node*)builddate, "BuildDate");
+       builddate->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE);
+       builddate->value.variant.storageType = UA_VARIANT_DATA_NODELETE;
+       builddate->value.variant.data = &server->buildDate;
+       builddate->value.variant.type = &UA_TYPES[UA_TYPES_DATETIME];
+       UA_Server_addNode(server, (UA_Node*)builddate, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+       UA_VariableNode *secondstillshutdown = UA_VariableNode_new();
+       copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
+       secondstillshutdown->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN);
+       secondstillshutdown->value.variant.data = UA_UInt32_new();
+       secondstillshutdown->value.variant.type = &UA_TYPES[UA_TYPES_UINT32];
+       UA_Server_addNode(server, (UA_Node*)secondstillshutdown, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
+
+       UA_VariableNode *shutdownreason = UA_VariableNode_new();
+       copyNames((UA_Node*)shutdownreason, "ShutdownReason");
+       shutdownreason->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON);
+       shutdownreason->value.variant.data = UA_LocalizedText_new();
+       shutdownreason->value.variant.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+       UA_Server_addNode(server, (UA_Node*)shutdownreason, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT));
+       ADDREFERENCE(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON), UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
+           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
 
 
    return server;
    return server;
 }
 }

+ 44 - 13
src/server/ua_server_addressspace.c

@@ -14,7 +14,7 @@ UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_Qualifi
     UA_ExpandedNodeId_init(&parentId);
     UA_ExpandedNodeId_init(&parentId);
     UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
     UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
     UA_AddNodesResult res =
     UA_AddNodesResult res =
-        UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
+        UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, parentId, referenceTypeId);
     ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
     ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                  UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
                  UA_EXPANDEDNODEID_NUMERIC(0, value->type->typeId.identifier.numeric));
     if(res.statusCode != UA_STATUSCODE_GOOD) {
     if(res.statusCode != UA_STATUSCODE_GOOD) {
@@ -26,6 +26,33 @@ UA_Server_addVariableNode(UA_Server *server, UA_Variant *value, const UA_Qualifi
     return res.statusCode;
     return res.statusCode;
 }
 }
 
 
+UA_StatusCode
+UA_Server_addObjectNode(UA_Server *server, const UA_QualifiedName browseName,
+                          UA_NodeId nodeId, const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId, const UA_NodeId typeDefinition)
+{
+    UA_ObjectNode *node = UA_ObjectNode_new();
+    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);
+    UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
+    UA_AddNodesResult res =
+        UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, parentId, referenceTypeId);
+    if(res.statusCode != UA_STATUSCODE_GOOD) {
+        UA_ObjectNode_delete(node);
+    }
+    UA_AddNodesResult_deleteMembers(&res);
+
+    if(!(UA_NodeId_isNull(&typeDefinition))){
+        UA_ExpandedNodeId typeDefid; // we need an expandednodeid
+        UA_ExpandedNodeId_init(&typeDefid);
+        UA_NodeId_copy(&typeDefinition, &typeDefid.nodeId);
+        ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION), typeDefid);
+    }
+    return res.statusCode;
+}
+
 UA_StatusCode
 UA_StatusCode
 UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
 UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
                                     const UA_QualifiedName browseName, UA_NodeId nodeId,
                                     const UA_QualifiedName browseName, UA_NodeId nodeId,
@@ -41,7 +68,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
     UA_ExpandedNodeId_init(&parentId);
     UA_ExpandedNodeId_init(&parentId);
     UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
     UA_NodeId_copy(&parentNodeId, &parentId.nodeId);
     UA_AddNodesResult res =
     UA_AddNodesResult res =
-        UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, &parentId, &referenceTypeId);
+        UA_Server_addNodeWithSession(server, &adminSession, (UA_Node*)node, parentId, referenceTypeId);
     ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
     ADDREFERENCE(res.addedNodeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION),
                  UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
                  UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE));
     if(res.statusCode != UA_STATUSCODE_GOOD)
     if(res.statusCode != UA_STATUSCODE_GOOD)
@@ -52,8 +79,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, UA_DataSource dataSource,
 
 
 /* Adds a one-way reference to the local nodestore */
 /* Adds a one-way reference to the local nodestore */
 static UA_StatusCode
 static UA_StatusCode
-addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item)
-{
+addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
     const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
     const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -62,7 +88,8 @@ addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_A
 	size_t i = node->referencesSize;
 	size_t i = node->referencesSize;
 	if(node->referencesSize < 0)
 	if(node->referencesSize < 0)
 		i = 0;
 		i = 0;
-	UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * (i + 1));
+    size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
+	UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
 	if(!new_refs)
 	if(!new_refs)
 		retval = UA_STATUSCODE_BADOUTOFMEMORY;
 		retval = UA_STATUSCODE_BADOUTOFMEMORY;
 	else {
 	else {
@@ -182,7 +209,9 @@ UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const
     if(item->targetServerUri.length > 0)
     if(item->targetServerUri.length > 0)
         return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
         return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
     
     
-    // Is this for an external nodestore?
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
+#ifdef UA_EXTERNAL_NAMESPACES
     UA_ExternalNodeStore *ensFirst = UA_NULL;
     UA_ExternalNodeStore *ensFirst = UA_NULL;
     UA_ExternalNodeStore *ensSecond = UA_NULL;
     UA_ExternalNodeStore *ensSecond = UA_NULL;
     for(size_t j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
     for(size_t j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
@@ -192,10 +221,10 @@ UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const
             ensSecond = &server->externalNamespaces[j].externalNodeStore;
             ensSecond = &server->externalNamespaces[j].externalNodeStore;
     }
     }
 
 
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(ensFirst) {
     if(ensFirst) {
         // todo: use external nodestore
         // todo: use external nodestore
     } else
     } else
+#endif
         retval = addOneWayReferenceWithSession(server, session, item);
         retval = addOneWayReferenceWithSession(server, session, item);
 
 
     if(retval) return retval;
     if(retval) return retval;
@@ -205,26 +234,28 @@ UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const
     secondItem.targetNodeId.nodeId = item->sourceNodeId;
     secondItem.targetNodeId.nodeId = item->sourceNodeId;
     secondItem.sourceNodeId = item->targetNodeId.nodeId;
     secondItem.sourceNodeId = item->targetNodeId.nodeId;
     secondItem.isForward = !item->isForward;
     secondItem.isForward = !item->isForward;
+#ifdef UA_EXTERNAL_NAMESPACES
     if(ensSecond) {
     if(ensSecond) {
         // todo: use external nodestore
         // todo: use external nodestore
     } else
     } else
+#endif
         retval = addOneWayReferenceWithSession (server, session, &secondItem);
         retval = addOneWayReferenceWithSession (server, session, &secondItem);
-    // todo: remove reference if the second direction failed
 
 
+    // todo: remove reference if the second direction failed
     return retval;
     return retval;
 } 
 } 
 
 
 /* userland version of addNodeWithSession */
 /* userland version of addNodeWithSession */
 UA_AddNodesResult
 UA_AddNodesResult
-UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId *parentNodeId,
-                  const UA_NodeId *referenceTypeId)
+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);
     return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
 }
 }
 
 
 UA_AddNodesResult
 UA_AddNodesResult
 UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
 UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
-                             const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId)
+                             const UA_ExpandedNodeId parentNodeId, const UA_NodeId referenceTypeId)
 {
 {
     UA_AddNodesResult result;
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
     UA_AddNodesResult_init(&result);
@@ -234,14 +265,14 @@ UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *no
         return result;
         return result;
     }
     }
 
 
-    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId);
+    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId.nodeId);
     if(!parent) {
     if(!parent) {
         result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
         result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
         return result;
         return result;
     }
     }
 
 
     const UA_ReferenceTypeNode *referenceType =
     const UA_ReferenceTypeNode *referenceType =
-        (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
+        (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, &referenceTypeId);
     if(!referenceType) {
     if(!referenceType) {
         result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         goto ret;
         goto ret;

+ 51 - 28
src/server/ua_server_binary.c

@@ -22,6 +22,10 @@ static void processHEL(UA_Connection *connection, const UA_ByteString *msg, size
     connection->remoteConf.maxMessageSize = helloMessage.maxMessageSize;
     connection->remoteConf.maxMessageSize = helloMessage.maxMessageSize;
     connection->remoteConf.protocolVersion = helloMessage.protocolVersion;
     connection->remoteConf.protocolVersion = helloMessage.protocolVersion;
     connection->remoteConf.recvBufferSize = helloMessage.receiveBufferSize;
     connection->remoteConf.recvBufferSize = helloMessage.receiveBufferSize;
+    if(connection->localConf.sendBufferSize > helloMessage.receiveBufferSize)
+        connection->localConf.sendBufferSize = helloMessage.receiveBufferSize;
+    if(connection->localConf.recvBufferSize > helloMessage.sendBufferSize)
+        connection->localConf.recvBufferSize = helloMessage.sendBufferSize;
     connection->remoteConf.sendBufferSize = helloMessage.sendBufferSize;
     connection->remoteConf.sendBufferSize = helloMessage.sendBufferSize;
     connection->state = UA_CONNECTION_ESTABLISHED;
     connection->state = UA_CONNECTION_ESTABLISHED;
     UA_TcpHelloMessage_deleteMembers(&helloMessage);
     UA_TcpHelloMessage_deleteMembers(&helloMessage);
@@ -103,16 +107,21 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
 
 
     UA_ByteString resp_msg;
     UA_ByteString resp_msg;
     retval = connection->getBuffer(connection, &resp_msg, respHeader.messageHeader.messageSize);
     retval = connection->getBuffer(connection, &resp_msg, respHeader.messageHeader.messageSize);
-
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_OpenSecureChannelResponse_deleteMembers(&p);
+        UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
+        return;
+    }
+        
     size_t tmpPos = 0;
     size_t tmpPos = 0;
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
     UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
     UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
     UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
     UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back
     UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos); // just mirror back
     UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
     UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
     UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
     UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
-
     UA_OpenSecureChannelResponse_deleteMembers(&p);
     UA_OpenSecureChannelResponse_deleteMembers(&p);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
+
     connection->write(connection, &resp_msg);
     connection->write(connection, &resp_msg);
     connection->releaseBuffer(connection, &resp_msg);
     connection->releaseBuffer(connection, &resp_msg);
 }
 }
@@ -123,35 +132,49 @@ static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r
     r->timestamp = UA_DateTime_now();
     r->timestamp = UA_DateTime_now();
 }
 }
 
 
+/* The request/response are casted to the header (first element of their struct) */
+static void invoke_service(UA_Server *server, UA_SecureChannel *channel,
+                           UA_RequestHeader *request, UA_ResponseHeader *response,
+                           void (*service)(UA_Server*, UA_Session*, void*, void*)) {
+    init_response_header(request, response);
+    /* try to get the session from the securechannel first */
+    UA_Session *session = UA_SecureChannel_getSession(channel, &request->authenticationToken);
+    if(!session)
+        session = UA_SessionManager_getSession(&server->sessionManager, &request->authenticationToken);
+    if(!session)
+        response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
+    else if(session->activated == UA_FALSE) {
+        response->serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED;
+        /* the session is invalidated */
+        UA_SessionManager_removeSession(&server->sessionManager, &request->authenticationToken);
+    }
+    else if(session->channel != channel)
+        response->serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
+    else {
+            UA_Session_updateLifetime(session);
+            service(server, session, request, response);
+    }
+}
+
 #define INVOKE_SERVICE(TYPE) do {                                       \
 #define INVOKE_SERVICE(TYPE) do {                                       \
         UA_##TYPE##Request p;                                           \
         UA_##TYPE##Request p;                                           \
         UA_##TYPE##Response r;                                          \
         UA_##TYPE##Response r;                                          \
         if(UA_##TYPE##Request_decodeBinary(msg, pos, &p))               \
         if(UA_##TYPE##Request_decodeBinary(msg, pos, &p))               \
             return;                                                     \
             return;                                                     \
         UA_##TYPE##Response_init(&r);                                   \
         UA_##TYPE##Response_init(&r);                                   \
-        init_response_header(&p.requestHeader, &r.responseHeader);      \
-        if(!clientChannel->session || !UA_NodeId_equal(&clientChannel->session->authenticationToken,\
-                &p.requestHeader.authenticationToken))                  \
-            r.responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;     \
-        else if(clientChannel->session->channel != clientChannel){      \
-            r.responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID; \
-        }                                                               \
-        else if(clientChannel->session->activated == UA_FALSE){         \
-            UA_SessionManager_removeSession(&server->sessionManager, &clientChannel->session->sessionId); \
-            r.responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED; \
-        }else{                                                          \
-            clientSession = clientChannel->session;                     \
-            Service_##TYPE(server, clientSession, &p, &r);              \
-        }                                                               \
+        invoke_service(server, clientChannel, &p.requestHeader,         \
+                       &r.responseHeader,                               \
+                       (void (*)(UA_Server*, UA_Session*, void*,void*))Service_##TYPE); \
         UA_##TYPE##Request_deleteMembers(&p);                           \
         UA_##TYPE##Request_deleteMembers(&p);                           \
-        retval = connection->getBuffer(connection, &message, headerSize + UA_##TYPE##Response_calcSizeBinary(&r)); \
+        retval = connection->getBuffer(connection, &message,            \
+                     headerSize + UA_##TYPE##Response_calcSizeBinary(&r)); \
         if(retval != UA_STATUSCODE_GOOD) {                              \
         if(retval != UA_STATUSCODE_GOOD) {                              \
             UA_##TYPE##Response_deleteMembers(&r);                      \
             UA_##TYPE##Response_deleteMembers(&r);                      \
             return;                                                     \
             return;                                                     \
         }                                                               \
         }                                                               \
         UA_##TYPE##Response_encodeBinary(&r, &message, &messagePos);    \
         UA_##TYPE##Response_encodeBinary(&r, &message, &messagePos);    \
         UA_##TYPE##Response_deleteMembers(&r);                          \
         UA_##TYPE##Response_deleteMembers(&r);                          \
-    } while(0)
+} while(0)
 
 
 static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
 static void processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *msg, size_t *pos) {
     // 1) Read in the securechannel
     // 1) Read in the securechannel
@@ -165,6 +188,7 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     UA_SecureChannel anonymousChannel;
     UA_SecureChannel anonymousChannel;
     if(!clientChannel) {
     if(!clientChannel) {
         UA_SecureChannel_init(&anonymousChannel);
         UA_SecureChannel_init(&anonymousChannel);
+        anonymousChannel.session = &anonymousSession;
         clientChannel = &anonymousChannel;
         clientChannel = &anonymousChannel;
     }
     }
 #endif
 #endif
@@ -182,12 +206,6 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     clientChannel->sequenceNumber = sequenceHeader.sequenceNumber;
     clientChannel->sequenceNumber = sequenceHeader.sequenceNumber;
     clientChannel->requestId = sequenceHeader.requestId;
     clientChannel->requestId = sequenceHeader.requestId;
 
 
-    UA_Session *clientSession = UA_NULL;
-#ifdef EXTENSION_STATELESS
-    if(clientChannel == &anonymousChannel)
-        clientSession = &anonymousSession;
-#endif
-
     // 3) Build the header and compute the header size
     // 3) Build the header and compute the header size
     UA_SecureConversationMessageHeader respHeader;
     UA_SecureConversationMessageHeader respHeader;
     respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
     respHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
@@ -343,8 +361,13 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
 #endif
 #endif
 
 
     default: {
     default: {
-        UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
-                    requestType.namespaceIndex, requestType.identifier.numeric);
+        if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787){
+            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION,
+                        "Client requested a subscription that are not supported, the message will be skipped");
+        }else{
+            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION, "Unknown request: NodeId(ns=%d, i=%d)",
+                        requestType.namespaceIndex, requestType.identifier.numeric);
+        }
         UA_RequestHeader  p;
         UA_RequestHeader  p;
         UA_ResponseHeader r;
         UA_ResponseHeader r;
         if(UA_RequestHeader_decodeBinary(msg, pos, &p) != UA_STATUSCODE_GOOD)
         if(UA_RequestHeader_decodeBinary(msg, pos, &p) != UA_STATUSCODE_GOOD)
@@ -399,7 +422,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
     UA_TcpMessageHeader tcpMessageHeader;
     UA_TcpMessageHeader tcpMessageHeader;
     do {
     do {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader) != UA_STATUSCODE_GOOD) {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader) != UA_STATUSCODE_GOOD) {
-            UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION, "Decoding of message header failed");
+            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION, "Decoding of message header failed");
             connection->close(connection);
             connection->close(connection);
             break;
             break;
         }
         }
@@ -432,7 +455,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
 
 
         UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
         UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
         if(pos != targetpos) {
         if(pos != targetpos) {
-            UA_LOG_INFO(server->logger, UA_LOGGERCATEGORY_COMMUNICATION,
+            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION,
                         "The message was not entirely processed, skipping to the end");
                         "The message was not entirely processed, skipping to the end");
             pos = targetpos;
             pos = targetpos;
         }
         }

+ 6 - 5
src/server/ua_server_internal.h

@@ -49,7 +49,7 @@ struct UA_Server {
     UA_ByteString serverCertificate;
     UA_ByteString serverCertificate;
     UA_SecureChannelManager secureChannelManager;
     UA_SecureChannelManager secureChannelManager;
     UA_SessionManager sessionManager;
     UA_SessionManager sessionManager;
-    
+
     /* Address Space */
     /* Address Space */
     UA_NodeStore *nodestore;
     UA_NodeStore *nodestore;
     size_t namespacesSize;
     size_t namespacesSize;
@@ -64,6 +64,7 @@ struct UA_Server {
     UA_Boolean *running;
     UA_Boolean *running;
     UA_UInt16 nThreads;
     UA_UInt16 nThreads;
     UA_UInt32 **workerCounters;
     UA_UInt32 **workerCounters;
+    pthread_t *thr;
     struct DelayedWork *delayedWork;
     struct DelayedWork *delayedWork;
 
 
     // worker threads wait on the queue
     // worker threads wait on the queue
@@ -76,11 +77,11 @@ struct UA_Server {
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg);
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg);
 
 
 UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
 UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
-                                               const UA_ExpandedNodeId *parentNodeId,
-                                               const UA_NodeId *referenceTypeId);
+                                               const UA_ExpandedNodeId parentNodeId,
+                                               const UA_NodeId referenceTypeId);
 
 
-UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId *parentNodeId,
-                                    const UA_NodeId *referenceTypeId);
+UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
+                                    const UA_NodeId referenceTypeId);
 
 
 UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item);
 UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item);
 
 

+ 137 - 91
src/server/ua_server_worker.c

@@ -12,11 +12,11 @@
  *    all previous work has actually finished (only for multithreading)
  *    all previous work has actually finished (only for multithreading)
  */
  */
 
 
-#define MAXTIMEOUT 50000 // max timeout in usec until the next main loop iteration
+#define MAXTIMEOUT 50000 // max timeout in microsec until the next main loop iteration
 #define BATCHSIZE 20 // max size of worklists that are dispatched to workers
 #define BATCHSIZE 20 // max size of worklists that are dispatched to workers
 
 
-static void processWork(UA_Server *server, UA_WorkItem *work, UA_Int32 workSize) {
-    for(UA_Int32 i = 0; i < workSize; i++) {
+static void processWork(UA_Server *server, UA_WorkItem *work, size_t workSize) {
+    for(size_t i = 0; i < workSize; i++) {
         UA_WorkItem *item = &work[i];
         UA_WorkItem *item = &work[i];
         switch(item->type) {
         switch(item->type) {
         case UA_WORKITEMTYPE_BINARYMESSAGE:
         case UA_WORKITEMTYPE_BINARYMESSAGE:
@@ -135,71 +135,98 @@ static void emptyDispatchQueue(UA_Server *server) {
 /* Timed Work */
 /* Timed Work */
 /**************/
 /**************/
 
 
+/**
+ * The TimedWork structure contains an array of workitems that are either executed at the same time
+ * or in the same repetition inverval. The linked list is sorted, so we can stop traversing when the
+ * first element has nextTime > now.
+ */
 struct TimedWork {
 struct TimedWork {
     LIST_ENTRY(TimedWork) pointers;
     LIST_ENTRY(TimedWork) pointers;
     UA_DateTime nextTime;
     UA_DateTime nextTime;
-    UA_UInt32 interval; ///> in ms resolution, 0 means no repetition
+    UA_UInt32 interval; ///> in 100ns resolution, 0 means no repetition
     size_t workSize;
     size_t workSize;
-    struct {
-        UA_WorkItem work;
-        UA_Guid workId;
-    } work[];
+    UA_WorkItem *work;
+    UA_Guid workIds[];
 };
 };
 
 
-/* The item is copied and not freed by this function. */
+/* Traverse the list until there is a TimedWork to which the item can be added or we reached the
+   end. The item is copied into the TimedWork and not freed by this function. The interval is in
+   100ns resolution */
 static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA_DateTime firstTime,
 static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA_DateTime firstTime,
-                                  UA_UInt32 repetitionInterval, UA_Guid *resultWorkGuid) {
-    struct TimedWork *lastTw = UA_NULL, *matchingTw = UA_NULL;
+                                  UA_UInt32 interval, UA_Guid *resultWorkGuid) {
+    struct TimedWork *matchingTw = UA_NULL; // add the item here
+    struct TimedWork *lastTw = UA_NULL; // if there is no matchingTw, add a new TimedWork after this entry
+    struct TimedWork *tempTw;
 
 
     /* search for matching entry */
     /* search for matching entry */
-    if(repetitionInterval == 0) {
-        LIST_FOREACH(lastTw, &server->timedWork, pointers) {
-            if(lastTw->nextTime == firstTime) {
-                if(lastTw->nextTime == firstTime)
-                    matchingTw = lastTw;
+    tempTw = LIST_FIRST(&server->timedWork);
+    if(interval == 0) {
+        /* single execution. the time needs to match */
+        while(tempTw) {
+            if(tempTw->nextTime >= firstTime) {
+                if(tempTw->nextTime == firstTime)
+                    matchingTw = tempTw;
                 break;
                 break;
             }
             }
+            lastTw = tempTw;
+            tempTw = LIST_NEXT(lastTw, pointers);
         }
         }
     } else {
     } else {
-        LIST_FOREACH(matchingTw, &server->timedWork, pointers) {
-            if(repetitionInterval == matchingTw->interval)
+        /* repeated execution. the interval needs to match */
+        while(tempTw) {
+            if(interval == tempTw->interval) {
+                matchingTw = tempTw;
                 break;
                 break;
+            }
+            if(tempTw->nextTime > firstTime)
+                break;
+            lastTw = tempTw;
+            tempTw = LIST_NEXT(lastTw, pointers);
         }
         }
     }
     }
     
     
-    struct TimedWork *newWork;
     if(matchingTw) {
     if(matchingTw) {
         /* append to matching entry */
         /* append to matching entry */
-        newWork = UA_realloc(matchingTw, sizeof(struct TimedWork) + (sizeof(UA_WorkItem)*matchingTw->workSize + 1));
-        if(!newWork)
+        matchingTw = UA_realloc(matchingTw, sizeof(struct TimedWork) + sizeof(UA_Guid)*(matchingTw->workSize + 1));
+        if(!matchingTw)
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        if(matchingTw->pointers.le_next)
+            matchingTw->pointers.le_next->pointers.le_prev = &matchingTw->pointers.le_next;
+        if(matchingTw->pointers.le_prev)
+            *matchingTw->pointers.le_prev = matchingTw;
+        UA_WorkItem *newItems = UA_realloc(matchingTw->work, sizeof(UA_WorkItem)*(matchingTw->workSize + 1));
+        if(!newItems)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
-        if(newWork->pointers.le_next)
-            newWork->pointers.le_next->pointers.le_prev = &newWork->pointers.le_next;
-        if(newWork->pointers.le_prev)
-            *newWork->pointers.le_prev = newWork;
+        matchingTw->work = newItems;
     } else {
     } else {
         /* create a new entry */
         /* create a new entry */
-        newWork = UA_malloc(sizeof(struct TimedWork) + sizeof(UA_WorkItem));
-        if(!newWork)
+        matchingTw = UA_malloc(sizeof(struct TimedWork) + sizeof(UA_Guid));
+        if(!matchingTw)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
-        newWork->workSize = 0;
-        newWork->nextTime = firstTime;
-        newWork->interval = repetitionInterval;
+        matchingTw->work = UA_malloc(sizeof(UA_WorkItem));
+        if(!matchingTw->work) {
+            UA_free(matchingTw);
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        }
+        matchingTw->workSize = 0;
+        matchingTw->nextTime = firstTime;
+        matchingTw->interval = interval;
         if(lastTw)
         if(lastTw)
-            LIST_INSERT_AFTER(lastTw, newWork, pointers);
+            LIST_INSERT_AFTER(lastTw, matchingTw, pointers);
         else
         else
-            LIST_INSERT_HEAD(&server->timedWork, newWork, pointers);
+            LIST_INSERT_HEAD(&server->timedWork, matchingTw, pointers);
     }
     }
-    newWork->work[newWork->workSize].work = *item;
+    matchingTw->work[matchingTw->workSize] = *item;
+    matchingTw->workSize++;
+
+    /* create a guid for finding and deleting the timed work later on */
     if(resultWorkGuid) {
     if(resultWorkGuid) {
-        newWork->work[newWork->workSize].workId = UA_Guid_random(&server->random_seed);
-        *resultWorkGuid = newWork->work[matchingTw->workSize - 1].workId;
+        matchingTw->workIds[matchingTw->workSize] = UA_Guid_random(&server->random_seed);
+        *resultWorkGuid = matchingTw->workIds[matchingTw->workSize];
     }
     }
-    newWork->workSize++;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-// Currently, these functions need to get the server mutex, but should be sufficiently fast
 UA_StatusCode UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_DateTime executionTime,
 UA_StatusCode UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_DateTime executionTime,
                                          UA_Guid *resultWorkGuid) {
                                          UA_Guid *resultWorkGuid) {
     return addTimedWork(server, work, executionTime, 0, resultWorkGuid);
     return addTimedWork(server, work, executionTime, 0, resultWorkGuid);
@@ -207,7 +234,7 @@ UA_StatusCode UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *w
 
 
 UA_StatusCode UA_Server_addRepeatedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_UInt32 interval,
 UA_StatusCode UA_Server_addRepeatedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_UInt32 interval,
                                             UA_Guid *resultWorkGuid) {
                                             UA_Guid *resultWorkGuid) {
-    return addTimedWork(server, work, UA_DateTime_now() + interval * 1000, interval * 1000, resultWorkGuid);
+    return addTimedWork(server, work, UA_DateTime_now() + interval * 10000, interval * 10000, resultWorkGuid);
 }
 }
 
 
 /** Dispatches timed work, returns the timeout until the next timed work in ms */
 /** Dispatches timed work, returns the timeout until the next timed work in ms */
@@ -223,17 +250,16 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
         next = LIST_NEXT(tw, pointers);
         next = LIST_NEXT(tw, pointers);
 
 
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-        if(tw->repetitionInterval > 0) {
+        if(tw->interval > 0) {
             // copy the entry and insert at the new location
             // copy the entry and insert at the new location
             UA_WorkItem *workCopy = (UA_WorkItem *) UA_malloc(sizeof(UA_WorkItem) * tw->workSize);
             UA_WorkItem *workCopy = (UA_WorkItem *) UA_malloc(sizeof(UA_WorkItem) * tw->workSize);
             UA_memcpy(workCopy, tw->work, sizeof(UA_WorkItem) * tw->workSize);
             UA_memcpy(workCopy, tw->work, sizeof(UA_WorkItem) * tw->workSize);
             dispatchWork(server, tw->workSize, workCopy); // frees the work pointer
             dispatchWork(server, tw->workSize, workCopy); // frees the work pointer
-            tw->time += tw->repetitionInterval;
-
+            tw->nextTime += tw->interval;
             struct TimedWork *prevTw = tw; // after which tw do we insert?
             struct TimedWork *prevTw = tw; // after which tw do we insert?
             while(UA_TRUE) {
             while(UA_TRUE) {
                 struct TimedWork *n = LIST_NEXT(prevTw, pointers);
                 struct TimedWork *n = LIST_NEXT(prevTw, pointers);
-                if(!n || n->time > tw->time)
+                if(!n || n->nextTime > tw->nextTime)
                     break;
                     break;
                 prevTw = n;
                 prevTw = n;
             }
             }
@@ -244,16 +270,17 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
         } else {
         } else {
             dispatchWork(server, tw->workSize, tw->work); // frees the work pointer
             dispatchWork(server, tw->workSize, tw->work); // frees the work pointer
             LIST_REMOVE(tw, pointers);
             LIST_REMOVE(tw, pointers);
-            UA_free(tw->workIds);
             UA_free(tw);
             UA_free(tw);
         }
         }
 #else
 #else
         // 1) Process the work since it is past its due date
         // 1) Process the work since it is past its due date
-        processWork(server, (UA_WorkItem *) tw->work, tw->workSize); // does not free the work
+        processWork(server, tw->work, tw->workSize); // does not free the work ptr
 
 
         // 2) If the work is repeated, add it back into the list. Otherwise remove it.
         // 2) If the work is repeated, add it back into the list. Otherwise remove it.
         if(tw->interval > 0) {
         if(tw->interval > 0) {
-            tw->nextTime += tw->interval * 10;
+            tw->nextTime += tw->interval;
+            if(tw->nextTime < current)
+                tw->nextTime = current;
             struct TimedWork *prevTw = tw;
             struct TimedWork *prevTw = tw;
             while(UA_TRUE) {
             while(UA_TRUE) {
                 struct TimedWork *n = LIST_NEXT(prevTw, pointers);
                 struct TimedWork *n = LIST_NEXT(prevTw, pointers);
@@ -267,6 +294,7 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
             }
             }
         } else {
         } else {
             LIST_REMOVE(tw, pointers);
             LIST_REMOVE(tw, pointers);
+            UA_free(tw->work);
             UA_free(tw);
             UA_free(tw);
         }
         }
 #endif
 #endif
@@ -276,7 +304,7 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
     struct TimedWork *first = LIST_FIRST(&server->timedWork);
     struct TimedWork *first = LIST_FIRST(&server->timedWork);
     UA_UInt16 timeout = MAXTIMEOUT;
     UA_UInt16 timeout = MAXTIMEOUT;
     if(first) {
     if(first) {
-        timeout = (first->nextTime - current)/10000;
+        timeout = (first->nextTime - current)/10;
         if(timeout > MAXTIMEOUT)
         if(timeout > MAXTIMEOUT)
             return MAXTIMEOUT;
             return MAXTIMEOUT;
     }
     }
@@ -290,6 +318,7 @@ void UA_Server_deleteTimedWork(UA_Server *server) {
         current = next;
         current = next;
         next = LIST_NEXT(current, pointers);
         next = LIST_NEXT(current, pointers);
         LIST_REMOVE(current, pointers);
         LIST_REMOVE(current, pointers);
+        UA_free(current->work);
         UA_free(current);
         UA_free(current);
     }
     }
 }
 }
@@ -310,7 +339,7 @@ struct DelayedWork {
 };
 };
 
 
 // Dispatched as a methodcall-WorkItem when the delayedwork is added
 // Dispatched as a methodcall-WorkItem when the delayedwork is added
-static void getCounters(UA_Server *server, DelayedWork *delayed) {
+static void getCounters(UA_Server *server, struct DelayedWork *delayed) {
     UA_UInt32 *counters = UA_malloc(server->nThreads * sizeof(UA_UInt32));
     UA_UInt32 *counters = UA_malloc(server->nThreads * sizeof(UA_UInt32));
     for(UA_UInt16 i = 0;i<server->nThreads;i++)
     for(UA_UInt16 i = 0;i<server->nThreads;i++)
         counters[i] = *server->workerCounters[i];
         counters[i] = *server->workerCounters[i];
@@ -323,7 +352,7 @@ static void getCounters(UA_Server *server, DelayedWork *delayed) {
 static void addDelayedWork(UA_Server *server, UA_WorkItem work) {
 static void addDelayedWork(UA_Server *server, UA_WorkItem work) {
     struct DelayedWork *dw = server->delayedWork;
     struct DelayedWork *dw = server->delayedWork;
     if(!dw || dw->workItemsCount >= DELAYEDWORKSIZE) {
     if(!dw || dw->workItemsCount >= DELAYEDWORKSIZE) {
-        struct DelayedWork *newwork = UA_malloc(sizeof(DelayedWork));
+        struct DelayedWork *newwork = UA_malloc(sizeof(struct DelayedWork));
         newwork->workItems = UA_malloc(sizeof(UA_WorkItem)*DELAYEDWORKSIZE);
         newwork->workItems = UA_malloc(sizeof(UA_WorkItem)*DELAYEDWORKSIZE);
         newwork->workItemsCount = 0;
         newwork->workItemsCount = 0;
         newwork->workerCounters = UA_NULL;
         newwork->workerCounters = UA_NULL;
@@ -407,24 +436,24 @@ static void dispatchDelayedWork(UA_Server *server, void *data /* not used, but n
 /* Main Server Loop */
 /* Main Server Loop */
 /********************/
 /********************/
 
 
-UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
+UA_StatusCode UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running){
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     // 1) Prepare the threads
     // 1) Prepare the threads
     server->running = running; // the threads need to access the variable
     server->running = running; // the threads need to access the variable
     server->nThreads = nThreads;
     server->nThreads = nThreads;
     pthread_cond_init(&server->dispatchQueue_condition, 0);
     pthread_cond_init(&server->dispatchQueue_condition, 0);
-    pthread_t *thr = UA_malloc(nThreads * sizeof(pthread_t));
+    server->thr = UA_malloc(nThreads * sizeof(pthread_t));
     server->workerCounters = UA_malloc(nThreads * sizeof(UA_UInt32 *));
     server->workerCounters = UA_malloc(nThreads * sizeof(UA_UInt32 *));
     for(UA_UInt32 i=0;i<nThreads;i++) {
     for(UA_UInt32 i=0;i<nThreads;i++) {
         struct workerStartData *startData = UA_malloc(sizeof(struct workerStartData));
         struct workerStartData *startData = UA_malloc(sizeof(struct workerStartData));
         startData->server = server;
         startData->server = server;
         startData->workerCounter = &server->workerCounters[i];
         startData->workerCounter = &server->workerCounters[i];
-        pthread_create(&thr[i], UA_NULL, (void* (*)(void*))workerLoop, startData);
+        pthread_create(&server->thr[i], UA_NULL, (void* (*)(void*))workerLoop, startData);
     }
     }
 
 
     UA_WorkItem processDelayed = {.type = UA_WORKITEMTYPE_METHODCALL,
     UA_WorkItem processDelayed = {.type = UA_WORKITEMTYPE_METHODCALL,
-                                  .work.methodCall = {.method = dispatchDelayedWork,
-                                                      .data = UA_NULL} };
+            .work.methodCall = {.method = dispatchDelayedWork,
+                    .data = UA_NULL} };
     UA_Server_addRepeatedWorkItem(server, &processDelayed, 10000000, UA_NULL);
     UA_Server_addRepeatedWorkItem(server, &processDelayed, 10000000, UA_NULL);
 #endif
 #endif
 
 
@@ -432,60 +461,77 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
     for(size_t i = 0; i <server->networkLayersSize; i++)
     for(size_t i = 0; i <server->networkLayersSize; i++)
         server->networkLayers[i].start(server->networkLayers[i].nlHandle, &server->logger);
         server->networkLayers[i].start(server->networkLayers[i].nlHandle, &server->logger);
 
 
-    //3) The loop
-    while(1) {
-        // 3.1) Process timed work
-        UA_UInt16 timeout = processTimedWork(server);
-
-        // 3.2) Get work from the networklayer and dispatch it
-        for(size_t i = 0; i < server->networkLayersSize; i++) {
-            UA_ServerNetworkLayer *nl = &server->networkLayers[i];
-            UA_WorkItem *work;
-            UA_Int32 workSize;
-            if(*running) {
-            	if(i == server->networkLayersSize-1)
-            		workSize = nl->getWork(nl->nlHandle, &work, timeout);
-            	else
-            		workSize = nl->getWork(nl->nlHandle, &work, 0);
-            } else {
-                workSize = server->networkLayers[i].stop(nl->nlHandle, &work);
-            }
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode UA_Server_run_getAndProcessWork(UA_Server *server, UA_Boolean *running){
+    // 3.1) Process timed work
+    UA_UInt16 timeout = processTimedWork(server);
+
+    // 3.2) Get work from the networklayer and dispatch it
+    for(size_t i = 0; i < server->networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->networkLayers[i];
+        UA_WorkItem *work;
+        UA_Int32 workSize;
+        if(*running) {
+            if(i == server->networkLayersSize-1)
+                workSize = nl->getWork(nl->nlHandle, &work, timeout);
+            else
+                workSize = nl->getWork(nl->nlHandle, &work, 0);
+        } else {
+            workSize = server->networkLayers[i].stop(nl->nlHandle, &work);
+        }
 
 
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-            // Filter out delayed work
-            for(UA_Int32 k=0;k<workSize;k++) {
-                if(work[k].type != UA_WORKITEMTYPE_DELAYEDMETHODCALL)
-                    continue;
-                addDelayedWork(server, work[k]);
-                work[k].type = UA_WORKITEMTYPE_NOTHING;
-            }
-            dispatchWork(server, workSize, work);
-            if(workSize > 0)
-                pthread_cond_broadcast(&server->dispatchQueue_condition); 
+// Filter out delayed work
+for(UA_Int32 k=0;k<workSize;k++) {
+    if(work[k].type != UA_WORKITEMTYPE_DELAYEDMETHODCALL)
+        continue;
+    addDelayedWork(server, work[k]);
+    work[k].type = UA_WORKITEMTYPE_NOTHING;
+}
+dispatchWork(server, workSize, work);
+if(workSize > 0)
+    pthread_cond_broadcast(&server->dispatchQueue_condition);
 #else
 #else
-            processWork(server, work, workSize);
-            if(workSize > 0)
-                UA_free(work);
+processWork(server, work, workSize);
+if(workSize > 0)
+    UA_free(work);
 #endif
 #endif
-        }
-
-        // 3.3) Exit?
-        if(!*running)
-            break;
     }
     }
+    return UA_STATUSCODE_GOOD;
+}
 
 
+UA_StatusCode UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads){
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     // 4) Clean up: Wait until all worker threads finish, then empty the
     // 4) Clean up: Wait until all worker threads finish, then empty the
     // dispatch queue, then process the remaining delayed work
     // dispatch queue, then process the remaining delayed work
     for(UA_UInt32 i=0;i<nThreads;i++) {
     for(UA_UInt32 i=0;i<nThreads;i++) {
-        pthread_join(thr[i], UA_NULL);
+        pthread_join(server->thr[i], UA_NULL);
         UA_free(server->workerCounters[i]);
         UA_free(server->workerCounters[i]);
     }
     }
     UA_free(server->workerCounters);
     UA_free(server->workerCounters);
-    UA_free(thr);
+    UA_free(server->thr);
     emptyDispatchQueue(server);
     emptyDispatchQueue(server);
     processDelayedWork(server);
     processDelayedWork(server);
 #endif
 #endif
 
 
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
+
+UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
+    UA_Server_run_startup(server, nThreads, running);
+
+    // 3) The loop
+    while(1) {
+        UA_Server_run_getAndProcessWork(server, running);
+
+        // 3.3) Exit?
+        if(!*running)
+            break;
+    }
+
+    UA_Server_run_shutdown(server, nThreads);
+
+    return UA_STATUSCODE_GOOD;
+}

+ 44 - 36
src/server/ua_services_attribute.c

@@ -5,9 +5,7 @@
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 #include "ua_util.h"
 #include "ua_util.h"
 
 
-static UA_StatusCode
-parse_numericrange(const UA_String str, UA_NumericRange *range)
-{
+static UA_StatusCode parse_numericrange(const UA_String str, UA_NumericRange *range) {
     if(str.length < 0 || str.length >= 1023)
     if(str.length < 0 || str.length >= 1023)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     char *cstring = UA_alloca(str.length+1);
     char *cstring = UA_alloca(str.length+1);
@@ -15,7 +13,7 @@ parse_numericrange(const UA_String str, UA_NumericRange *range)
     cstring[str.length] = 0;
     cstring[str.length] = 0;
     UA_Int32 index = 0;
     UA_Int32 index = 0;
     size_t dimensionsIndex = 0;
     size_t dimensionsIndex = 0;
-    size_t dimensionsMax = 3; // more should be uncommon
+    size_t dimensionsMax = 3; // more should be uncommon, realloc if necessary
     struct UA_NumericRangeDimension *dimensions = UA_malloc(sizeof(struct UA_NumericRangeDimension) * 3);
     struct UA_NumericRangeDimension *dimensions = UA_malloc(sizeof(struct UA_NumericRangeDimension) * 3);
     if(!dimensions)
     if(!dimensions)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -92,10 +90,11 @@ static void handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValu
 /** Reads a single attribute from a node in the nodestore. */
 /** Reads a single attribute from a node in the nodestore. */
 static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
 static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
                       const UA_ReadValueId *id, UA_DataValue *v) {
                       const UA_ReadValueId *id, UA_DataValue *v) {
-
+    UA_String binEncoding = UA_STRING("DefaultBinary");
+    UA_String xmlEncoding = UA_STRING("DefaultXml");
 	if(id->dataEncoding.name.length >= 0){
 	if(id->dataEncoding.name.length >= 0){
-		if(memcmp(id->dataEncoding.name.data, "DefaultBinary", 13) != 0 &&
-           memcmp(id->dataEncoding.name.data, "DefaultXml", 10) != 0) {
+		if(!UA_String_equal(&binEncoding, &id->dataEncoding.name) &&
+           !UA_String_equal(&xmlEncoding, &id->dataEncoding.name)) {
 			v->hasStatus = UA_TRUE;
 			v->hasStatus = UA_TRUE;
 			v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
 			v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
 			return;
 			return;
@@ -216,11 +215,14 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
                 UA_DataValue_init(&val);
                 UA_DataValue_init(&val);
                 UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
                 UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
                                               timestamps == UA_TIMESTAMPSTORETURN_BOTH);
                                               timestamps == UA_TIMESTAMPSTORETURN_BOTH);
-                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, sourceTimeStamp, &val);
+                if(hasRange)
+                    retval |= vn->value.dataSource.read(vn->value.dataSource.handle, sourceTimeStamp, &range, &val);
+                else
+                    retval |= vn->value.dataSource.read(vn->value.dataSource.handle, sourceTimeStamp, UA_NULL, &val);
                 if(retval == UA_STATUSCODE_GOOD) {
                 if(retval == UA_STATUSCODE_GOOD) {
-                    retval |= UA_DataValue_copy(&val, v); // todo: selection of indexranges
+                    retval |= UA_DataValue_copy(&val, v); // todo: still too much copying necessary!!
+                    vn->value.dataSource.release(vn->value.dataSource.handle, &val);
                 }
                 }
-                vn->value.dataSource.release(vn->value.dataSource.handle, &val);
             }
             }
 
 
             if(hasRange)
             if(hasRange)
@@ -237,7 +239,7 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
         else {
         else {
             UA_DataValue val;
             UA_DataValue val;
             UA_DataValue_init(&val);
             UA_DataValue_init(&val);
-            retval = vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, &val);
+            retval = vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, UA_NULL, &val);
             if(retval != UA_STATUSCODE_GOOD)
             if(retval != UA_STATUSCODE_GOOD)
                 break;
                 break;
             retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
             retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
@@ -268,7 +270,7 @@ static void readValue(UA_Server *server, UA_TimestampsToReturn timestamps,
             } else {
             } else {
                 UA_DataValue val;
                 UA_DataValue val;
                 UA_DataValue_init(&val);
                 UA_DataValue_init(&val);
-                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, &val);
+                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, UA_NULL, &val);
                 if(retval != UA_STATUSCODE_GOOD)
                 if(retval != UA_STATUSCODE_GOOD)
                     break;
                     break;
                 if(!val.hasValue)
                 if(!val.hasValue)
@@ -367,7 +369,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
         return;
         return;
     }
     }
 
 
-    /* ### Begin External Namespaces */
+#ifdef UA_EXTERNAL_NAMESPACES
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
@@ -386,10 +388,12 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
         ens->readNodes(ens->ensHandle, &request->requestHeader, request->nodesToRead,
         ens->readNodes(ens->ensHandle, &request->requestHeader, request->nodesToRead,
                        indices, indexSize, response->results, UA_FALSE, response->diagnosticInfos);
                        indices, indexSize, response->results, UA_FALSE, response->diagnosticInfos);
     }
     }
-    /* ### End External Namespaces */
+#endif
 
 
     for(size_t i = 0;i < size;i++) {
     for(size_t i = 0;i < size;i++) {
+#ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
+#endif
             readValue(server, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]);
             readValue(server, request->timestampsToReturn, &request->nodesToRead[i], &response->results[i]);
     }
     }
 
 
@@ -477,12 +481,15 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
             if(vn->valueSource == UA_VALUESOURCE_DATASOURCE) {
             if(vn->valueSource == UA_VALUESOURCE_DATASOURCE) {
                 if(!vn->value.dataSource.write) {
                 if(!vn->value.dataSource.write) {
                     retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
                     retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
-                    break;
+                    goto clean_up_range;
                 }
                 }
                 // todo: writing ranges
                 // todo: writing ranges
-                retval = vn->value.dataSource.write(vn->value.dataSource.handle, &wvalue->value.value);
+                if(hasRange)
+                    retval = vn->value.dataSource.write(vn->value.dataSource.handle, &wvalue->value.value, &range);
+                else
+                    retval = vn->value.dataSource.write(vn->value.dataSource.handle, &wvalue->value.value, UA_NULL);
                 done = UA_TRUE;
                 done = UA_TRUE;
-                break;
+                goto clean_up_range;
             }
             }
             const UA_Variant *oldV = &vn->value.variant;
             const UA_Variant *oldV = &vn->value.variant;
 
 
@@ -493,10 +500,9 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
                     /* An enum was sent as an int32, or an opaque type as a bytestring. This is
                     /* An enum was sent as an int32, or an opaque type as a bytestring. This is
                        detected with the typeIndex indicated the "true" datatype. */
                        detected with the typeIndex indicated the "true" datatype. */
                     wvalue->value.value.type = oldV->type;
                     wvalue->value.value.type = oldV->type;
-                else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] &&
-                        (!oldV->data || vn->value.variant.arrayLength > -1) /* isArray */ &&
+                else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
                         wvalue->value.value.type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
                         wvalue->value.value.type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
-                        wvalue->value.value.data && wvalue->value.value.arrayLength == -1 /* isScalar */) {
+                        UA_Variant_isScalar(&wvalue->value.value)) {
                     /* a string is written to a byte array */
                     /* a string is written to a byte array */
                     UA_ByteString *str = (UA_ByteString*) wvalue->value.value.data;
                     UA_ByteString *str = (UA_ByteString*) wvalue->value.value.data;
                     wvalue->value.value.arrayLength = str->length;
                     wvalue->value.value.arrayLength = str->length;
@@ -505,7 +511,7 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
                     UA_free(str);
                     UA_free(str);
                 } else {
                 } else {
                     retval = UA_STATUSCODE_BADTYPEMISMATCH;
                     retval = UA_STATUSCODE_BADTYPEMISMATCH;
-                    break;
+                    goto clean_up_range;
                 }
                 }
             }
             }
 
 
@@ -514,34 +520,34 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
                 UA_VariableNode_new() : (UA_VariableNode*)UA_VariableTypeNode_new();
                 UA_VariableNode_new() : (UA_VariableNode*)UA_VariableTypeNode_new();
             if(!newVn) {
             if(!newVn) {
                 retval = UA_STATUSCODE_BADOUTOFMEMORY;
                 retval = UA_STATUSCODE_BADOUTOFMEMORY;
-                break;
+                goto clean_up_range;
             }
             }
             retval = (node->nodeClass == UA_NODECLASS_VARIABLE) ? UA_VariableNode_copy(vn, newVn) : 
             retval = (node->nodeClass == UA_NODECLASS_VARIABLE) ? UA_VariableNode_copy(vn, newVn) : 
                 UA_VariableTypeNode_copy((const UA_VariableTypeNode*)vn, (UA_VariableTypeNode*)newVn);
                 UA_VariableTypeNode_copy((const UA_VariableTypeNode*)vn, (UA_VariableTypeNode*)newVn);
             if(retval != UA_STATUSCODE_GOOD)
             if(retval != UA_STATUSCODE_GOOD)
                 goto clean_up;
                 goto clean_up;
                 
                 
-            /* insert the new value*/
+            /* insert the new value */
             if(hasRange)
             if(hasRange)
-                retval = UA_Variant_setRange(&newVn->value.variant, wvalue->value.value.data, range);
+                retval = UA_Variant_setRangeCopy(&newVn->value.variant, wvalue->value.value.data,
+                                                 wvalue->value.value.arrayLength, range);
             else {
             else {
                 UA_Variant_deleteMembers(&newVn->value.variant);
                 UA_Variant_deleteMembers(&newVn->value.variant);
                 retval = UA_Variant_copy(&wvalue->value.value, &newVn->value.variant);
                 retval = UA_Variant_copy(&wvalue->value.value, &newVn->value.variant);
             }
             }
-            if(retval != UA_STATUSCODE_GOOD ||
-               UA_NodeStore_replace(server->nodestore, node, (UA_Node*)newVn,
-                                    UA_NULL) != UA_STATUSCODE_GOOD)
-                goto clean_up;
-            if(hasRange)
-                UA_free(range.dimensions);
-            done = UA_TRUE;
-            break;
+
+            if(retval == UA_STATUSCODE_GOOD && UA_NodeStore_replace(server->nodestore, node,
+                                                   (UA_Node*)newVn, UA_NULL) == UA_STATUSCODE_GOOD) {
+                done = UA_TRUE;
+                goto clean_up_range;
+            }
 
 
             clean_up:
             clean_up:
             if(node->nodeClass == UA_NODECLASS_VARIABLE)
             if(node->nodeClass == UA_NODECLASS_VARIABLE)
                 UA_VariableNode_delete(newVn);
                 UA_VariableNode_delete(newVn);
             else
             else
                 UA_VariableTypeNode_delete((UA_VariableTypeNode*)newVn);
                 UA_VariableTypeNode_delete((UA_VariableTypeNode*)newVn);
+            clean_up_range:
             if(hasRange)
             if(hasRange)
                 UA_free(range.dimensions);
                 UA_free(range.dimensions);
             }
             }
@@ -570,8 +576,8 @@ static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *wvalue) {
     return retval;
     return retval;
 }
 }
 
 
-void Service_Write(UA_Server *server, UA_Session *session,
-                   const UA_WriteRequest *request, UA_WriteResponse *response) {
+void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
+                   UA_WriteResponse *response) {
     UA_assert(server != UA_NULL && session != UA_NULL && request != UA_NULL && response != UA_NULL);
     UA_assert(server != UA_NULL && session != UA_NULL && request != UA_NULL && response != UA_NULL);
 
 
     if(request->nodesToWriteSize <= 0){
     if(request->nodesToWriteSize <= 0){
@@ -585,7 +591,7 @@ void Service_Write(UA_Server *server, UA_Session *session,
         return;
         return;
     }
     }
 
 
-    /* ### Begin External Namespaces */
+#ifdef UA_EXTERNAL_NAMESPACES
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToWriteSize);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToWriteSize);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToWriteSize);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToWriteSize);
@@ -605,11 +611,13 @@ void Service_Write(UA_Server *server, UA_Session *session,
         ens->writeNodes(ens->ensHandle, &request->requestHeader, request->nodesToWrite,
         ens->writeNodes(ens->ensHandle, &request->requestHeader, request->nodesToWrite,
                         indices, indexSize, response->results, response->diagnosticInfos);
                         indices, indexSize, response->results, response->diagnosticInfos);
     }
     }
-    /* ### End External Namespaces */
+#endif
     
     
     response->resultsSize = request->nodesToWriteSize;
     response->resultsSize = request->nodesToWriteSize;
     for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++) {
     for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++) {
+#ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
+#endif
             response->results[i] = writeValue(server, &request->nodesToWrite[i]);
             response->results[i] = writeValue(server, &request->nodesToWrite[i]);
     }
     }
 }
 }

+ 1 - 6
src/server/ua_services_discovery.c

@@ -13,8 +13,6 @@ void Service_FindServers(UA_Server *server, const UA_FindServersRequest *request
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
     }
     }
-    UA_String_deleteMembers(response->servers->discoveryUrls);
-    UA_String_copy(&request->endpointUrl, response->servers->discoveryUrls);
 	response->serversSize = 1;
 	response->serversSize = 1;
 }
 }
 
 
@@ -54,10 +52,7 @@ void Service_GetEndpoints(UA_Server *server, const UA_GetEndpointsRequest *reque
     for(UA_Int32 j = 0; j < server->endpointDescriptionsSize && retval == UA_STATUSCODE_GOOD; j++) {
     for(UA_Int32 j = 0; j < server->endpointDescriptionsSize && retval == UA_STATUSCODE_GOOD; j++) {
         if(relevant_endpoints[j] != UA_TRUE)
         if(relevant_endpoints[j] != UA_TRUE)
             continue;
             continue;
-        retval = UA_copy(&server->endpointDescriptions[j], &response->endpoints[j],
-                         &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
-        UA_String_deleteMembers(&response->endpoints[j].endpointUrl);
-        UA_String_copy(&request->endpointUrl, &response->endpoints[j].endpointUrl);
+        retval = UA_EndpointDescription_copy(&server->endpointDescriptions[j], &response->endpoints[k]);
         k++;
         k++;
     }
     }
 
 

+ 13 - 8
src/server/ua_services_nodemanagement.c

@@ -156,6 +156,7 @@ static UA_StatusCode parseObjectTypeNode(UA_ExtensionObject *attributes, UA_Node
 static UA_StatusCode parseViewNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
 static UA_StatusCode parseViewNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     UA_ViewAttributes attr;
     UA_ViewAttributes attr;
     size_t pos = 0;
     size_t pos = 0;
+
     // todo return more informative error codes from decodeBinary
     // todo return more informative error codes from decodeBinary
     if(UA_ViewAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
     if(UA_ViewAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -164,6 +165,7 @@ static UA_StatusCode parseViewNode(UA_ExtensionObject *attributes, UA_Node **new
         UA_ViewAttributes_deleteMembers(&attr);
         UA_ViewAttributes_deleteMembers(&attr);
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
     }
+
     // now copy all the attributes. This potentially removes them from the decoded attributes.
     // now copy all the attributes. This potentially removes them from the decoded attributes.
     COPY_STANDARDATTRIBUTES;
     COPY_STANDARDATTRIBUTES;
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS)
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS)
@@ -207,8 +209,8 @@ static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_Add
         return;
         return;
 
 
     // add the node
     // add the node
-    *result = UA_Server_addNodeWithSession(server, session, node, &item->parentNodeId,
-                                           &item->referenceTypeId);
+    *result = UA_Server_addNodeWithSession(server, session, node, item->parentNodeId,
+                                           item->referenceTypeId);
     if(result->statusCode != UA_STATUSCODE_GOOD) {
     if(result->statusCode != UA_STATUSCODE_GOOD) {
         switch (node->nodeClass) {
         switch (node->nodeClass) {
         case UA_NODECLASS_OBJECT:
         case UA_NODECLASS_OBJECT:
@@ -243,7 +245,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         return;
         return;
     }
     }
 
 
-    /* ### Begin External Namespaces */
+#ifdef UA_EXTERNAL_NAMESPACES
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
@@ -263,11 +265,13 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         ens->addNodes(ens->ensHandle, &request->requestHeader, request->nodesToAdd,
         ens->addNodes(ens->ensHandle, &request->requestHeader, request->nodesToAdd,
                       indices, indexSize, response->results, response->diagnosticInfos);
                       indices, indexSize, response->results, response->diagnosticInfos);
     }
     }
-    /* ### End External Namespaces */
+#endif
     
     
     response->resultsSize = size;
     response->resultsSize = size;
     for(size_t i = 0;i < size;i++) {
     for(size_t i = 0;i < size;i++) {
+#ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
+#endif
             addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
             addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
     }
     }
 }
 }
@@ -287,7 +291,7 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 	response->resultsSize = size;
 	response->resultsSize = size;
 	UA_memset(response->results, UA_STATUSCODE_GOOD, sizeof(UA_StatusCode) * size);
 	UA_memset(response->results, UA_STATUSCODE_GOOD, sizeof(UA_StatusCode) * size);
 
 
-	/* ### Begin External Namespaces */
+#ifdef UA_EXTERNAL_NAMESPACES
 	UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
 	UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
 	UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
 	UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
 	UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
 	UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
@@ -307,11 +311,13 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 		ens->addReferences(ens->ensHandle, &request->requestHeader, request->referencesToAdd,
 		ens->addReferences(ens->ensHandle, &request->requestHeader, request->referencesToAdd,
                            indices, indicesSize, response->results, response->diagnosticInfos);
                            indices, indicesSize, response->results, response->diagnosticInfos);
 	}
 	}
-	/* ### End External Namespaces */
+#endif
 
 
 	response->resultsSize = size;
 	response->resultsSize = size;
 	for(UA_Int32 i = 0; i < response->resultsSize; i++) {
 	for(UA_Int32 i = 0; i < response->resultsSize; i++) {
+#ifdef UA_EXTERNAL_NAMESPACES
 		if(!isExternal[i])
 		if(!isExternal[i])
+#endif
 			UA_Server_addReference(server, &request->referencesToAdd[i]);
 			UA_Server_addReference(server, &request->referencesToAdd[i]);
 	}
 	}
 }
 }
@@ -321,8 +327,7 @@ void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_Delete
 
 
 }
 }
 
 
-void Service_DeleteReferences(UA_Server *server, UA_Session *session,
-                              const UA_DeleteReferencesRequest *request,
+void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
                               UA_DeleteReferencesResponse *response) {
                               UA_DeleteReferencesResponse *response) {
 
 
 }
 }

+ 58 - 91
src/server/ua_services_session.c

@@ -7,25 +7,19 @@
 void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
 void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                            const UA_CreateSessionRequest *request,
                            const UA_CreateSessionRequest *request,
                            UA_CreateSessionResponse *response) {
                            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)
+    response->responseHeader.serviceResult =
+        UA_Array_copy(server->endpointDescriptions, (void**)&response->serverEndpoints,
+                      &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], server->endpointDescriptionsSize);
+    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
         return;
         return;
-    response->serverEndpointsSize = 1;
+    response->serverEndpointsSize = server->endpointDescriptionsSize;
 
 
-    // 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;
 	UA_Session *newSession;
     response->responseHeader.serviceResult = UA_SessionManager_createSession(&server->sessionManager,
     response->responseHeader.serviceResult = UA_SessionManager_createSession(&server->sessionManager,
                                                                              channel, request, &newSession);
                                                                              channel, request, &newSession);
 	if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
 	if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
 		return;
 		return;
 
 
-	//bind session to channel
-	channel->session = newSession;
-
     //TODO get maxResponseMessageSize internally
     //TODO get maxResponseMessageSize internally
     newSession->maxResponseMessageSize = request->maxResponseMessageSize;
     newSession->maxResponseMessageSize = request->maxResponseMessageSize;
     response->sessionId = newSession->sessionId;
     response->sessionId = newSession->sessionId;
@@ -36,34 +30,24 @@ void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
         response->responseHeader.serviceResult |=
         response->responseHeader.serviceResult |=
             UA_ByteString_copy(&server->endpointDescriptions->serverCertificate, &response->serverCertificate);
             UA_ByteString_copy(&server->endpointDescriptions->serverCertificate, &response->serverCertificate);
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
-        UA_SessionManager_removeSession(&server->sessionManager, &newSession->sessionId);
+        UA_SessionManager_removeSession(&server->sessionManager, &newSession->authenticationToken);
          return;
          return;
     }
     }
 }
 }
 
 
-#ifdef RETURN
-#undef RETURN
-#endif
-#define RETURN  UA_UserIdentityToken_deleteMembers(&token); \
-                UA_UserNameIdentityToken_deleteMembers(&username_token); \
-                return
-void Service_ActivateSession(UA_Server *server,UA_SecureChannel *channel,
+void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
                              const UA_ActivateSessionRequest *request,
                              const UA_ActivateSessionRequest *request,
                              UA_ActivateSessionResponse *response) {
                              UA_ActivateSessionResponse *response) {
     // make the channel know about the session
     // make the channel know about the session
-	UA_Session *foundSession;
-	UA_SessionManager_getSessionByToken(&server->sessionManager,
-                                        (const UA_NodeId*)&request->requestHeader.authenticationToken,
-                                        &foundSession);
+	UA_Session *foundSession =
+        UA_SessionManager_getSession(&server->sessionManager,
+                                     (const UA_NodeId*)&request->requestHeader.authenticationToken);
 
 
-	if(foundSession == UA_NULL){
+	if(foundSession == UA_NULL) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         return;
         return;
-	}
-
-	if(foundSession->validTill < UA_DateTime_now()){
+	} else if(foundSession->validTill < UA_DateTime_now()) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
-        //TODO: maybe delete session? or wait for a recurring cleanup?
         return;
         return;
 	}
 	}
 
 
@@ -75,80 +59,63 @@ void Service_ActivateSession(UA_Server *server,UA_SecureChannel *channel,
     UA_UserNameIdentityToken username_token;
     UA_UserNameIdentityToken username_token;
     UA_UserNameIdentityToken_init(&username_token);
     UA_UserNameIdentityToken_init(&username_token);
 
 
-    //check policies
-
-    if(token.policyId.data == UA_NULL){ //user identity token is NULL
+    if(token.policyId.data == UA_NULL) {
+        /* 1) no policy defined */
         response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-        //todo cleanup session
-        RETURN;
-    }
-
-    //anonymous logins
-    if(server->config.Login_enableAnonymous && UA_String_equalchars(&token.policyId, ANONYMOUS_POLICY)){
-        //success - activate
-        channel->session = foundSession;
-        channel->session->activated = UA_TRUE;
-        //TODO: not sure if we have to do this, tests seem to work
-        //if(foundSession->channel) //in case session is being rebound
-        //    foundSession->channel->session = UA_NULL;
-        foundSession->channel=channel;
-        RETURN;
-    //username logins
-    }else if(server->config.Login_enableUsernamePassword && UA_String_equalchars(&token.policyId, USERNAME_POLICY)){
+    } else if(server->config.Login_enableAnonymous &&
+              UA_String_equalchars(&token.policyId, ANONYMOUS_POLICY)) {
+        /* 2) anonymous logins */
+        if(foundSession->channel && foundSession->channel != channel)
+            UA_SecureChannel_detachSession(foundSession->channel, foundSession);
+        UA_SecureChannel_attachSession(channel, foundSession);
+        foundSession->activated = UA_TRUE;
+        UA_Session_updateLifetime(foundSession);
+    } else if(server->config.Login_enableUsernamePassword &&
+              UA_String_equalchars(&token.policyId, USERNAME_POLICY)) {
+        /* 3) username logins */
         offset = 0;
         offset = 0;
         UA_UserNameIdentityToken_decodeBinary(&request->userIdentityToken.body, &offset, &username_token);
         UA_UserNameIdentityToken_decodeBinary(&request->userIdentityToken.body, &offset, &username_token);
-        if(username_token.encryptionAlgorithm.data != UA_NULL){
-            //we only support encryption
+        if(username_token.encryptionAlgorithm.data != UA_NULL) {
+            /* 3.1) we only support encryption */
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-            //todo cleanup session
-            RETURN;
-        }
-        if(username_token.userName.length == -1 && username_token.password.length == -1){
-            //empty username and password
+        } else  if(username_token.userName.length == -1 && username_token.password.length == -1){
+            /* 3.2) empty username and password */
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-            //todo cleanup session
-            RETURN;
-        }
-        for(UA_UInt32 i=0;i<server->config.Login_loginsCount;++i){
-            if(UA_String_equalchars(&username_token.userName, server->config.Login_usernames[i])
-            && UA_String_equalchars(&username_token.password, server->config.Login_passwords[i])){
-                //success - activate
-                channel->session = foundSession;
-                channel->session->activated = UA_TRUE;
-                //TODO: not sure if we have to do this, tests seem to work
-                //if(foundSession->channel) //in case session is being rebound
-                //    foundSession->channel->session = UA_NULL;
-                foundSession->channel=channel;
-                RETURN;
+        } else {
+            /* 3.3) ok, trying to match the username */
+            UA_UInt32 i = 0;
+            for(; i < server->config.Login_loginsCount; ++i) {
+                if(UA_String_equalchars(&username_token.userName, server->config.Login_usernames[i])
+                    && UA_String_equalchars(&username_token.password, server->config.Login_passwords[i])) {
+                    /* success - activate */
+                    if(foundSession->channel && foundSession->channel != channel)
+                        UA_SecureChannel_detachSession(foundSession->channel, foundSession);
+                    UA_SecureChannel_attachSession(channel, foundSession);
+                    foundSession->activated = UA_TRUE;
+                    UA_Session_updateLifetime(foundSession);
+                    break;
+                }
             }
             }
+            /* no username/pass matched */
+            if(i >= server->config.Login_loginsCount)
+                response->responseHeader.serviceResult = UA_STATUSCODE_BADUSERACCESSDENIED;
         }
         }
-        //no username/pass matched
-       response->responseHeader.serviceResult = UA_STATUSCODE_BADUSERACCESSDENIED;
-       //todo cleanup session
-       RETURN;
+    } else {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
     }
     }
-
-    //default case - no login
-    response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-    //todo cleanup session
-    RETURN;
-
-
-
+    UA_UserIdentityToken_deleteMembers(&token);
+    UA_UserNameIdentityToken_deleteMembers(&username_token);
+    return;
 }
 }
-#undef RETURN
 
 
 void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_CloseSessionRequest *request,
 void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_CloseSessionRequest *request,
                           UA_CloseSessionResponse *response) {
                           UA_CloseSessionResponse *response) {
-	UA_Session *foundSession;
-	UA_SessionManager_getSessionByToken(&server->sessionManager,
-			(const UA_NodeId*)&request->requestHeader.authenticationToken, &foundSession);
-
-	if(foundSession == UA_NULL){
+	UA_Session *foundSession =
+        UA_SessionManager_getSession(&server->sessionManager,
+		                             (const UA_NodeId*)&request->requestHeader.authenticationToken);
+	if(foundSession == UA_NULL)
 		response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
 		response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
-		return;
-	}
-
-	response->responseHeader.serviceResult =
-        UA_SessionManager_removeSession(&server->sessionManager, &session->sessionId);
+	else 
+        response->responseHeader.serviceResult =
+            UA_SessionManager_removeSession(&server->sessionManager, &session->authenticationToken);
 }
 }

+ 145 - 108
src/server/ua_services_view.c

@@ -75,21 +75,21 @@ is_relevant: ;
  * array to process the newly found referencetype nodeids (emulated recursion).
  * array to process the newly found referencetype nodeids (emulated recursion).
  */
  */
 static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes,
 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;
-
+                                  size_t *reftypes_count) {
     const UA_Node *node = UA_NodeStore_get(ns, root);
     const UA_Node *node = UA_NodeStore_get(ns, root);
-    if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)  {
+    if(!node)
+        return UA_STATUSCODE_BADNOMATCH;
+    if(node->nodeClass != UA_NODECLASS_REFERENCETYPE)  {
         UA_NodeStore_release(node);
         UA_NodeStore_release(node);
-        UA_free(results);
         return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
     }
     }
     UA_NodeStore_release(node);
     UA_NodeStore_release(node);
 
 
+    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_NodeId_copy(root, &results[0]);
     UA_StatusCode retval = UA_NodeId_copy(root, &results[0]);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_free(results);
         UA_free(results);
@@ -136,21 +136,38 @@ static UA_StatusCode findsubtypes(UA_NodeStore *ns, const UA_NodeId *root, UA_No
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-/* Results for a single browsedescription. Call this either with an existing continuationpoint from
-   which we take the entire context for the search. Or, call with a browsedescription and maxrefs
-   value. If we need to create a new continuationpoint, it will be alloced and the new pointer
-   stored in *cp.
+static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session){
+    session->availableContinuationPoints++;
+    UA_ByteString_deleteMembers(&cp->identifier);
+    UA_BrowseDescription_deleteMembers(&cp->browseDescription);
+    LIST_REMOVE(cp, pointers);
+    UA_free(cp);
+}
+
+/**
+ * Results for a single browsedescription. This is the inner loop for both Browse and BrowseNext
+ * @param session Session to save continuationpoints
+ * @param ns The nodstore where the to-be-browsed node can be found
+ * @param cp If cp points to a continuationpoint, we continue from there.
+ *           If cp is null, we can add a new continuation point if possible and necessary.
+ * @param descr If no cp is set, we take the browsedescription from there
+ * @param maxrefs The maximum number of references the client has requested
+ * @param result The entry in the request
  */
  */
-static void browse(UA_NodeStore *ns, struct ContinuationPointEntry **cp, const UA_BrowseDescription *descr, 
-                   UA_UInt32 maxrefs, UA_BrowseResult *result)
-{
+static void browse(UA_Session *session, UA_NodeStore *ns, struct ContinuationPointEntry *cp,
+                   const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) {
     UA_UInt32 continuationIndex = 0;
     UA_UInt32 continuationIndex = 0;
-    if(*cp) {
-        descr = &(*cp)->browseDescription;
-        maxrefs = (*cp)->maxReferences;
-        continuationIndex = (*cp)->continuationIndex;
+    size_t referencesCount = 0;
+    UA_Int32 referencesIndex = 0;
+    
+    /* set the browsedescription if a cp is given */
+    if(cp) {
+        descr = &cp->browseDescription;
+        maxrefs = cp->maxReferences;
+        continuationIndex = cp->continuationIndex;
     }
     }
 
 
+    /* is the browsedirection valid? */
     if(descr->browseDirection != UA_BROWSEDIRECTION_BOTH &&
     if(descr->browseDirection != UA_BROWSEDIRECTION_BOTH &&
        descr->browseDirection != UA_BROWSEDIRECTION_FORWARD &&
        descr->browseDirection != UA_BROWSEDIRECTION_FORWARD &&
        descr->browseDirection != UA_BROWSEDIRECTION_INVERSE) {
        descr->browseDirection != UA_BROWSEDIRECTION_INVERSE) {
@@ -158,30 +175,32 @@ static void browse(UA_NodeStore *ns, struct ContinuationPointEntry **cp, const U
         return;
         return;
     }
     }
     
     
+    /* get the references that match the browsedescription */
     size_t relevant_refs_size = 0;
     size_t relevant_refs_size = 0;
     UA_NodeId *relevant_refs = UA_NULL;
     UA_NodeId *relevant_refs = UA_NULL;
-    // what are the relevant references?
     UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
     UA_Boolean all_refs = UA_NodeId_isNull(&descr->referenceTypeId);
-
-    //check if reference type id exists
-    if(!all_refs && UA_NodeStore_get(ns, &descr->referenceTypeId) == UA_NULL) {
-        result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-        return;
-    }
-
     if(!all_refs) {
     if(!all_refs) {
         if(descr->includeSubtypes) {
         if(descr->includeSubtypes) {
-            result->statusCode = findsubtypes(ns, &descr->referenceTypeId, &relevant_refs,
-                                              &relevant_refs_size);
+            result->statusCode = findsubtypes(ns, &descr->referenceTypeId, &relevant_refs, &relevant_refs_size);
             if(result->statusCode != UA_STATUSCODE_GOOD)
             if(result->statusCode != UA_STATUSCODE_GOOD)
                 return;
                 return;
         } else {
         } else {
+            const UA_Node *rootRef = UA_NodeStore_get(ns, &descr->referenceTypeId);
+            if(!rootRef) {
+                result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+                return;
+            } else if(rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
+                UA_NodeStore_release(rootRef);
+                result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+                return;
+            }
+            UA_NodeStore_release(rootRef);
             relevant_refs = (UA_NodeId*)(uintptr_t)&descr->referenceTypeId;
             relevant_refs = (UA_NodeId*)(uintptr_t)&descr->referenceTypeId;
             relevant_refs_size = 1;
             relevant_refs_size = 1;
         }
         }
     }
     }
 
 
-    // get the node
+    /* get the node */
     const UA_Node *node = UA_NodeStore_get(ns, &descr->nodeId);
     const UA_Node *node = UA_NodeStore_get(ns, &descr->nodeId);
     if(!node) {
     if(!node) {
         result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
@@ -190,11 +209,16 @@ static void browse(UA_NodeStore *ns, struct ContinuationPointEntry **cp, const U
         return;
         return;
     }
     }
 
 
+    /* if the node has no references, just return */
     if(node->referencesSize <= 0) {
     if(node->referencesSize <= 0) {
         result->referencesSize = 0;
         result->referencesSize = 0;
-        goto cleanup;
+        UA_NodeStore_release(node);
+        if(!all_refs && descr->includeSubtypes)
+            UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
+        return;
     }
     }
 
 
+    /* how many references can we return at most? */
     UA_UInt32 real_maxrefs = maxrefs;
     UA_UInt32 real_maxrefs = maxrefs;
     if(real_maxrefs == 0)
     if(real_maxrefs == 0)
         real_maxrefs = node->referencesSize;
         real_maxrefs = node->referencesSize;
@@ -204,10 +228,10 @@ static void browse(UA_NodeStore *ns, struct ContinuationPointEntry **cp, const U
         goto cleanup;
         goto cleanup;
     }
     }
 
 
-    size_t count = 0;
+    /* loop over the node's references */
     size_t skipped = 0;
     size_t skipped = 0;
-    for(UA_Int32 i = 0; i < node->referencesSize && count < real_maxrefs; i++) {
-        const UA_Node *current = relevant_node(ns, descr, all_refs, &node->references[i],
+    for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
+        const UA_Node *current = relevant_node(ns, descr, all_refs, &node->references[referencesIndex],
                                                relevant_refs, relevant_refs_size);
                                                relevant_refs, relevant_refs_size);
         if(!current)
         if(!current)
             continue;
             continue;
@@ -216,53 +240,62 @@ static void browse(UA_NodeStore *ns, struct ContinuationPointEntry **cp, const U
             skipped++;
             skipped++;
             continue;
             continue;
         }
         }
-        UA_StatusCode retval = fillrefdescr(ns, current, &node->references[i], descr->resultMask,
-                                            &result->references[count]);
+        UA_StatusCode retval = fillrefdescr(ns, current, &node->references[referencesIndex], descr->resultMask,
+                                            &result->references[referencesCount]);
         UA_NodeStore_release(current);
         UA_NodeStore_release(current);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
-            UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], count);
+            UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], referencesCount);
             result->references = UA_NULL;
             result->references = UA_NULL;
-            count = 0;
+            result->referencesSize = 0;
             result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
             result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
             goto cleanup;
             goto cleanup;
         }
         }
-        count++;
+        referencesCount++;
     }
     }
 
 
-    if(*cp) {
-        (*cp)->continuationIndex += count;
-        if((*cp)->continuationIndex == node->referencesSize) {
-            /* remove a finished continuationPoint */
-            UA_ByteString_deleteMembers(&(*cp)->identifier);
-            UA_BrowseDescription_deleteMembers(&(*cp)->browseDescription);
-            LIST_REMOVE(*cp, pointers);
-            UA_free(*cp);
-            *cp = UA_NULL;
-        }
-    } else if(maxrefs != 0 && count >= maxrefs) {
-        /* create a continuationPoint */
-        *cp = UA_malloc(sizeof(struct ContinuationPointEntry));
-        UA_BrowseDescription_copy(descr,&(*cp)->browseDescription);
-        (*cp)->maxReferences = maxrefs;
-        (*cp)->continuationIndex = count;
-        UA_Guid *ident = UA_Guid_new();
-        UA_UInt32 seed = (uintptr_t)*cp;
-        *ident = UA_Guid_random(&seed);
-        (*cp)->identifier.data = (UA_Byte*)ident;
-        (*cp)->identifier.length = sizeof(UA_Guid);
-    }
-    
-    if(count > 0)
-        result->referencesSize = count;
-    else {
+    result->referencesSize = referencesCount;
+    if(referencesCount == 0) {
         UA_free(result->references);
         UA_free(result->references);
         result->references = UA_NULL;
         result->references = UA_NULL;
     }
     }
 
 
-cleanup:
+    cleanup:
     UA_NodeStore_release(node);
     UA_NodeStore_release(node);
     if(!all_refs && descr->includeSubtypes)
     if(!all_refs && descr->includeSubtypes)
         UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
         UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        return;
+
+    /* create, update, delete continuation points */
+    if(cp) {
+        if(referencesIndex == node->referencesSize) {
+            /* all done, remove a finished continuationPoint */
+            removeCp(cp, session);
+        } else {
+            /* update the cp and return the cp identifier */
+            cp->continuationIndex += referencesCount;
+            UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
+        }
+    } else if(maxrefs != 0 && referencesCount >= maxrefs) {
+        /* create a cp */
+        if(session->availableContinuationPoints <= 0 || !(cp = UA_malloc(sizeof(struct ContinuationPointEntry)))) {
+            result->statusCode = UA_STATUSCODE_BADNOCONTINUATIONPOINTS;
+            return;
+        }
+        UA_BrowseDescription_copy(descr, &cp->browseDescription);
+        cp->maxReferences = maxrefs;
+        cp->continuationIndex = referencesCount;
+        UA_Guid *ident = UA_Guid_new();
+        UA_UInt32 seed = (uintptr_t)cp;
+        *ident = UA_Guid_random(&seed);
+        cp->identifier.data = (UA_Byte*)ident;
+        cp->identifier.length = sizeof(UA_Guid);
+        UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
+
+        /* store the cp */
+        LIST_INSERT_HEAD(&session->continuationPoints, cp, pointers);
+        session->availableContinuationPoints--;
+    }
 }
 }
 
 
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
@@ -272,25 +305,26 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
         return;
         return;
     }
     }
     
     
-   if(request->nodesToBrowseSize <= 0) {
+    if(request->nodesToBrowseSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
         return;
     }
     }
-   size_t size = request->nodesToBrowseSize;
 
 
-   response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
+    size_t size = request->nodesToBrowseSize;
+    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
     }
     }
-
-    /* ### Begin External Namespaces */
+    response->resultsSize = size;
+    
+#ifdef UA_EXTERNAL_NAMESPACES
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     for(size_t j = 0; j < server->externalNamespacesSize; j++) {
     for(size_t j = 0; j < server->externalNamespacesSize; j++) {
         size_t indexSize = 0;
         size_t indexSize = 0;
-        for(size_t i = 0;i < size;i++) {
+        for(size_t i = 0; i < size; i++) {
             if(request->nodesToBrowse[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
             if(request->nodesToBrowse[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
                 continue;
                 continue;
             isExternal[i] = UA_TRUE;
             isExternal[i] = UA_TRUE;
@@ -303,19 +337,14 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
         ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse, indices, indexSize,
         ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse, indices, indexSize,
                          request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
                          request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
     }
     }
-    /* ### End External Namespaces */
+#endif
 
 
-    response->resultsSize = size;
     for(size_t i = 0; i < size; i++) {
     for(size_t i = 0; i < size; i++) {
-        if(!isExternal[i]) {
-            struct ContinuationPointEntry *cp = UA_NULL;
-            browse(server->nodestore, &cp, &request->nodesToBrowse[i],
+#ifdef UA_EXTERNAL_NAMESPACES
+        if(!isExternal[i])
+#endif
+            browse(session, server->nodestore, UA_NULL, &request->nodesToBrowse[i],
                    request->requestedMaxReferencesPerNode, &response->results[i]);
                    request->requestedMaxReferencesPerNode, &response->results[i]);
-            if(cp) {
-                LIST_INSERT_HEAD(&session->continuationPoints, cp, pointers);
-                UA_ByteString_copy(&cp->identifier, &response->results[i].continuationPoint);
-            }
-        }
     }
     }
 }
 }
 
 
@@ -327,6 +356,7 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
    }
    }
    size_t size = request->continuationPointsSize;
    size_t size = request->continuationPointsSize;
    if(!request->releaseContinuationPoints) {
    if(!request->releaseContinuationPoints) {
+       /* continue with the cp */
        response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
        response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
        if(!response->results) {
        if(!response->results) {
            response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
@@ -334,31 +364,34 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
        }
        }
        response->resultsSize = size;
        response->resultsSize = size;
        for(size_t i = 0; i < size; i++) {
        for(size_t i = 0; i < size; i++) {
-           struct ContinuationPointEntry *cp = UA_NULL;
-           struct ContinuationPointEntry *search_cp;
-           LIST_FOREACH(search_cp, &session->continuationPoints, pointers) {
-               if(UA_ByteString_equal(&search_cp->identifier, &request->continuationPoints[i])) {
-                   cp = search_cp;
+           struct ContinuationPointEntry *cp;
+           LIST_FOREACH(cp, &session->continuationPoints, pointers) {
+               if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
+                   browse(session, server->nodestore, cp, UA_NULL, 0, &response->results[i]);
                    break;
                    break;
                }
                }
            }
            }
            if(!cp)
            if(!cp)
                response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
                response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
-           else
-               browse(server->nodestore, &cp, UA_NULL, 0, &response->results[i]);
        }
        }
    } else {
    } else {
+       /* remove the cp */
+       response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
+       if(!response->results) {
+           response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+           return;
+       }
+       response->resultsSize = size;
        for(size_t i = 0; i < size; i++) {
        for(size_t i = 0; i < size; i++) {
            struct ContinuationPointEntry *cp = UA_NULL;
            struct ContinuationPointEntry *cp = UA_NULL;
            LIST_FOREACH(cp, &session->continuationPoints, pointers) {
            LIST_FOREACH(cp, &session->continuationPoints, pointers) {
                if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
                if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
-                   UA_ByteString_deleteMembers(&cp->identifier);
-                   UA_BrowseDescription_deleteMembers(&cp->browseDescription);
-                   LIST_REMOVE(cp, pointers);
-                   UA_free(cp);
+                   removeCp(cp, session);
                    break;
                    break;
                }
                }
            }
            }
+           if(!cp)
+               response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        }
        }
    }
    }
 }
 }
@@ -384,8 +417,11 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
         all_refs = UA_TRUE;
         all_refs = UA_TRUE;
     else if(!elem->includeSubtypes)
     else if(!elem->includeSubtypes)
         reftypes = (UA_NodeId*)(uintptr_t)&elem->referenceTypeId; // ptr magic due to const cast
         reftypes = (UA_NodeId*)(uintptr_t)&elem->referenceTypeId; // ptr magic due to const cast
-    else
+    else {
         retval = findsubtypes(server->nodestore, &elem->referenceTypeId, &reftypes, &reftypes_count);
         retval = findsubtypes(server->nodestore, &elem->referenceTypeId, &reftypes, &reftypes_count);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
 
 
     for(UA_Int32 i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; i++) {
     for(UA_Int32 i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; i++) {
         UA_Boolean match = all_refs;
         UA_Boolean match = all_refs;
@@ -493,7 +529,7 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
         return;
         return;
     }
     }
 
 
-    /* ### Begin External Namespaces */
+#ifdef UA_EXTERNAL_NAMESPACES
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
@@ -512,11 +548,13 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
     	ens->translateBrowsePathsToNodeIds(ens->ensHandle, &request->requestHeader, request->browsePaths,
     	ens->translateBrowsePathsToNodeIds(ens->ensHandle, &request->requestHeader, request->browsePaths,
     			indices, indexSize, response->results, response->diagnosticInfos);
     			indices, indexSize, response->results, response->diagnosticInfos);
     }
     }
-    /* ### End External Namespaces */
+#endif
 
 
     response->resultsSize = size;
     response->resultsSize = size;
-    for(size_t i = 0; i < size; i++){
+    for(size_t i = 0; i < size; i++) {
+#ifdef UA_EXTERNAL_NAMESPACES
     	if(!isExternal[i])
     	if(!isExternal[i])
+#endif
     		translateBrowsePath(server, session, &request->browsePaths[i], &response->results[i]);
     		translateBrowsePath(server, session, &request->browsePaths[i], &response->results[i]);
     }
     }
 }
 }
@@ -525,13 +563,15 @@ void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_Regi
                            UA_RegisterNodesResponse *response) {
                            UA_RegisterNodesResponse *response) {
 	//TODO: hang the nodeids to the session if really needed
 	//TODO: hang the nodeids to the session if really needed
 	response->responseHeader.timestamp = UA_DateTime_now();
 	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;
+    if(request->nodesToRegisterSize <= 0)
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+    else {
+        response->responseHeader.serviceResult =
+            UA_Array_copy(request->nodesToRegister, (void**)&response->registeredNodeIds, &UA_TYPES[UA_TYPES_NODEID],
+                request->nodesToRegisterSize);
+        if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
+            response->registeredNodeIdsSize = request->nodesToRegisterSize;
+    }
 }
 }
 
 
 void Service_UnregisterNodes(UA_Server *server, UA_Session *session, const UA_UnregisterNodesRequest *request,
 void Service_UnregisterNodes(UA_Server *server, UA_Session *session, const UA_UnregisterNodesRequest *request,
@@ -540,7 +580,4 @@ void Service_UnregisterNodes(UA_Server *server, UA_Session *session, const UA_Un
 	response->responseHeader.timestamp = UA_DateTime_now();
 	response->responseHeader.timestamp = UA_DateTime_now();
 	if(request->nodesToUnregisterSize==0)
 	if(request->nodesToUnregisterSize==0)
 		response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
 		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;
 }
 }

+ 38 - 79
src/server/ua_session_manager.c

@@ -2,12 +2,6 @@
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
 #include "ua_util.h"
 #include "ua_util.h"
 
 
-/**
- The functions in this file are not thread-safe. For multi-threaded access, a
- second implementation should be provided. See for example, how a nodestore
- implementation is choosen based on whether multithreading is enabled or not.
- */
-
 UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt32 maxSessionCount,
 UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt32 maxSessionCount,
                                     UA_UInt32 maxSessionLifeTime, UA_UInt32 startSessionId) {
                                     UA_UInt32 maxSessionLifeTime, UA_UInt32 startSessionId) {
     LIST_INIT(&sessionManager->sessions);
     LIST_INIT(&sessionManager->sessions);
@@ -19,75 +13,44 @@ UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt3
 }
 }
 
 
 void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager) {
 void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager) {
-    session_list_entry *current, *next = LIST_FIRST(&sessionManager->sessions);
-    while(next) {
-        current = next;
-        next = LIST_NEXT(current, pointers);
+    session_list_entry *current;
+    while((current = LIST_FIRST(&sessionManager->sessions))) {
         LIST_REMOVE(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_Session_deleteMembersCleanup(&current->session);
         UA_free(current);
         UA_free(current);
     }
     }
 }
 }
 
 
-UA_StatusCode
-UA_SessionManager_getSessionById(UA_SessionManager *sessionManager, const UA_NodeId *sessionId,
-                                 UA_Session **session)
-{
-    if(sessionManager == UA_NULL) {
-        *session = UA_NULL;
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
-
-    session_list_entry *current = UA_NULL;
-    LIST_FOREACH(current, &sessionManager->sessions, pointers) {
-        if(UA_NodeId_equal(&current->session.sessionId, sessionId))
-            break;
-    }
-
-    if(!current) {
-        *session = UA_NULL;
-        return UA_STATUSCODE_BADINTERNALERROR;
+void UA_SessionManager_cleanupTimedOut(UA_SessionManager *sessionManager, UA_DateTime now) {
+    session_list_entry *sentry = LIST_FIRST(&sessionManager->sessions);
+    while(sentry) {
+        if(sentry->session.validTill < now) {
+            session_list_entry *next = LIST_NEXT(sentry, pointers);
+            LIST_REMOVE(sentry, pointers);
+            UA_Session_deleteMembersCleanup(&sentry->session);
+            UA_free(sentry);
+            sessionManager->currentSessionCount--;
+            sentry = next;
+        } else {
+            sentry = LIST_NEXT(sentry, pointers);
+        }
     }
     }
-
-    // Lifetime handling is not done here, but in a regular cleanup by the
-    // server. If the session still exists, then it is valid.
-    *session = &current->session;
-    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode
-UA_SessionManager_getSessionByToken(UA_SessionManager *sessionManager, const UA_NodeId *token,
-                                    UA_Session **session)
-{
-    if(sessionManager == UA_NULL) {
-        *session = UA_NULL;
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
-
+UA_Session * UA_SessionManager_getSession(UA_SessionManager *sessionManager, const UA_NodeId *token) {
     session_list_entry *current = UA_NULL;
     session_list_entry *current = UA_NULL;
     LIST_FOREACH(current, &sessionManager->sessions, pointers) {
     LIST_FOREACH(current, &sessionManager->sessions, pointers) {
         if(UA_NodeId_equal(&current->session.authenticationToken, token))
         if(UA_NodeId_equal(&current->session.authenticationToken, token))
             break;
             break;
     }
     }
-
-    if(!current) {
-        *session = UA_NULL;
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
-
-    // Lifetime handling is not done here, but in a regular cleanup by the
-    // server. If the session still exists, then it is valid.
-    *session = &current->session;
-    return UA_STATUSCODE_GOOD;
+    if(!current || UA_DateTime_now() > current->session.validTill)
+        return UA_NULL;
+    return &current->session;
 }
 }
 
 
-/** Creates and adds a session. */
-UA_StatusCode
-UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChannel *channel,
-                                const UA_CreateSessionRequest *request, UA_Session **session)
-{
+/** Creates and adds a session. But it is not yet attached to a secure channel. */
+UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChannel *channel,
+                                              const UA_CreateSessionRequest *request, UA_Session **session) {
     if(sessionManager->currentSessionCount >= sessionManager->maxSessionCount)
     if(sessionManager->currentSessionCount >= sessionManager->maxSessionCount)
         return UA_STATUSCODE_BADTOOMANYSESSIONS;
         return UA_STATUSCODE_BADTOOMANYSESSIONS;
 
 
@@ -95,37 +58,33 @@ UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChan
     if(!newentry)
     if(!newentry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
+    sessionManager->currentSessionCount++;
     UA_Session_init(&newentry->session);
     UA_Session_init(&newentry->session);
     newentry->session.sessionId = UA_NODEID_NUMERIC(1, sessionManager->lastSessionId++);
     newentry->session.sessionId = UA_NODEID_NUMERIC(1, sessionManager->lastSessionId++);
-    newentry->session.authenticationToken = UA_NODEID_NUMERIC(1, sessionManager->lastSessionId);
-    newentry->session.channel = channel;
-    newentry->session.timeout =
-        (request->requestedSessionTimeout <= sessionManager->maxSessionLifeTime &&
-         request->requestedSessionTimeout>0) ?
-        request->requestedSessionTimeout : sessionManager->maxSessionLifeTime;
-    UA_Session_setExpirationDate(&newentry->session);
-
-    sessionManager->currentSessionCount++;
+    UA_UInt32 randSeed = sessionManager->lastSessionId;
+    newentry->session.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random(&randSeed));
+    if(request->requestedSessionTimeout <= sessionManager->maxSessionLifeTime &&
+       request->requestedSessionTimeout > 0)
+        newentry->session.timeout = request->requestedSessionTimeout;
+    else
+        newentry->session.timeout = sessionManager->maxSessionLifeTime; // todo: remove when the CTT is fixed
+    UA_Session_updateLifetime(&newentry->session);
     LIST_INSERT_HEAD(&sessionManager->sessions, newentry, pointers);
     LIST_INSERT_HEAD(&sessionManager->sessions, newentry, pointers);
     *session = &newentry->session;
     *session = &newentry->session;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode
-UA_SessionManager_removeSession(UA_SessionManager *sessionManager, const UA_NodeId *sessionId)
-{
-    session_list_entry *current = UA_NULL;
+UA_StatusCode UA_SessionManager_removeSession(UA_SessionManager *sessionManager, const UA_NodeId *token) {
+    session_list_entry *current;
     LIST_FOREACH(current, &sessionManager->sessions, pointers) {
     LIST_FOREACH(current, &sessionManager->sessions, pointers) {
-        if(UA_NodeId_equal(&current->session.sessionId, sessionId))
+        if(UA_NodeId_equal(&current->session.authenticationToken, token))
             break;
             break;
     }
     }
-
     if(!current)
     if(!current)
-        return UA_STATUSCODE_BADINTERNALERROR;
-
+        return UA_STATUSCODE_BADSESSIONIDINVALID;
     LIST_REMOVE(current, pointers);
     LIST_REMOVE(current, pointers);
-    UA_SecureChannel_detachSession(current->session.channel);
-    UA_Session_deleteMembers(&current->session);
+    UA_Session_deleteMembersCleanup(&current->session);
     UA_free(current);
     UA_free(current);
+    sessionManager->currentSessionCount--;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }

+ 8 - 13
src/server/ua_session_manager.h

@@ -7,8 +7,8 @@
 #include "ua_session.h"
 #include "ua_session.h"
 
 
 typedef struct session_list_entry {
 typedef struct session_list_entry {
-    UA_Session session;
     LIST_ENTRY(session_list_entry) pointers;
     LIST_ENTRY(session_list_entry) pointers;
+    UA_Session session;
 } session_list_entry;
 } session_list_entry;
 
 
 typedef struct UA_SessionManager {
 typedef struct UA_SessionManager {
@@ -24,20 +24,15 @@ UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt3
 
 
 void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager);
 void UA_SessionManager_deleteMembers(UA_SessionManager *sessionManager);
 
 
-UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager,
-                                              UA_SecureChannel *channel, const UA_CreateSessionRequest *request, UA_Session **session);
+void UA_SessionManager_cleanupTimedOut(UA_SessionManager *sessionManager, UA_DateTime now);
 
 
-UA_StatusCode UA_SessionManager_removeSession(UA_SessionManager *sessionManager,
-                                              const UA_NodeId *sessionId);
-
-/** Finds the session which is identified by the sessionId */
-UA_StatusCode UA_SessionManager_getSessionById(UA_SessionManager *sessionManager,
-                                               const UA_NodeId *sessionId, UA_Session **session);
+UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager,
+                                              UA_SecureChannel *channel, const UA_CreateSessionRequest *request,
+                                              UA_Session **session);
 
 
-UA_StatusCode UA_SessionManager_getSessionByToken(UA_SessionManager *sessionManager,
-                                                  const UA_NodeId *token, UA_Session **session);
+UA_StatusCode UA_SessionManager_removeSession(UA_SessionManager *sessionManager, const UA_NodeId *token);
 
 
-//UA_Int32 UA_SessionManager_updateSessions();
-//UA_Int32 UA_SessionManager_generateToken(UA_Session session, UA_Int32 requestedLifeTime, SecurityTokenRequestType requestType, UA_ChannelSecurityToken* newToken);
+/** Finds the session which is identified by the authentication token */
+UA_Session * UA_SessionManager_getSession(UA_SessionManager *sessionManager, const UA_NodeId *token);
 
 
 #endif /* UA_SESSION_MANAGER_H_ */
 #endif /* UA_SESSION_MANAGER_H_ */

+ 28 - 2
src/ua_connection.c

@@ -1,8 +1,7 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_connection.h"
 #include "ua_connection.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
-
-const char *UA_LoggerCategoryNames[4] = {"communication", "server", "client", "userland"};
+#include "ua_securechannel.h"
 
 
 // max message size is 64k
 // max message size is 64k
 const UA_ConnectionConfig UA_ConnectionConfig_standard =
 const UA_ConnectionConfig UA_ConnectionConfig_standard =
@@ -20,6 +19,8 @@ void UA_Connection_init(UA_Connection *connection) {
     connection->write = UA_NULL;
     connection->write = UA_NULL;
     connection->close = UA_NULL;
     connection->close = UA_NULL;
     connection->recv = UA_NULL;
     connection->recv = UA_NULL;
+    connection->getBuffer = UA_NULL;
+    connection->releaseBuffer = UA_NULL;
 }
 }
 
 
 void UA_Connection_deleteMembers(UA_Connection *connection) {
 void UA_Connection_deleteMembers(UA_Connection *connection) {
@@ -98,3 +99,28 @@ UA_ByteString UA_Connection_completeMessages(UA_Connection *connection, UA_ByteS
     }
     }
     return current;
     return current;
 }
 }
+
+void UA_Connection_detachSecureChannel(UA_Connection *connection) {
+#ifdef UA_MULTITHREADING
+    UA_SecureChannel *channel = connection->channel;
+    if(channel)
+        uatomic_cmpxchg(&channel->connection, connection, UA_NULL);
+    uatomic_set(&connection->channel, UA_NULL);
+#else
+    if(connection->channel)
+        connection->channel->connection = UA_NULL;
+    connection->channel = UA_NULL;
+#endif
+}
+
+void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
+#ifdef UA_MULTITHREADING
+    if(uatomic_cmpxchg(&channel->connection, UA_NULL, connection) == UA_NULL)
+        uatomic_set(&connection->channel, channel);
+#else
+    if(channel->connection != UA_NULL)
+        return;
+    channel->connection = connection;
+    connection->channel = channel;
+#endif
+}

+ 51 - 21
src/ua_securechannel.c

@@ -1,5 +1,6 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_securechannel.h"
 #include "ua_securechannel.h"
+#include "ua_session.h"
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
 
 
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
@@ -12,15 +13,25 @@ void UA_SecureChannel_init(UA_SecureChannel *channel) {
     channel->requestId = 0;
     channel->requestId = 0;
     channel->sequenceNumber = 0;
     channel->sequenceNumber = 0;
     channel->connection = UA_NULL;
     channel->connection = UA_NULL;
-    channel->session    = UA_NULL;
+    LIST_INIT(&channel->sessions);
 }
 }
 
 
-void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel) {
+void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel) {
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->serverAsymAlgSettings);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->serverAsymAlgSettings);
     UA_ByteString_deleteMembers(&channel->serverNonce);
     UA_ByteString_deleteMembers(&channel->serverNonce);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
     UA_ByteString_deleteMembers(&channel->clientNonce);
     UA_ByteString_deleteMembers(&channel->clientNonce);
     UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
     UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
+    UA_Connection *c = channel->connection;
+    if(c) {
+        UA_Connection_detachSecureChannel(c);
+        c->close(c);
+    }
+    /* just remove the pointers and free the linked list (not the sessions) */
+    struct SessionEntry *se;
+    while((se = LIST_FIRST(&channel->sessions))) {
+        UA_SecureChannel_detachSession(channel, se->session); /* the se is deleted inside */
+    }
 }
 }
 
 
 //TODO implement real nonce generator - DUMMY function
 //TODO implement real nonce generator - DUMMY function
@@ -48,28 +59,47 @@ UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, U
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-/* these need ua_securechannel.h */
-void UA_Connection_detachSecureChannel(UA_Connection *connection) {
+void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session) {
+    struct SessionEntry *se = UA_malloc(sizeof(struct SessionEntry));
+    if(!se)
+        return;
+    se->session = session;
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
-    UA_SecureChannel *channel = connection->channel;
-    if(channel)
-        uatomic_cmpxchg(&channel->connection, connection, UA_NULL);
-    uatomic_set(&connection->channel, UA_NULL);
+    if(uatomic_cmpxchg(&session->channel, UA_NULL, channel) != UA_NULL) {
+        UA_free(se);
+        return;
+    }
 #else
 #else
-    if(connection->channel)
-        connection->channel->connection = UA_NULL;
-    connection->channel = UA_NULL;
+    if(session->channel != UA_NULL) {
+        UA_free(se);
+        return;
+    }
+    session->channel = channel;
 #endif
 #endif
+    LIST_INSERT_HEAD(&channel->sessions, se, pointers);
 }
 }
 
 
-void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
-#ifdef UA_MULTITHREADING
-    if(uatomic_cmpxchg(&channel->connection, UA_NULL, connection) == UA_NULL)
-        uatomic_set(&connection->channel, channel);
-#else
-    if(channel->connection != UA_NULL)
-        return;
-    channel->connection = connection;
-    connection->channel = channel;
-#endif
+void UA_SecureChannel_detachSession(UA_SecureChannel *channel, UA_Session *session) {
+    if(session)
+        session->channel = UA_NULL;
+    struct SessionEntry *se;
+    LIST_FOREACH(se, &channel->sessions, pointers) {
+        if(se->session != session)
+            continue;
+        LIST_REMOVE(se, pointers);
+        UA_free(se);
+        break;
+    }
+}
+
+UA_Session * UA_SecureChannel_getSession(UA_SecureChannel *channel, UA_NodeId *token) {
+    struct SessionEntry *se;
+    LIST_FOREACH(se, &channel->sessions, pointers) {
+        if(UA_NodeId_equal(&se->session->authenticationToken, token))
+            break;
+    }
+    if(se)
+        return se->session;
+    else
+        return UA_NULL;
 }
 }

+ 10 - 3
src/ua_securechannel.h

@@ -1,6 +1,7 @@
 #ifndef UA_SECURECHANNEL_H_
 #ifndef UA_SECURECHANNEL_H_
 #define UA_SECURECHANNEL_H_
 #define UA_SECURECHANNEL_H_
 
 
+#include "queue.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_transport_generated.h"
 #include "ua_transport_generated.h"
 #include "ua_connection.h"
 #include "ua_connection.h"
@@ -14,6 +15,11 @@
 struct UA_Session;
 struct UA_Session;
 typedef struct UA_Session UA_Session;
 typedef struct UA_Session UA_Session;
 
 
+struct SessionEntry {
+    LIST_ENTRY(SessionEntry) pointers;
+    UA_Session *session; // Just a pointer. The session is held in the session manager or the client
+};
+
 struct UA_SecureChannel {
 struct UA_SecureChannel {
     UA_MessageSecurityMode  securityMode;
     UA_MessageSecurityMode  securityMode;
     UA_ChannelSecurityToken securityToken; // the channelId is contained in the securityToken
     UA_ChannelSecurityToken securityToken; // the channelId is contained in the securityToken
@@ -24,18 +30,19 @@ struct UA_SecureChannel {
     UA_UInt32      requestId;
     UA_UInt32      requestId;
     UA_UInt32      sequenceNumber;
     UA_UInt32      sequenceNumber;
     UA_Connection *connection;
     UA_Connection *connection;
-    UA_Session    *session;
+    LIST_HEAD(session_pointerlist, SessionEntry) sessions;
 };
 };
 
 
 void UA_SecureChannel_init(UA_SecureChannel *channel);
 void UA_SecureChannel_init(UA_SecureChannel *channel);
-void UA_SecureChannel_deleteMembers(UA_SecureChannel *channel);
+void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel);
 
 
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce);
 UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce);
 UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId);
 UA_StatusCode UA_SecureChannel_updateRequestId(UA_SecureChannel *channel, UA_UInt32 requestId);
 UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber);
 UA_StatusCode UA_SecureChannel_updateSequenceNumber(UA_SecureChannel *channel, UA_UInt32 sequenceNumber);
 
 
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session);
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session);
-void UA_SecureChannel_detachSession(UA_SecureChannel *channel);
+void UA_SecureChannel_detachSession(UA_SecureChannel *channel, UA_Session *session);
+UA_Session * UA_SecureChannel_getSession(UA_SecureChannel *channel, UA_NodeId *token);
 
 
 /** @} */
 /** @} */
 
 

+ 7 - 65
src/ua_session.c

@@ -30,14 +30,6 @@ UA_Session adminSession = {
     .timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL,
     .timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = UA_NULL,
     .continuationPoints = {UA_NULL}};
     .continuationPoints = {UA_NULL}};
 
 
-/* TODO: Nobody seems to call this function right now */
-static UA_StatusCode UA_Session_generateToken(UA_NodeId *newToken, UA_UInt32 *seed) {
-    newToken->namespaceIndex = 0; // where else?
-    newToken->identifierType = UA_NODEIDTYPE_GUID;
-    newToken->identifier.guid = UA_Guid_random(seed);
-    return UA_STATUSCODE_GOOD;
-}
-
 void UA_Session_init(UA_Session *session) {
 void UA_Session_init(UA_Session *session) {
     UA_ApplicationDescription_init(&session->clientDescription);
     UA_ApplicationDescription_init(&session->clientDescription);
     session->activated = UA_FALSE;
     session->activated = UA_FALSE;
@@ -49,79 +41,29 @@ void UA_Session_init(UA_Session *session) {
     session->timeout = 0;
     session->timeout = 0;
     UA_DateTime_init(&session->validTill);
     UA_DateTime_init(&session->validTill);
     session->channel = UA_NULL;
     session->channel = UA_NULL;
-    session->continuationPoints = (struct ContinuationPointList){UA_NULL};
     #ifdef ENABLESUBSCRIPTIONS
     #ifdef ENABLESUBSCRIPTIONS
         SubscriptionManager_init(session);
         SubscriptionManager_init(session);
     #endif
     #endif
+    session->availableContinuationPoints = MAXCONTINUATIONPOINTS;
+    LIST_INIT(&session->continuationPoints);
 }
 }
 
 
-void UA_Session_deleteMembers(UA_Session *session) {
+void UA_Session_deleteMembersCleanup(UA_Session *session) {
     UA_ApplicationDescription_deleteMembers(&session->clientDescription);
     UA_ApplicationDescription_deleteMembers(&session->clientDescription);
     UA_NodeId_deleteMembers(&session->authenticationToken);
     UA_NodeId_deleteMembers(&session->authenticationToken);
     UA_NodeId_deleteMembers(&session->sessionId);
     UA_NodeId_deleteMembers(&session->sessionId);
     UA_String_deleteMembers(&session->sessionName);
     UA_String_deleteMembers(&session->sessionName);
-    session->channel = UA_NULL;
     struct ContinuationPointEntry *cp;
     struct ContinuationPointEntry *cp;
     while((cp = LIST_FIRST(&session->continuationPoints))) {
     while((cp = LIST_FIRST(&session->continuationPoints))) {
+        LIST_REMOVE(cp, pointers);
         UA_ByteString_deleteMembers(&cp->identifier);
         UA_ByteString_deleteMembers(&cp->identifier);
         UA_BrowseDescription_deleteMembers(&cp->browseDescription);
         UA_BrowseDescription_deleteMembers(&cp->browseDescription);
-        LIST_REMOVE(cp, pointers);
         UA_free(cp);
         UA_free(cp);
     }
     }
-}
-
-UA_StatusCode UA_Session_setExpirationDate(UA_Session *session) {
-    if(!session)
-        return UA_STATUSCODE_BADINTERNALERROR;
-
-    session->validTill = UA_DateTime_now() + session->timeout * 10000; //timeout in ms
-    return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode UA_Session_getPendingLifetime(UA_Session *session, UA_Double *pendingLifetime_ms) {
-    if(!session)
-        return UA_STATUSCODE_BADINTERNALERROR;
-
-    *pendingLifetime_ms = (session->validTill - UA_DateTime_now())/10000; //difference in ms
-    return UA_STATUSCODE_GOOD;
-}
-
-void UA_Session_detachSecureChannel(UA_Session *session) {
-#ifdef UA_MULTITHREADING
-    UA_SecureChannel *channel = session->channel;
-    if(channel)
-        uatomic_cmpxchg(&channel->session, session, UA_NULL);
-    uatomic_set(&session->channel, UA_NULL);
-#else
     if(session->channel)
     if(session->channel)
-        session->channel->session = UA_NULL;
-    session->channel = UA_NULL;
-#endif
-}
-
-/* these functions are here, since they need to include ua_session.h */
-void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session) {
-#ifdef UA_MULTITHREADING
-    if(uatomic_cmpxchg(&session->channel, UA_NULL, channel) == UA_NULL)
-        uatomic_set(&channel->session, session);
-#else
-    if(session->channel != UA_NULL)
-        return;
-    session->channel = channel;
-    channel->session = session;
-#endif
+        UA_SecureChannel_detachSession(session->channel, session);
 }
 }
 
 
-void UA_SecureChannel_detachSession(UA_SecureChannel *channel) {
-#ifdef UA_MULTITHREADING
-    UA_Session *session = channel->session;
-    if(session)
-        uatomic_cmpxchg(&session->channel, channel, UA_NULL);
-    uatomic_set(&channel->session, UA_NULL);
-#else
-    if(channel == NULL) return;
-    if(channel->session)
-        channel->session->channel = UA_NULL;
-    channel->session = UA_NULL;
-#endif
+void UA_Session_updateLifetime(UA_Session *session) {
+    session->validTill = UA_DateTime_now() + session->timeout * 10000; //timeout in ms
 }
 }

+ 7 - 10
src/ua_session.h

@@ -1,9 +1,11 @@
 #ifndef UA_SESSION_H_
 #ifndef UA_SESSION_H_
 #define UA_SESSION_H_
 #define UA_SESSION_H_
 
 
+#include "queue.h"
 #include "ua_types.h"
 #include "ua_types.h"
 #include "ua_securechannel.h"
 #include "ua_securechannel.h"
-#include "queue.h"
+
+#define MAXCONTINUATIONPOINTS 5
 
 
 #ifdef ENABLESUBSCRIPTIONS
 #ifdef ENABLESUBSCRIPTIONS
 #include "server/ua_subscription_manager.h"
 #include "server/ua_subscription_manager.h"
@@ -37,6 +39,7 @@ struct UA_Session {
         UA_SubscriptionManager subscriptionManager;
         UA_SubscriptionManager subscriptionManager;
     #endif
     #endif
     UA_SecureChannel *channel;
     UA_SecureChannel *channel;
+    UA_UInt16 availableContinuationPoints;
     LIST_HEAD(ContinuationPointList, ContinuationPointEntry) continuationPoints;
     LIST_HEAD(ContinuationPointList, ContinuationPointEntry) continuationPoints;
 };
 };
 
 
@@ -44,16 +47,10 @@ extern UA_Session anonymousSession; ///< If anonymous access is allowed, this se
 extern UA_Session adminSession; ///< Local access to the services (for startup and maintenance) uses this Session with all possible access rights (Session ID: 1)
 extern UA_Session adminSession; ///< Local access to the services (for startup and maintenance) uses this Session with all possible access rights (Session ID: 1)
 
 
 void UA_Session_init(UA_Session *session);
 void UA_Session_init(UA_Session *session);
-void UA_Session_deleteMembers(UA_Session *session);
-
-/** If any activity on a session happens, the timeout must be extended */
-UA_StatusCode UA_Session_updateLifetime(UA_Session *session);
-/** Set up the point in time till the session is valid */
-UA_StatusCode UA_Session_setExpirationDate(UA_Session *session);
-/** Gets the sessions pending lifetime (calculated from the timeout which was set) */
-UA_StatusCode UA_Session_getPendingLifetime(UA_Session *session, UA_Double *pendingLifetime);
+void UA_Session_deleteMembersCleanup(UA_Session *session);
 
 
-void UA_Session_detachSecureChannel(UA_Session *session);
+/** If any activity on a session happens, the timeout is extended */
+void UA_Session_updateLifetime(UA_Session *session);
 
 
 /** @} */
 /** @} */
 
 

+ 108 - 40
src/ua_types.c

@@ -104,7 +104,7 @@ UA_StatusCode UA_String_copy(UA_String const *src, UA_String *dst) {
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_String UA_String_fromChars(char const *src) {
+UA_String UA_String_fromChars(char const src[]) {
     UA_String str;
     UA_String str;
     size_t length = strlen(src);
     size_t length = strlen(src);
     if(length == 0) {
     if(length == 0) {
@@ -122,25 +122,25 @@ UA_String UA_String_fromChars(char const *src) {
     return str;
     return str;
 }
 }
 
 
-#define UA_STRING_COPYPRINTF_BUFSIZE 1024
-UA_StatusCode UA_String_copyprintf(char const *fmt, UA_String *dst, ...) {
-    char src[UA_STRING_COPYPRINTF_BUFSIZE];
+#define UA_STRING_ALLOCPRINTF_BUFSIZE 1024
+UA_StatusCode UA_String_copyprintf(char const fmt[], UA_String *dst, ...) {
+    char src[UA_STRING_ALLOCPRINTF_BUFSIZE];
     va_list ap;
     va_list ap;
     va_start(ap, dst);
     va_start(ap, dst);
-#if defined(__GNUC__) || defined(__clang__)
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic push
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
 #endif
 #endif
     // vsnprintf should only take a literal and no variable to be secure
     // vsnprintf should only take a literal and no variable to be secure
-    UA_Int32 len = vsnprintf(src, UA_STRING_COPYPRINTF_BUFSIZE, fmt, ap);
-#if defined(__GNUC__) || defined(__clang__)
+    UA_Int32 len = vsnprintf(src, UA_STRING_ALLOCPRINTF_BUFSIZE, fmt, ap);
+#if ((__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4 || defined(__clang__))
 #pragma GCC diagnostic pop
 #pragma GCC diagnostic pop
 #endif
 #endif
     va_end(ap);
     va_end(ap);
     if(len < 0)  // FIXME: old glibc 2.0 would return -1 when truncated
     if(len < 0)  // FIXME: old glibc 2.0 would return -1 when truncated
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     // since glibc 2.1 vsnprintf returns the len that would have resulted if buf were large enough
     // since glibc 2.1 vsnprintf returns the len that would have resulted if buf were large enough
-    len = ( len > UA_STRING_COPYPRINTF_BUFSIZE ? UA_STRING_COPYPRINTF_BUFSIZE : len );
+    len = ( len > UA_STRING_ALLOCPRINTF_BUFSIZE ? UA_STRING_ALLOCPRINTF_BUFSIZE : len );
     if(!(dst->data = UA_malloc((UA_UInt32)len)))
     if(!(dst->data = UA_malloc((UA_UInt32)len)))
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
     UA_memcpy((void *)dst->data, src, (UA_UInt32)len);
     UA_memcpy((void *)dst->data, src, (UA_UInt32)len);
@@ -333,11 +333,6 @@ UA_StatusCode UA_NodeId_copy(UA_NodeId const *src, UA_NodeId *dst) {
     return retval;
     return retval;
 }
 }
 
 
-static UA_Boolean UA_NodeId_isBasicType(UA_NodeId const *id) {
-    return id ->namespaceIndex == 0 && 1 <= id ->identifier.numeric &&
-        id ->identifier.numeric <= 25;
-}
-
 void UA_NodeId_deleteMembers(UA_NodeId *p) {
 void UA_NodeId_deleteMembers(UA_NodeId *p) {
     switch(p->identifierType) {
     switch(p->identifierType) {
     case UA_NODEIDTYPE_STRING:
     case UA_NODEIDTYPE_STRING:
@@ -401,6 +396,62 @@ UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
     return UA_TRUE;
     return UA_TRUE;
 }
 }
 
 
+UA_NodeId UA_NodeId_fromInteger(UA_UInt16 nsIndex, UA_Int32 identifier) {
+    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_NUMERIC,
+                         .identifier.numeric = identifier };
+}
+
+UA_NodeId UA_NodeId_fromCharString(UA_UInt16 nsIndex, char identifier[]) {
+    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_STRING,
+                         .identifier.string = UA_STRING(identifier) };
+}
+
+UA_NodeId UA_NodeId_fromCharStringCopy(UA_UInt16 nsIndex, char const identifier[]) {
+    return (UA_NodeId) {.namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_STRING,
+                        .identifier.string = UA_STRING_ALLOC(identifier) };
+}
+
+UA_NodeId UA_NodeId_fromString(UA_UInt16 nsIndex, UA_String identifier) {
+    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_STRING,
+                         .identifier.string = identifier };
+}
+
+UA_NodeId UA_NodeId_fromStringCopy(UA_UInt16 nsIndex, UA_String identifier) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_STRING;
+    UA_String_copy(&identifier, &id.identifier.string);
+    return id;
+}
+
+UA_NodeId UA_NodeId_fromGuid(UA_UInt16 nsIndex, UA_Guid identifier) {
+    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_GUID,
+                         .identifier.guid = identifier };
+}
+
+UA_NodeId UA_NodeId_fromCharByteString(UA_UInt16 nsIndex, char identifier[]) {
+    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_BYTESTRING,
+                         .identifier.byteString = UA_STRING(identifier) };
+}
+
+UA_NodeId UA_NodeId_fromCharByteStringCopy(UA_UInt16 nsIndex, char const identifier[]) {
+    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_BYTESTRING,
+                         .identifier.byteString = UA_STRING_ALLOC(identifier) };
+}
+
+UA_NodeId UA_NodeId_fromByteString(UA_UInt16 nsIndex, UA_ByteString identifier) {
+    return (UA_NodeId) { .namespaceIndex = nsIndex, .identifierType = UA_NODEIDTYPE_BYTESTRING,
+                         .identifier.byteString = identifier };
+}
+
+UA_NodeId UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteString identifier) {
+    UA_NodeId id;
+    id.namespaceIndex = nsIndex;
+    id.identifierType = UA_NODEIDTYPE_BYTESTRING;
+    UA_ByteString_copy(&identifier, &id.identifier.byteString);
+    return id;
+}
+
 /* ExpandedNodeId */
 /* ExpandedNodeId */
 UA_TYPE_NEW_DEFAULT(UA_ExpandedNodeId)
 UA_TYPE_NEW_DEFAULT(UA_ExpandedNodeId)
 UA_TYPE_DELETE_DEFAULT(UA_ExpandedNodeId)
 UA_TYPE_DELETE_DEFAULT(UA_ExpandedNodeId)
@@ -566,15 +617,16 @@ void UA_Variant_deleteMembers(UA_Variant *p) {
     if(p->arrayDimensions) {
     if(p->arrayDimensions) {
         UA_free(p->arrayDimensions);
         UA_free(p->arrayDimensions);
         p->arrayDimensions = UA_NULL;
         p->arrayDimensions = UA_NULL;
+        p->arrayDimensionsSize = -1;
     }
     }
 }
 }
 
 
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
 UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
     UA_Variant_init(dst);
     UA_Variant_init(dst);
-    UA_Int32 tmp = src->arrayLength;
-    if(src->arrayLength == -1 && src->data)
-        tmp = 1;
-    UA_StatusCode retval = UA_Array_copy(src->data, &dst->data, src->type, tmp);
+    UA_Int32 elements = src->arrayLength;
+    if(UA_Variant_isScalar(src))
+        elements = 1;
+    UA_StatusCode retval = UA_Array_copy(src->data, &dst->data, src->type, elements);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Variant_deleteMembers(dst);
         UA_Variant_deleteMembers(dst);
         UA_Variant_init(dst);
         UA_Variant_init(dst);
@@ -597,7 +649,7 @@ UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
     return retval;
     return retval;
 }
 }
 
 
-UA_Boolean UA_Variant_isScalar(UA_Variant *v) {
+UA_Boolean UA_Variant_isScalar(const UA_Variant *v) {
     return (v->data != UA_NULL && v->arrayLength == -1);
     return (v->data != UA_NULL && v->arrayLength == -1);
 }
 }
 
 
@@ -628,7 +680,7 @@ testRangeWithVariant(const UA_Variant *v, const UA_NumericRange range, size_t *t
     /* Test the integrity of the range */
     /* Test the integrity of the range */
     size_t count = 1;
     size_t count = 1;
     if(range.dimensionsSize != dims_count)
     if(range.dimensionsSize != dims_count)
-        return UA_STATUSCODE_BADINTERNALERROR;
+        return UA_STATUSCODE_BADINDEXRANGEINVALID;
     for(UA_Int32 i = 0; i < dims_count; i++) {
     for(UA_Int32 i = 0; i < dims_count; i++) {
         if(range.dimensions[i].min > range.dimensions[i].max)
         if(range.dimensions[i].min > range.dimensions[i].max)
             return UA_STATUSCODE_BADINDEXRANGEINVALID;
             return UA_STATUSCODE_BADINDEXRANGEINVALID;
@@ -714,47 +766,63 @@ UA_StatusCode UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_Variant_setRange(UA_Variant *v, void *data, const UA_NumericRange range) {
+UA_StatusCode UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_Int32 dataArraySize,
+                                  const UA_NumericRange range) {
     size_t count, block_size, block_distance, first_elem;
     size_t count, block_size, block_distance, first_elem;
     UA_StatusCode retval = testRangeWithVariant(v, range, &count, &block_size, &block_distance, &first_elem);
     UA_StatusCode retval = testRangeWithVariant(v, range, &count, &block_size, &block_distance, &first_elem);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
+    if((UA_Int32)count != dataArraySize)
+        return UA_STATUSCODE_BADINDEXRANGEINVALID;
 
 
     size_t block_count = count / block_size;
     size_t block_count = count / block_size;
     size_t elem_size = v->type->memSize;
     size_t elem_size = v->type->memSize;
     uintptr_t nextdst = (uintptr_t)v->data + (first_elem * elem_size);
     uintptr_t nextdst = (uintptr_t)v->data + (first_elem * elem_size);
-    uintptr_t nextsrc = (uintptr_t)data;
-    if(v->type->fixedSize) {
-        for(size_t i = 0; i < block_count; i++) {
-            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block_size);
-            nextdst += block_size * elem_size;
-            nextsrc += block_distance * elem_size;
-        }
-    } else {
-        for(size_t i = 0; i < block_count; i++) {
+    uintptr_t nextsrc = (uintptr_t)dataArray;
+    for(size_t i = 0; i < block_count; i++) {
+        if(!v->type->fixedSize) {
             for(size_t j = 0; j < block_size; j++) {
             for(size_t j = 0; j < block_size; j++) {
                 UA_deleteMembers((void*)nextdst, v->type);
                 UA_deleteMembers((void*)nextdst, v->type);
                 nextdst += elem_size;
                 nextdst += elem_size;
             }
             }
             nextdst -= block_size * elem_size;
             nextdst -= block_size * elem_size;
-            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block_size);
-            nextdst += block_size * elem_size;
-            nextsrc += block_distance * elem_size;
         }
         }
+        memcpy((void*)nextdst, (void*)nextsrc, elem_size * block_size);
+        nextsrc += block_size * elem_size;
+        nextdst += block_distance * elem_size;
     }
     }
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_Variant_setCopyRange(const UA_Variant *src, UA_Variant *dst, void *data,
-                                      const UA_NumericRange range) {
-    // todo: don't copy the entire variant but only the retained parts
-    UA_StatusCode retval = UA_Variant_copy(src, dst);
+UA_StatusCode UA_EXPORT UA_Variant_setRangeCopy(UA_Variant *v, const void *dataArray, UA_Int32 dataArraySize,
+                                                const UA_NumericRange range) {
+    size_t count, block_size, block_distance, first_elem;
+    UA_StatusCode retval = testRangeWithVariant(v, range, &count, &block_size, &block_distance, &first_elem);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
-    retval = UA_Variant_setRange(dst, data, range);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_Variant_deleteMembers(dst);
-        return retval;
+    if((UA_Int32)count != dataArraySize)
+        return UA_STATUSCODE_BADINDEXRANGEINVALID;
+
+    size_t block_count = count / block_size;
+    size_t elem_size = v->type->memSize;
+    uintptr_t nextdst = (uintptr_t)v->data + (first_elem * elem_size);
+    uintptr_t nextsrc = (uintptr_t)dataArray;
+    if(v->type->fixedSize) {
+        for(size_t i = 0; i < block_count; i++) {
+            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block_size);
+            nextsrc += block_size * elem_size;
+            nextdst += block_distance * elem_size;
+        }
+    } else {
+        for(size_t i = 0; i < block_count; i++) {
+            for(size_t j = 0; j < block_size; j++) {
+                UA_deleteMembers((void*)nextdst, v->type);
+                UA_copy((void*)nextsrc, (void*)nextdst, v->type);
+                nextdst += elem_size;
+                nextsrc += elem_size;
+            }
+            nextdst += (block_distance - block_size) * elem_size;
+        }
     }
     }
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }

+ 1 - 1
src/ua_types_encoding_binary.c

@@ -1080,7 +1080,7 @@ UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *ds
         if(member->isArray) {
         if(member->isArray) {
             ptr += (member->padding >> 3);
             ptr += (member->padding >> 3);
             UA_Int32 *noElements = (UA_Int32*)ptr;
             UA_Int32 *noElements = (UA_Int32*)ptr;
-            UA_Int32 tempNoElements;
+            UA_Int32 tempNoElements = 0;
             retval |= UA_Int32_decodeBinary(src, offset, &tempNoElements);
             retval |= UA_Int32_decodeBinary(src, offset, &tempNoElements);
             if(retval)
             if(retval)
                 continue;
                 continue;

+ 15 - 1
src/ua_util.h

@@ -75,7 +75,21 @@
 # undef SLIST_ENTRY
 # undef SLIST_ENTRY
 # define RAND(SEED) (UA_UInt32)rand()
 # define RAND(SEED) (UA_UInt32)rand()
 #else
 #else
-# include <endian.h>
+# if !(defined htole16 && defined htole32 && defined htole64 && defined le16toh && defined le32toh && defined le64toh)
+#  include <endian.h>
+#  if !(defined htole16 && defined htole32 && defined htole64 && defined le16toh && defined le32toh && defined le64toh)
+#   if ( __BYTE_ORDER != __LITTLE_ENDIAN )
+#    error "Host byte order is not little-endian and no appropriate conversion functions are defined. (Have a look at ua_config.h)"
+#   else
+#    define htole16(x) x
+#    define htole32(x) x
+#    define htole64(x) x
+#    define le16toh(x) x
+#    define le32toh(x) x
+#    define le64toh(x) x
+#   endif
+#  endif
+# endif
 # include <sys/time.h>
 # include <sys/time.h>
 # define RAND(SEED) (UA_UInt32)rand_r(SEED)
 # define RAND(SEED) (UA_UInt32)rand_r(SEED)
 #endif
 #endif

+ 19 - 17
tests/CMakeLists.txt

@@ -9,7 +9,9 @@ find_package(Threads REQUIRED)
 set(LIBS ${CHECK_LIBRARIES})
 set(LIBS ${CHECK_LIBRARIES})
 if(NOT WIN32)
 if(NOT WIN32)
     list(APPEND LIBS rt pthread)
     list(APPEND LIBS rt pthread)
-endif(NOT WIN32)
+else()
+    list(APPEND LIBS ws2_32)
+endif()
 if(MULTITHREADING)
 if(MULTITHREADING)
     list(APPEND LIBS urcu-cds urcu urcu-common)
     list(APPEND LIBS urcu-cds urcu urcu-common)
 endif(MULTITHREADING)
 endif(MULTITHREADING)
@@ -47,21 +49,21 @@ add_test(nodestore ${CMAKE_CURRENT_BINARY_DIR}/check_nodestore)
 
 
 # test with canned interactions from files
 # test with canned interactions from files
 
 
-add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/client_HELOPN.bin
-                   PRE_BUILD
-                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/hex2bin.py ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_HELOPN.hex
-                                  ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_CreateActivateSession.hex
-                   DEPENDS ${PROJECT_SOURCE_DIR}/tools/hex2bin.py
-                           ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_HELOPN.hex)
+#add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/client_HELOPN.bin
+#                   PRE_BUILD
+#                   COMMAND python ${PROJECT_SOURCE_DIR}/tools/hex2bin.py ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_HELOPN.hex
+#                                  ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_CreateActivateSession.hex
+#                   DEPENDS ${PROJECT_SOURCE_DIR}/tools/hex2bin.py
+#                           ${CMAKE_CURRENT_SOURCE_DIR}/dumps/client_HELOPN.hex)
 
 
-set(check_fileinput_source check_server_interaction_fileinput.c testing_networklayers.c $<TARGET_OBJECTS:open62541-object>)
-if(NOT ENABLE_AMALGAMATION)
-    list(APPEND check_fileinput_source ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
-endif()
-add_executable(check_server_interaction_fileinput ${check_fileinput_source})
+#set(check_fileinput_source check_server_interaction_fileinput.c testing_networklayers.c $<TARGET_OBJECTS:open62541-object>)
+#if(NOT ENABLE_AMALGAMATION)
+#    list(APPEND check_fileinput_source ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
+#endif()
+#add_executable(check_server_interaction_fileinput ${check_fileinput_source})
 
 
-target_include_directories(check_server_interaction_fileinput PRIVATE ${PROJECT_SOURCE_DIR}/examples)
-target_include_directories(check_server_interaction_fileinput PRIVATE ${PROJECT_BINARY_DIR})
-target_link_libraries(check_server_interaction_fileinput ${LIBS})
-add_test(server_interaction_fileinput ${CMAKE_CURRENT_BINARY_DIR}/check_server_interaction_fileinput ${CMAKE_CURRENT_BINARY_DIR}/client_HELOPN.bin)
-add_custom_target(server_interaction_fileinput ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/client_HELOPN.bin)
+#target_include_directories(check_server_interaction_fileinput PRIVATE ${PROJECT_SOURCE_DIR}/examples)
+#target_include_directories(check_server_interaction_fileinput PRIVATE ${PROJECT_BINARY_DIR})
+#target_link_libraries(check_server_interaction_fileinput ${LIBS})
+#add_test(server_interaction_fileinput ${CMAKE_CURRENT_BINARY_DIR}/check_server_interaction_fileinput ${CMAKE_CURRENT_BINARY_DIR}/client_HELOPN.bin)
+#add_custom_target(server_interaction_fileinput ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/client_HELOPN.bin)

+ 16 - 4
tests/testing_networklayers.c

@@ -53,10 +53,9 @@ NetworkLayer_FileInput_getWork(NetworkLayer_FileInput *layer, UA_WorkItem **work
         
         
     *workItems = malloc(sizeof(UA_WorkItem));
     *workItems = malloc(sizeof(UA_WorkItem));
     UA_WorkItem *work = *workItems;
     UA_WorkItem *work = *workItems;
-    work->type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
-    work->work.binaryNetworkMessage.connection = &layer->connection;
-    work->work.binaryNetworkMessage.message = (UA_ByteString){.length = bytes_read, .data = (UA_Byte*)buf};
-
+    work->type = UA_WORKITEMTYPE_BINARYMESSAGE;
+    work->work.binaryMessage.connection = &layer->connection;
+    work->work.binaryMessage.message = (UA_ByteString){.length = bytes_read, .data = (UA_Byte*)buf};
     return 1;
     return 1;
 }
 }
 
 
@@ -70,6 +69,17 @@ static void NetworkLayer_FileInput_delete(NetworkLayer_FileInput *layer) {
 	free(layer);
 	free(layer);
 }
 }
 
 
+static UA_StatusCode NetworkLayer_FileInput_getBuffer(UA_Connection *connection, UA_ByteString *buf, size_t minSize) {
+    buf->data = malloc(minSize);
+    if(!buf->data)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    buf->length = minSize;
+    return UA_STATUSCODE_GOOD;
+}
+
+static void NetworkLayer_FileInput_releaseBuffer(UA_Connection *connection, UA_ByteString *buf) {
+    UA_ByteString_deleteMembers(buf);
+}
 
 
 UA_ServerNetworkLayer
 UA_ServerNetworkLayer
 ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCallback)(void),
 ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCallback)(void),
@@ -82,6 +92,8 @@ ServerNetworkLayerFileInput_new(UA_UInt32 files, char **filenames, void(*readCal
     layer->connection.channel = (void*)0;
     layer->connection.channel = (void*)0;
     layer->connection.close = (void (*)(UA_Connection*))closeCallback;
     layer->connection.close = (void (*)(UA_Connection*))closeCallback;
     layer->connection.write = (UA_StatusCode (*)(UA_Connection*, const UA_ByteString*))writeCallback;
     layer->connection.write = (UA_StatusCode (*)(UA_Connection*, const UA_ByteString*))writeCallback;
+    layer->connection.releaseBuffer = NetworkLayer_FileInput_releaseBuffer;
+    layer->connection.getBuffer = NetworkLayer_FileInput_getBuffer;
 
 
     layer->files = files;
     layer->files = files;
     layer->filenames = filenames;
     layer->filenames = filenames;

+ 0 - 20
tools/.deployDoxygen.sh

@@ -1,20 +0,0 @@
-#!/bin/bash
-
-#
-# This script is run by travis-ci and pushes generated
-# Doxygen docs to open62541-www
-#
-
-git fetch origin coverity_scan
-git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
-cd open62541-www
-git rm -rf doc
-cp -r ../build/doc ./
-git add -A doc/*
-git config --global user.email "open62541-travis-ci@users.noreply.github.com"
-git config --global user.name "Open62541 travis-ci"
-git config --global push.default simple
-git commit -am "doxygen updated by travis-ci"
-git push https://$GITAUTH@github.com/acplt/open62541-www
-cd ..
-rm -rf open62541-www

+ 59 - 0
tools/.deployGH.sh

@@ -0,0 +1,59 @@
+#!/bin/bash
+
+#
+# This script is run by travis-ci and pushes generated
+# Doxygen docs and single-source distributions to open62541-www
+#
+TAGSTOSAVE=50
+
+#current tag info
+TAG="$(git rev-parse --short=10 HEAD)"
+BRANCH="$(git log --pretty=format:"%d" --date=iso --abbrev=10 --all -1)"
+DATE="$(git log --pretty=format:"%ad" --date=iso --abbrev=10 --all -1)"
+COMMENT="$(git log --pretty=format:"%s" --date=iso --abbrev=10 --all -1)"
+
+git fetch origin coverity_scan
+git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
+cd open62541-www
+#hanndle releases
+cd releases
+if [ ! -e "$TAG.zip" ]; then
+#add the first line
+echo "<tr><td><a href='./$TAG.zip'>$TAG</a></td><td>$BRANCH</td><td>$DATE</td><td>$COMMENT</td></tr>" | cat - rawtable.txt > temp && mv temp rawtable.txt
+
+#keep top lines only
+head "-$TAGSTOSAVE" rawtable.txt > temp && mv temp rawtable.txt
+
+#compose the index file
+cat head.txt rawtable.txt foot.txt > index.html
+
+#create a zip for single-file release and copy the files
+cp ../../open62541.c .
+cp ../../open62541.h .
+zip -r "$TAG.zip" open62541.c open62541.h
+rm open62541.c
+rm open62541.h
+git add "$TAG.zip"
+
+echo "$TAG.zip" | cat - raw.txt > temp && mv temp raw.txt
+
+LINETOSTART=$((TAGSTOSAVE+1))
+#remove obsolete zips
+tail -n +"$LINETOSTART" raw.txt | xargs git rm
+
+#remove obsolete zips from list
+head "-$TAGSTOSAVE" raw.txt > temp && mv temp raw.txt
+fi
+cd ..
+
+#handle doc
+git rm -r -f doc
+cp -r ../doc ./
+git add -A doc/*
+git config --global user.email "open62541-travis-ci@users.noreply.github.com"
+git config --global user.name "Open62541 travis-ci"
+git config --global push.default simple
+git commit -am "gh-pages updated by travis-ci"
+git push https://$GITAUTH@github.com/acplt/open62541-www
+cd ..
+rm -rf open62541-www

+ 13 - 5
tools/amalgamate.py

@@ -1,8 +1,10 @@
 from __future__ import print_function
 from __future__ import print_function
 import re
 import re
 import argparse
 import argparse
+import os.path
 
 
 parser = argparse.ArgumentParser()
 parser = argparse.ArgumentParser()
+parser.add_argument('version', help='version to include')
 parser.add_argument('outfile', help='outfile w/o extension')
 parser.add_argument('outfile', help='outfile w/o extension')
 parser.add_argument('inputs', nargs='*', action='store', help='input filenames')
 parser.add_argument('inputs', nargs='*', action='store', help='input filenames')
 args = parser.parse_args()
 args = parser.parse_args()
@@ -30,8 +32,13 @@ for fname in args.inputs:
                     includes.append(inc)
                     includes.append(inc)
 
 
 file = open(args.outfile, 'w')
 file = open(args.outfile, 'w')
-file.write('''/*
- * Copyright (C) 2014 the contributors as stated in the AUTHORS file
+file.write('''/* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES 
+ * visit http://open62541.org/ for information about this software
+ * Git-Revision: %s
+ */
+ 
+ /*
+ * Copyright (C) 2015 the contributors as stated in the AUTHORS file
  *
  *
  * This file is part of open62541. open62541 is free software: you can
  * 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
  * redistribute it and/or modify it under the terms of the GNU Lesser General
@@ -43,9 +50,7 @@ file.write('''/*
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  * details.
  * details.
- */
-
-/* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES */\n\n''')
+ */\n\n''' % args.version)
 
 
 if not is_c:
 if not is_c:
     file.write('''#ifndef %s
     file.write('''#ifndef %s
@@ -73,6 +78,7 @@ else:
 for fname in args.inputs:
 for fname in args.inputs:
     if not "util.h" in fname:
     if not "util.h" in fname:
         with open(fname) as infile:
         with open(fname) as infile:
+            file.write("/*********************************** amalgamated original file \"" + fname + "\" ***********************************/\n")
             for line in infile:
             for line in infile:
                 inc_res = include_re.match(line)
                 inc_res = include_re.match(line)
                 guard_res = guard_re.match(line)
                 guard_res = guard_re.match(line)
@@ -87,3 +93,5 @@ if not is_c:
 
 
 #endif /* %s */''' % (outname.upper() + "_H_"))
 #endif /* %s */''' % (outname.upper() + "_H_"))
 file.close()
 file.close()
+
+print ("The size of "+args.outfile+" is "+ str(os.path.getsize(args.outfile)))

+ 6 - 2
tools/certs/create_self-signed.py

@@ -40,7 +40,7 @@ os.system("""openssl x509 -req \
 	-out localhost.crt \
 	-out localhost.crt \
 	-extensions v3_ca \
 	-extensions v3_ca \
 	-extfile localhost.cnf""")
 	-extfile localhost.cnf""")
-os.system("""openssl x509 -in localhost.crt -outform der -out localhost.der""")
+os.system("""openssl x509 -in localhost.crt -outform der -out server_cert.der""")
 #we will need these files later
 #we will need these files later
 os.remove("localhost.key") #we will need it later
 os.remove("localhost.key") #we will need it later
 os.remove("localhost.crt")
 os.remove("localhost.crt")
@@ -48,5 +48,9 @@ os.remove("localhost.csr")
 os.remove("ca.key")
 os.remove("ca.key")
 os.remove("ca.srl")
 os.remove("ca.srl")
 
 
-shutil.move("localhost.der", sys.argv[1])
+if os.path.isfile(os.path.join(sys.argv[1], "server_cert.der")):
+	os.remove(os.path.join(sys.argv[1], "server_cert.der"))
+shutil.move("server_cert.der", sys.argv[1])
+if os.path.isfile(os.path.join(sys.argv[1], "ca.crt")):
+	os.remove(os.path.join(sys.argv[1], "ca.crt"))
 shutil.move("ca.crt", sys.argv[1])
 shutil.move("ca.crt", sys.argv[1])

+ 3 - 3
tools/generate_datatypes.py

@@ -161,7 +161,7 @@ class EnumerationType(object):
 
 
     def typedef_c(self):
     def typedef_c(self):
         return "typedef enum { \n    " + \
         return "typedef enum { \n    " + \
-            ",\n    ".join(map(lambda (key,value) : key.upper() + " = " + value,self.elements.iteritems())) + \
+            ",\n    ".join(map(lambda kv : kv[0].upper() + " = " + kv[1], self.elements.iteritems())) + \
             "\n} " + self.name + ";"
             "\n} " + self.name + ";"
 
 
     def typelayout_c(self, namespace_0, description, outname):
     def typelayout_c(self, namespace_0, description, outname):
@@ -311,7 +311,7 @@ class StructType(object):
         return layout + "}"
         return layout + "}"
 
 
     def functions_c(self, typeTableName):
     def functions_c(self, typeTableName):
-        return '''#define %s_new() UA_new(%s)
+        return '''#define %s_new() (%s*)UA_new(%s)
 #define %s_init(p) UA_init(p, %s)
 #define %s_init(p) UA_init(p, %s)
 #define %s_delete(p) UA_delete(p, %s)
 #define %s_delete(p) UA_delete(p, %s)
 #define %s_deleteMembers(p) UA_deleteMembers(p, %s)
 #define %s_deleteMembers(p) UA_deleteMembers(p, %s)
@@ -319,7 +319,7 @@ class StructType(object):
 #define %s_calcSizeBinary(p) UA_calcSizeBinary(p, %s)
 #define %s_calcSizeBinary(p) UA_calcSizeBinary(p, %s)
 #define %s_encodeBinary(src, dst, offset) UA_encodeBinary(src, %s, dst, offset)
 #define %s_encodeBinary(src, dst, offset) UA_encodeBinary(src, %s, dst, offset)
 #define %s_decodeBinary(src, offset, dst) UA_decodeBinary(src, offset, dst, %s)''' % \
 #define %s_decodeBinary(src, offset, dst) UA_decodeBinary(src, offset, dst, %s)''' % \
-    tuple(itertools.chain(*itertools.repeat([self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 8)))
+    tuple([self.name] + list(itertools.chain(*itertools.repeat([self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 8))))
 
 
 def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
 def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
     '''Returns an ordered dict that maps names to types. The order is such that
     '''Returns an ordered dict that maps names to types. The order is such that

File diff suppressed because it is too large
+ 0 - 23008
tools/schema/Opc.Ua.NodeSet2.xml