瀏覽代碼

Merge remote-tracking branch 'upstream/master'

Oleksiy Vasylyev 9 年之前
父節點
當前提交
551251f0a3
共有 89 個文件被更改,包括 1937 次插入5436 次删除
  1. 7 7
      .travis.yml
  2. 264 217
      CMakeLists.txt
  3. 24 21
      README.md
  4. 3 3
      appveyor.yml
  5. 2 2
      deps/libc_string.c
  6. 0 2311
      doc/Doxyfile.in
  7. 0 194
      doc/DoxygenLayout.xml
  8. 45 59
      doc/building.rst
  9. 2 6
      doc/conf.py
  10. 11 3
      doc/datatypes.rst
  11. 0 110
      doc/mainpage.dox
  12. 0 336
      doc/style/doxygen.css
  13. 0 20
      doc/style/footer.html
  14. 0 19
      doc/style/header.html
  15. 0 4
      doc/style/jquery-1.11.1.min.js
  16. 0 58
      doc/style/load-style.js
  17. 1 1
      doc/tutorial_server_firstSteps.rst
  18. 20 16
      examples/CMakeLists.txt
  19. 5 5
      examples/client.c
  20. 3 2
      examples/client_firstSteps.c
  21. 0 696
      examples/client_legacy.c
  22. 7 16
      examples/client_stateless.c
  23. 37 24
      examples/server.c
  24. 11 7
      examples/server.cpp
  25. 22 13
      examples/server_datasource.c
  26. 11 11
      examples/server_firstSteps.c
  27. 18 13
      examples/server_method.c
  28. 10 6
      examples/server_nodeset.c
  29. 8 4
      examples/server_repeated_job.c
  30. 10 8
      examples/server_variable.c
  31. 1 1
      include/ua_client.h
  32. 1 1
      include/ua_client_highlevel.h
  33. 71 25
      include/ua_config.h.in
  34. 152 131
      include/ua_server.h
  35. 56 33
      include/ua_types.h
  36. 8 10
      src/client/ua_client.c
  37. 2 2
      src/client/ua_client_internal.h
  38. 3 3
      src/server/ua_nodes.c
  39. 1 1
      src/server/ua_nodes.h
  40. 1 1
      src/server/ua_nodestore.h
  41. 3 3
      src/server/ua_securechannel_manager.c
  42. 142 204
      src/server/ua_server.c
  43. 30 19
      src/server/ua_server_binary.c
  44. 21 26
      src/server/ua_server_internal.h
  45. 103 120
      src/server/ua_server_worker.c
  46. 11 6
      src/server/ua_services.h
  47. 34 29
      src/server/ua_services_attribute.c
  48. 4 4
      src/server/ua_services_call.c
  49. 48 11
      src/server/ua_services_discovery.c
  50. 81 55
      src/server/ua_services_nodemanagement.c
  51. 6 6
      src/server/ua_services_session.c
  52. 44 32
      src/server/ua_services_subscription.c
  53. 28 23
      src/server/ua_services_view.c
  54. 1 2
      src/server/ua_session_manager.c
  55. 10 7
      src/server/ua_subscription.c
  56. 1 28
      src/server/ua_subscription_manager.c
  57. 2 2
      src/ua_connection.c
  58. 2 2
      src/ua_securechannel.c
  59. 2 2
      src/ua_session.c
  60. 2 2
      src/ua_session.h
  61. 115 62
      src/ua_types.c
  62. 11 75
      src/ua_types_encoding_binary.c
  63. 12 3
      src/ua_util.h
  64. 0 0
      src_extra/logger_stdout.c
  65. 0 0
      src_extra/logger_stdout.h
  66. 72 60
      examples/networklayer_tcp.c
  67. 3 2
      examples/networklayer_tcp.h
  68. 1 1
      examples/networklayer_udp.c
  69. 0 0
      src_extra/networklayer_udp.h
  70. 4 4
      tests/CMakeLists.txt
  71. 23 0
      tests/check_builtin.c
  72. 19 19
      tests/check_nodestore.c
  73. 90 8
      tests/check_services_attributes.c
  74. 33 4
      tests/check_services_nodemanagement.c
  75. 0 20
      tools/.checkPorts.sh
  76. 0 20
      tools/.deployGH_doc.sh
  77. 0 54
      tools/.deployGH_release.sh
  78. 9 38
      tools/generate_datatypes.py
  79. 10 3
      tools/pyUANamespace/open62541_MacroHelper.py
  80. 15 17
      tools/pyUANamespace/ua_builtin_types.py
  81. 3 0
      tools/pyUANamespace/ua_namespace.py
  82. 4 2
      tools/pyUANamespace/ua_node_types.py
  83. 1 2
      tools/travis_linux_before_install.sh
  84. 44 40
      tools/travis_linux_script.sh
  85. 1 3
      tools/travis_osx_before_install.sh
  86. 12 16
      tools/travis_osx_script.sh
  87. 0 0
      tools/.coverity.sh
  88. 14 0
      tools/travis_push_doc.sh
  89. 49 0
      tools/travis_push_release.sh

+ 7 - 7
.travis.yml

@@ -25,15 +25,15 @@ matrix:
     - os: osx
       compiler: gcc
 before_install:
-- "if [ ${TRAVIS_OS_NAME} == 'linux' ]; then . ./tools/travis_linux_before_install.sh; fi"
-- "if [ ${TRAVIS_OS_NAME} == 'osx' ]; then . ./tools/travis_osx_before_install.sh; fi"
+- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis_linux_before_install.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis_osx_before_install.sh; fi
 script:
-- "if [ ${TRAVIS_OS_NAME} == 'linux' ]; then . ./tools/travis_linux_script.sh; fi"
-- "if [ ${TRAVIS_OS_NAME} == 'osx' ]; then . ./tools/travis_osx_script.sh; fi"
+- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis_linux_script.sh; fi
+- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis_osx_script.sh; fi
 after_success:
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master") ]]; then ./tools/.deployGH_doc.sh; fi
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" ) ]]; then ./tools/.deployGH_release.sh; fi
-- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master") ]]; then ./tools/.coverity.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis_push_doc.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" && ${TRAVIS_BRANCH} == "master" && ${TRAVIS_PULL_REQUEST} == "false" ) ]]; then sh ./tools/travis_push_coverity.sh; fi
+- if [[ ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "gcc" ) ]]; then sh ./tools/travis_push_release.sh; fi
 before_deploy:
 - rm build -rf && mkdir -p build && cd build
 - echo "Cross compile release build for Raspberry Pi"

+ 264 - 217
CMakeLists.txt

@@ -1,82 +1,171 @@
 cmake_minimum_required(VERSION 2.8.11)
-# set(CMAKE_VERBOSE_MAKEFILE ON)
-
 project(open62541 C)
+# set(CMAKE_VERBOSE_MAKEFILE ON)
 
-FIND_PACKAGE(PythonInterp REQUIRED)
+######################
+# Check Dependencies #
+######################
 
-# Find Python-lxml
-execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
+# Find Python and Python-lxml
+find_package(PythonInterp REQUIRED)
+execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
+                OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
+                OUTPUT_STRIP_TRAILING_WHITESPACE)
 if(NOT EXISTS "${PYTHON_SITE_PACKAGES}/lxml")
-    execute_process ( COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE)
+  execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))"
+                  OUTPUT_VARIABLE PYTHON_SITE_PACKAGES
+                  OUTPUT_STRIP_TRAILING_WHITESPACE)
     if(NOT EXISTS "${PYTHON_SITE_PACKAGES}/lxml")
-        message( FATAL_ERROR "Python-lxml is not installed.")
+        message(FATAL_ERROR "Python-lxml is not installed.")
     endif()
 endif()
 
+# Check for git
 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 "unknown--git-commit-id-unknown")
-        message( STATUS "Git failed (not a repo, or no tags). Build will not contain git revision info." )
+  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 "unknown--git-commit-id-unknown")
+        message(STATUS "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} )
+        string(REPLACE "\n" "" GIT_COMMIT_ID ${GIT_COM_ID} )
     endif()
 else()
-    set( GIT_COMMIT_ID "unknown--no-git-found")
-    message( STATUS "Git not found. Build will not contain git revision info." )
+    set(GIT_COMMIT_ID "unknown--no-git-found")
+    message(STATUS "Git not found. Build will not contain git revision info." )
 endif()
 add_definitions("-DVERSION=${GIT_COMMIT_ID}")
 
-MESSAGE (STATUS "Git version: "  ${GIT_COMMIT_ID})
+message(STATUS "Git version: "  ${GIT_COMMIT_ID})
 
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
 
+####################################
+# Build Type and Compiler Settings #
+####################################
+
 # Set default build type.
 if(NOT CMAKE_BUILD_TYPE)
-    message(STATUS "CMAKE_BUILD_TYPE not given; setting to 'RelWithDebInfo'.")
-    set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Choose the type of build." FORCE)
+    message(STATUS "CMAKE_BUILD_TYPE not given; setting to 'Debug'.")
+    set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build." FORCE)
 endif()
 
+# Collect libraries
+list(APPEND open62541_LIBRARIES "")
+
 # compiler flags
 if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
     add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat -Wno-unused-parameter
-                      -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
-                      -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes #-Wshadow #-Wconversion
-                      -Winit-self -Wuninitialized -Wformat-security -Wformat-nonliteral)
-    # binary size reduction settings
+                    -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
+                    -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes #-Wshadow #-Wconversion
+                    -Winit-self -Wuninitialized -Wformat-security -Wformat-nonliteral)
+
+  # library linking
+  set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
+  if(NOT WIN32 AND NOT CYGWIN)
+	add_definitions(-fvisibility=hidden -fPIC)
+    if(NOT APPLE)
+      set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
+    endif()
+  endif()
+
+  # Debug
+  if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+	#add_definitions(-fsanitize=address)
+    #list(APPEND open62541_LIBRARIES asan)
+
+	#add_definitions(-fsanitize=undefined)
+    #list(APPEND open62541_LIBRARIES ubsan)
+
+  elseif(CMAKE_BUILD_TYPE STREQUAL "MinSizeRel" OR
+         CMAKE_BUILD_TYPE STREQUAL "Release")
     add_definitions(-ffunction-sections -fdata-sections -fno-stack-protector -fno-unwind-tables
                     -fno-asynchronous-unwind-tables -fno-math-errno -fmerge-all-constants -fno-ident)
-  if(APPLE)
+    set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -s")
+    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s")
+    if(APPLE)
       set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-dead_strip")
       set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
-  else()
+    else()
       set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,--gc-sections")
       set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
-  endif()
-  set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
-	if(NOT WIN32 AND NOT CYGWIN)
-	    add_definitions(-fvisibility=hidden -fPIC)
-      if(NOT APPLE)
+      if(NOT WIN32 AND NOT CYGWIN)
         # these settings reduce the binary size by ~2kb
         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")
-        set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -s")
-        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s")
-    endif()
-    if(APPLE)
-        set(CMAKE_MACOSX_RPATH 1)
-        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DARWIN_C_SOURCE=1")
     endif()
+  endif()
+  
+  if(APPLE)
+    set(CMAKE_MACOSX_RPATH 1)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_DARWIN_C_SOURCE=1")
+  endif()
 elseif(MSVC)
     set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
     set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
 endif()
 
-# build the main library
+############
+# Settings #
+############
+
+# Options
+set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")
+option(UA_ENABLE_SUBSCRIPTIONS "Enable compilation of subscription and monitoring support." OFF)
+option(UA_ENABLE_METHODCALLS "Enable CallMethod/MethodCall service set" OFF)
+option(UA_ENABLE_MULTITHREADING "Enable multithreading" OFF)
+option(UA_ENABLE_NODEMANAGEMENT "Enable dynamic addition and removal of nodes" ON)
+option(UA_ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
+option(UA_ENABLE_COVERAGE "Enable gcov coverage" OFF)
+if(UA_ENABLE_COVERAGE)
+  set(CMAKE_BUILD_TYPE DEBUG)
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
+  set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
+endif()
+
+# Advanced options
+option(UA_ENABLE_TYPENAMES "Add the type and member names to the UA_DataType structure" OFF)
+mark_as_advanced(UA_ENABLE_TYPENAMES)
+
+option(UA_ENABLE_GENERATE_NAMESPACE0 "Generate and load UA XML Namespace 0 definition" OFF)
+
+option(UA_ENABLE_EMBEDDED_LIBC "Target has no libc, use internal definitions" OFF)
+mark_as_advanced(UA_ENABLE_EMBEDDED_LIBC)
+
+option(UA_ENABLE_EXTERNAL_NAMESPACES "Enable namespace handling by an external component (experimental)" OFF)
+mark_as_advanced(UA_ENABLE_EXTERNAL_NAMESPACES)
+
+option(UA_ENABLE_NONSTANDARD_STATELESS "Enable stateless extension" OFF)
+mark_as_advanced(UA_ENABLE_NONSTANDARD_STATELESS)
+
+option(UA_ENABLE_NONSTANDARD_UDP "Enable udp extension" OFF)
+mark_as_advanced(UA_ENABLE_NONSTANDARD_UDP)
+if(UA_ENABLE_NONSTANDARD_UDP)
+  set(UA_ENABLE_NONSTANDARD_STATELESS ON)
+endif()
+
+# Build Targets
+option(UA_BUILD_EXAMPLESERVER "Build the example server" OFF)
+option(UA_BUILD_EXAMPLECLIENT "Build a test client" OFF)
+option(UA_BUILD_UNIT_TESTS "Run unit tests after building" OFF)
+option(UA_BUILD_EXAMPLES "Build example servers and clients" OFF)
+option(UA_BUILD_DOCUMENTATION "Generate doxygen/sphinx documentation" OFF)
+
+# Advanced Build Targets
+option(UA_BUILD_SELFSIGNED_CERTIFICATE "Generate self-signed certificate" OFF)
+mark_as_advanced(UA_BUILD_SELFSIGNED_CERTIFICATE)
+
+#########################
+# Generate Main Library #
+#########################
+
+file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
+include_directories(${PROJECT_BINARY_DIR}/src_generated) #needed to locate an include of examples/server_nodeset.c
+configure_file("include/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
+
 set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_statuscodes.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
@@ -89,11 +178,11 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server_external_ns.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.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
-                     ${PROJECT_SOURCE_DIR}/deps/queue.h
+                     ${PROJECT_SOURCE_DIR}/src_extra/networklayer_tcp.h
+                     ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.h)
+set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_util.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
@@ -128,81 +217,103 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
-                ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c
-                ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
+                ${PROJECT_SOURCE_DIR}/src_extra/networklayer_tcp.c
+                ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.c
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
                 ##TODO: make client stuff optional
 
-## generate code from xml definitions
-file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
+if(UA_ENABLE_METHODCALLS)
+  list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_services_call.c)
+endif()
 
-option(ENABLE_TYPEINTROSPECTION "Add the type and member names to the internal structures" OFF)
-mark_as_advanced(ENABLE_TYPEINTROSPECTION)
-if(ENABLE_TYPEINTROSPECTION)
-  set(generate_typeintrospection "--typeintrospection")
+if(UA_ENABLE_EMBEDDED_LIBC)
+  list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/deps/libc_string.c)
+endif()
+
+if(UA_ENABLE_MULTITHREADING)
+  find_package(Threads REQUIRED)
+  list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_concurrent.c)
 else()
-  set(generate_typeintrospection "")
+  list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.c)
 endif()
 
-option(UA_EMBEDDED_LIBC "Target has no libc, use internal definitions" OFF)
-if(UA_EMBEDDED_LIBC)
-  list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/deps/libc_string.c)
+set(generate_typeintrospection "")
+if(UA_ENABLE_TYPENAMES)
+  set(generate_typeintrospection "--typeintrospection")
 endif()
 
-option(ENABLE_SUBSCRIPTIONS "Enable compilation of subscription and monitoring support." OFF)
-if(ENABLE_SUBSCRIPTIONS)
-  set(ENABLE_SUBSCRIPTIONS ON) #to propagate it to the config file
+set(generate_subscriptiontypes "")
+if(UA_ENABLE_SUBSCRIPTIONS)
   list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
                           ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.c
                           ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.c
                           ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel_subscriptions.c)
-  ##append subscription headers at before ua_session.
+  #append subscription headers at before ua_session
   list(FIND internal_headers "${PROJECT_SOURCE_DIR}/src/ua_session.h" UaSessionPos)
   list(INSERT internal_headers  ${UaSessionPos} ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.h
                                                 ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.h)
+  set(generate_subscriptiontypes "--enable-subscription-types=1")
+endif()
 
-  add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
-                            ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
-                            ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
-                     PRE_BUILD
-                     COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py --enable-subscription-types=1 ${generate_typeintrospection} --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
-                     DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
-                             ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
-                             ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
-else()
+if(UA_ENABLE_GENERATE_NAMESPACE0)
+  set(GENERATE_NAMESPACE0_FILE "Opc.Ua.NodeSet2.xml" CACHE STRING "Namespace definition XML file")
+  set_property(CACHE GENERATE_NAMESPACE0_FILE PROPERTY STRINGS Opc.Ua.NodeSet2.xml Opc.Ua.NodeSet2.Minimal.xml)
+  list(APPEND internal_headers ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h)
+  list(APPEND lib_sources ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.c)
+endif()
+
+#########################
+# Generate source files #
+#########################
+
+# standard data types
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                    PRE_BUILD
-                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py ${generate_typeintrospection} --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv 0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
+                                                ${generate_subscriptiontypes}
+                                                ${generate_typeintrospection}
+                                                --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv
+                                                0
+                                                ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
+                                                ${PROJECT_BINARY_DIR}/src_generated/ua_types
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
-endif()
 
+# transport data types
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                    PRE_BUILD
-                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py ${generate_typeintrospection} --ns0-types-xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd 1 ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_transport
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
+                                                ${generate_typeintrospection}
+                                                --ns0-types-xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
+                                                1
+                                                ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd
+                                                ${PROJECT_BINARY_DIR}/src_generated/ua_transport
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd)
 
+# nodeids
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                    PRE_BUILD
-                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_nodeids.py ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_nodeids.py
+                                                ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv
+                                                ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_nodeids.py
                            ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
 
-option(ENABLE_GENERATE_NAMESPACE0 "Generate and load UA XML Namespace 0 definition" OFF)
-if(ENABLE_GENERATE_NAMESPACE0)
-add_definitions(-DENABLE_GENERATE_NAMESPACE0)
-set(GENERATE_NAMESPACE0_FILE "Opc.Ua.NodeSet2.xml" CACHE STRING "Namespace definition XML file")
-set_property(CACHE GENERATE_NAMESPACE0_FILE PROPERTY STRINGS Opc.Ua.NodeSet2.xml Opc.Ua.NodeSet2.Minimal.xml)
+# generated namespace 0
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.c
                           ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h
                    PRE_BUILD
-                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_AssumeExternal.txt -s description -b ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist.txt ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/${GENERATE_NAMESPACE0_FILE} ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
+                                                -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_AssumeExternal.txt
+                                                -s description -b ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist.txt
+                                                ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/${GENERATE_NAMESPACE0_FILE}
+                                                ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated
                    DEPENDS ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/${GENERATE_NAMESPACE0_FILE}
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py
@@ -212,81 +323,35 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_g
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_namespace.py
                            ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/ua_node_types.py)
 
-list(APPEND internal_headers ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.h)
-list(APPEND lib_sources ${PROJECT_BINARY_DIR}/src_generated/ua_namespaceinit_generated.c)
-endif()
-
-## logging
-set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")
-
-# Enable Methodcall service
-option(ENABLE_METHODCALLS "Enable CallMethod/MethodCall service set" OFF)
-if(ENABLE_METHODCALLS)
-    set(ENABLE_METHODCALLS ON) #to propagate it to the config file
-    list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_services_call.c)
-endif()
-
-## multithreading
-option(ENABLE_MULTITHREADING "Enable multithreading (experimental)" OFF)
-if(ENABLE_MULTITHREADING)
-	set(UA_MULTITHREADING ON) #to propagate it to the config file
-    find_package(Threads REQUIRED)
-    list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_concurrent.c)
-else()
-    list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.c)
-endif()
-
-option(ENABLE_EXTERNAL_NAMESPACES "Enable namespace handling by an external component (experimental)" OFF)
-if(ENABLE_EXTERNAL_NAMESPACES)
-    add_definitions(-DUA_EXTERNAL_NAMESPACES)
-endif()
-
-## enable dynamic nodeset
-option(ENABLE_NODEMANAGEMENT "Enable dynamic addition and removal of nodes" ON)
-if(ENABLE_NODEMANAGEMENT)
-    add_definitions(-DENABLE_NODEMANAGEMENT)
-endif()
-
-## set the precompiler flags
-configure_file("include/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
-
-## extensions
-option(EXTENSION_UDP "Enable udp extension" OFF)
-if(EXTENSION_UDP)
-	add_definitions(-DEXTENSION_STATELESS)
-	message(STATUS "Extensions: enabling udp")
-	add_definitions(-DEXTENSION_UDP)
-	add_executable(exampleServerUDP $<TARGET_OBJECTS:open62541-object> examples/networklayer_udp.c examples/server_udp.c)
-  if(ENABLE_MULTITHREADING)
-  	target_link_libraries(exampleServerUDP urcu-cds urcu urcu-common)
-  endif()
-  if (NOT APPLE)
-      target_link_libraries(exampleServerUDP rt)
-  endif()
-endif()
-
-option(ENABLE_LEGACY "Enable LEGACY code" OFF)
-mark_as_advanced(ENABLE_LEGACY)
-
-option(EXTENSION_STATELESS "Enable stateless extension" OFF)
-if(EXTENSION_STATELESS)
-	message(STATUS "Extensions: enabling stateless")
-	add_definitions(-DEXTENSION_STATELESS)
-endif()
-
-option(ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
+# single-file release
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h
-               PRE_BUILD
-               COMMAND ${PYTHON_EXECUTABLE} ${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})
+                   PRE_BUILD
+                   COMMAND ${PYTHON_EXECUTABLE} ${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
-               COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${GIT_COMMIT_ID} ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
-                                            ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources}
-               DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${internal_headers} ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc ${lib_sources})
-
-if(ENABLE_AMALGAMATION)
+                   PRE_BUILD
+                   COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
+                                                ${GIT_COMMIT_ID}
+                                                ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
+                                                ${internal_headers}
+                                                ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc
+                                                ${lib_sources}
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
+                           ${internal_headers}
+                           ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_hash.inc
+                           ${lib_sources})
+
+#################
+# Build Targets #
+#################
+
+# build shared library
+if(UA_ENABLE_AMALGAMATION)
     add_custom_target(amalgamation ALL DEPENDS ${PROJECT_BINARY_DIR}/open62541.h ${PROJECT_BINARY_DIR}/open62541.c)
     add_library(open62541-object OBJECT ${PROJECT_BINARY_DIR}/open62541.c ${PROJECT_BINARY_DIR}/open62541.h)
     include_directories(${PROJECT_BINARY_DIR})
@@ -294,46 +359,30 @@ else()
     add_definitions(-DUA_NO_AMALGAMATION)
     add_library(open62541-object OBJECT ${lib_sources} ${internal_headers} ${exported_headers})
     include_directories(${PROJECT_SOURCE_DIR}/include)
-    include_directories(${PROJECT_SOURCE_DIR}/deps)
     include_directories(${PROJECT_SOURCE_DIR}/src)
+    include_directories(${PROJECT_SOURCE_DIR}/src_extra)
+    include_directories(${PROJECT_SOURCE_DIR}/deps)
 endif()
-include_directories(${PROJECT_BINARY_DIR}/src_generated) #needed to locate an include of examples/server_nodeset.c
 target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING)
-
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
 add_library(open62541-static STATIC $<TARGET_OBJECTS:open62541-object>)
 target_compile_definitions(open62541 PRIVATE -DUA_DYNAMIC_LINKING)
 target_compile_definitions(open62541-static PRIVATE -DUA_DYNAMIC_LINKING)
+target_link_libraries(open62541-static ${open62541_LIBRARIES})
 if(WIN32)
-    # since networklayer_tcp is linked into the amalgate
-    target_link_libraries(open62541 ws2_32)
-    target_link_libraries(open62541-static ws2_32)
-endif()
-if(ENABLE_MULTITHREADING)
-  target_link_libraries(open62541 urcu-cds urcu urcu-common pthread)
-  target_link_libraries(open62541-static urcu-cds urcu urcu-common pthread)
-endif()
-
-# coverage
-option(ENABLE_COVERAGE "Enable gcov coverage" OFF)
-if(ENABLE_COVERAGE)
-    message(STATUS "Enabling gcov support")
-    set(CMAKE_BUILD_TYPE DEBUG)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
-    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
+  target_link_libraries(open62541 ws2_32)
+  target_link_libraries(open62541-static ws2_32)
 endif()
 
-# build example server
-option(BUILD_EXAMPLESERVER "Build the example server" OFF)
-if(BUILD_EXAMPLESERVER)
+if(UA_BUILD_EXAMPLESERVER)
     set(server_source $<TARGET_OBJECTS:open62541-object>)
     add_executable(server_static examples/server.c ${server_source})
     add_executable(server examples/server.c)
-    if(ENABLE_AMALGAMATION)
+    if(UA_ENABLE_AMALGAMATION)
        ADD_DEPENDENCIES(server amalgamation)
     endif()
-    target_link_libraries(server open62541)
+    target_link_libraries(server ${open62541_LIBRARIES} open62541)
+    target_link_libraries(server_static ${open62541_LIBRARIES})
     if(WIN32)
         target_link_libraries(server_static ws2_32)
         target_link_libraries(server ws2_32)
@@ -341,15 +390,24 @@ if(BUILD_EXAMPLESERVER)
         target_link_libraries(server_static rt)
         target_link_libraries(server rt)
     endif()
-    if(ENABLE_MULTITHREADING)
+    if(UA_ENABLE_MULTITHREADING)
         target_link_libraries(server_static urcu-cds urcu urcu-common pthread)
         target_link_libraries(server urcu-cds urcu urcu-common pthread)
     endif()
+
+    if(UA_ENABLE_NONSTANDARD_UDP)
+      add_executable(exampleServerUDP $<TARGET_OBJECTS:open62541-object> examples/networklayer_udp.c examples/server_udp.c)
+      target_link_libraries(exampleServerUDP ${open62541_LIBRARIES} open62541)
+      if(UA_ENABLE_MULTITHREADING)
+  	    target_link_libraries(exampleServerUDP urcu-cds urcu urcu-common)
+      endif()
+      if (NOT APPLE)
+        target_link_libraries(exampleServerUDP rt)
+      endif()
+    endif()
 endif()
 
-## self-signed certificates
-option(GENERATE_SELFSIGNED "Generate self-signed certificates" OFF)
-if(GENERATE_SELFSIGNED)
+if(UA_BUILD_SELFSIGNED_CERTIFICATE)
     message(STATUS "Enabling self-signed certificates")
     find_package(OpenSSL REQUIRED)
     add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/server_cert.der
@@ -360,17 +418,17 @@ if(GENERATE_SELFSIGNED)
     add_custom_target(selfsigned ALL DEPENDS ${PROJECT_BINARY_DIR}/server_cert.der ${PROJECT_BINARY_DIR}/ca.crt)
 endif()
 
-# build example client
-option(BUILD_EXAMPLECLIENT "Build a test client" OFF)
-if(BUILD_EXAMPLECLIENT)
+if(UA_BUILD_EXAMPLECLIENT)
 	add_definitions(-DBENCHMARK)
     set(client_source $<TARGET_OBJECTS:open62541-object>)
 	add_executable(client_static examples/client.c ${client_source})
     add_executable(client examples/client.c)
-	if(ENABLE_AMALGAMATION)
+	if(UA_ENABLE_AMALGAMATION)
+	   ADD_DEPENDENCIES(client_static amalgamation)
 	   ADD_DEPENDENCIES(client amalgamation)
 	endif()
-	target_link_libraries(client open62541)
+	target_link_libraries(client_static ${open62541_LIBRARIES})
+	target_link_libraries(client open62541 ${open62541_LIBRARIES})
     if(WIN32)
         target_link_libraries(client_static ws2_32)
         target_link_libraries(client ws2_32)
@@ -378,36 +436,31 @@ if(BUILD_EXAMPLECLIENT)
         target_link_libraries(client_static rt)
         target_link_libraries(client rt)
     endif()
-    if(ENABLE_MULTITHREADING)
+    if(UA_ENABLE_MULTITHREADING)
         target_link_libraries(client_static urcu-cds urcu urcu-common pthread)
         target_link_libraries(client urcu-cds urcu urcu-common pthread)
     endif()
-    if(EXTENSION_STATELESS AND NOT ENABLE_AMALGAMATION)
+    if(UA_ENABLE_NONSTANDARD_STATELESS AND NOT UA_ENABLE_AMALGAMATION)
         add_executable(client_stateless examples/client_stateless.c ${client_source})
-        if(ENABLE_MULTITHREADING)
+	    target_link_libraries(client_stateless open62541 ${open62541_LIBRARIES})
+        if(UA_ENABLE_MULTITHREADING)
             target_link_libraries(client_stateless urcu-cds urcu urcu-common pthread)
         endif()
     endif()
-    if(ENABLE_LEGACY AND NOT ENABLE_AMALGAMATION)
-    	add_executable(client_legacy ${PROJECT_SOURCE_DIR}/examples/client_legacy.c $<TARGET_OBJECTS:open62541-object>)
-		target_link_libraries(client_legacy ${LIBS})
-	endif()
 endif()
 
-# build unit tests
-option(BUILD_UNIT_TESTS "Run unit tests after building" OFF)
-if(BUILD_UNIT_TESTS)
-	add_definitions(-DBUILD_UNIT_TESTS)
+if(UA_BUILD_UNIT_TESTS)
+	add_definitions(-DUA_BUILD_UNIT_TESTS)
     enable_testing()
     add_subdirectory(tests)
 endif()
 
-option(BUILD_EXAMPLES "Build example servers and clients" OFF)
-if(BUILD_EXAMPLES)
+if(UA_BUILD_EXAMPLES)
     #add_subdirectory(examples)
     #FIXME: we had problem with static linking for msvs, here a quick and dirty workaround
     #http://stackoverflow.com/questions/3704374/linking-error-lnk2019-in-msvc-unresolved-symbols-with-imp-prefix-but-shoul
     #http://stackoverflow.com/questions/1089828/same-header-file-for-both-dll-and-static-library
+	list(APPEND LIBS ${open62541_LIBRARIES})
     if(NOT WIN32)
 		list(APPEND LIBS pthread)
 		if (NOT APPLE)
@@ -416,9 +469,9 @@ if(BUILD_EXAMPLES)
 	else()
 		list(APPEND LIBS ws2_32)
 	endif()
-	if(ENABLE_MULTITHREADING)
+	if(UA_ENABLE_MULTITHREADING)
 		list(APPEND LIBS urcu-cds urcu urcu-common)
-	endif(ENABLE_MULTITHREADING)
+	endif(UA_ENABLE_MULTITHREADING)
 	
     add_executable(server_variable ${PROJECT_SOURCE_DIR}/examples/server_variable.c $<TARGET_OBJECTS:open62541-object>)
 	target_link_libraries(server_variable ${LIBS})
@@ -440,7 +493,11 @@ if(BUILD_EXAMPLES)
 
 	add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/nodeset.h ${PROJECT_BINARY_DIR}/src_generated/nodeset.c
 					   PRE_BUILD
-					   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/Opc.Ua.NodeSet2.xml ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml ${PROJECT_BINARY_DIR}/src_generated/nodeset
+					   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
+                                                    -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
+                                                    ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/Opc.Ua.NodeSet2.xml
+                                                    ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml
+                                                    ${PROJECT_BINARY_DIR}/src_generated/nodeset
 					   DEPENDS ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
 					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/logger.py
 					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/open62541_MacroHelper.py
@@ -451,35 +508,25 @@ if(BUILD_EXAMPLES)
 					           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
 					           ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml)
 					   
-	add_executable(server_nodeset ${PROJECT_SOURCE_DIR}/examples/server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c $<TARGET_OBJECTS:open62541-object>)
+	add_executable(server_nodeset ${PROJECT_SOURCE_DIR}/examples/server_nodeset.c
+                                  ${PROJECT_BINARY_DIR}/src_generated/nodeset.c
+                                  $<TARGET_OBJECTS:open62541-object>)
 	target_link_libraries(server_nodeset ${LIBS})
 
-	if(ENABLE_METHODCALLS)
+	if(UA_ENABLE_METHODCALLS)
 	  add_executable(server_method ${PROJECT_SOURCE_DIR}/examples/server_method.c $<TARGET_OBJECTS:open62541-object>)
 	  target_link_libraries(server_method ${LIBS})
 	endif()
 endif()
 
 # build documentation
-option(BUILD_DOCUMENTATION "Generate doxygen/sphinx documentation" OFF)
-if(BUILD_DOCUMENTATION)
-    find_package(Doxygen REQUIRED)
+if(UA_BUILD_DOCUMENTATION)
     find_package(Sphinx REQUIRED)
-    configure_file(${PROJECT_SOURCE_DIR}/doc/Doxyfile.in ${PROJECT_BINARY_DIR}/Doxyfile @ONLY)
-    configure_file(${PROJECT_SOURCE_DIR}/doc/conf.py ${PROJECT_BINARY_DIR}/conf.py @ONLY)
-    add_custom_target(doxygen
-                      ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile
-                      WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
-                      COMMENT "Generating API documentation with Doxygen")
-    add_custom_target(latex ${SPHINX_EXECUTABLE}
-      -b latex -c "${PROJECT_BINARY_DIR}"
-      "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc/sphinx"
-      DEPENDS doxygen
+    add_custom_target(doc_latex ${SPHINX_EXECUTABLE}
+      -b latex -c "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc_latex"
       COMMENT "Building LaTeX sources for documentation with Sphinx")
     add_custom_target(doc ${SPHINX_EXECUTABLE}
-      -b html -c "${PROJECT_BINARY_DIR}"
-      "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc/sphinx"
-      COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/doc/open62541_html.png" "${PROJECT_BINARY_DIR}/doc/sphinx/_static/"
-      DEPENDS doxygen
+      -b html -c "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_SOURCE_DIR}/doc" "${PROJECT_BINARY_DIR}/doc"
+      COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/doc/open62541_html.png" "${PROJECT_BINARY_DIR}/doc/_static/"
       COMMENT "Building HTML documentation with Sphinx")
 endif()

文件差異過大導致無法顯示
+ 24 - 21
README.md


+ 3 - 3
appveyor.yml

@@ -7,14 +7,14 @@ build_script:
 - cd c:\projects\open62541
 - md build
 - cd build
-- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DBUILD_EXAMPLES:BOOL=ON -G"Visual Studio 12 2013" ..
+- cmake -DUA_BUILD_EXAMPLESERVER:BOOL=ON -DUA_BUILD_EXAMPLECLIENT:BOOL=ON -DUA_BUILD_EXAMPLES:BOOL=ON -G"Visual Studio 12 2013" ..
 - msbuild open62541.sln
 - echo "Testing amalgamation"
 - cd ..
 - rd /s /q build
 - md build
 - cd build
-- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DBUILD_EXAMPLES:BOOL=ON -DENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013" ..
+- cmake -DUA_BUILD_EXAMPLESERVER:BOOL=ON -DUA_BUILD_EXAMPLECLIENT:BOOL=ON -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013" ..
 - msbuild open62541.sln 
 - cp C:\projects\open62541\build\open62541.c C:\projects\open62541\build\Debug\open62541.c
 - cp C:\projects\open62541\build\open62541.h C:\projects\open62541\build\Debug\open62541.h
@@ -22,7 +22,7 @@ build_script:
 - echo "Win 64 build"
 - md build64
 - cd build64
-- cmake -DBUILD_EXAMPLESERVER:BOOL=ON -DBUILD_EXAMPLECLIENT:BOOL=ON -DBUILD_EXAMPLES:BOOL=ON -DENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013 Win64" ..
+- cmake -DUA_BUILD_EXAMPLESERVER:BOOL=ON -DUA_BUILD_EXAMPLECLIENT:BOOL=ON -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_AMALGAMATION:BOOL=ON -G"Visual Studio 12 2013 Win64" ..
 - msbuild open62541.sln 
 - cp C:\projects\open62541\build64\open62541.c C:\projects\open62541\build64\Debug\open62541.c
 - cp C:\projects\open62541\build64\open62541.h C:\projects\open62541\build64\Debug\open62541.h

+ 2 - 2
deps/libc_string.c

@@ -3,9 +3,9 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
  */
 
-#include <stddef.h>
+#include "ua_config.h"
 
-void *memcpy(void * UA_RESTRICT dest, const void *UA_RESTRICT src, size_t n) {
+void *memcpy(void *UA_RESTRICT dest, const void *UA_RESTRICT src, size_t n) {
 	unsigned char *d = dest;
 	const unsigned char *s = src;
 	while(n--)

文件差異過大導致無法顯示
+ 0 - 2311
doc/Doxyfile.in


+ 0 - 194
doc/DoxygenLayout.xml

@@ -1,194 +0,0 @@
-<doxygenlayout version="1.0">
-  <!-- Generated by doxygen 1.8.6 -->
-  <!-- Navigation index tabs for HTML output -->
-  <navindex>
-    <tab type="mainpage" visible="yes" title=""/>
-    <tab type="pages" visible="yes" title="" intro=""/>
-    <tab type="modules" visible="yes" title="" intro=""/>
-    <tab type="namespaces" visible="no" title="">
-      <tab type="namespacelist" visible="yes" title="" intro=""/>
-      <tab type="namespacemembers" visible="yes" title="" intro=""/>
-    </tab>
-    <tab type="classes" visible="no" title="">
-      <tab type="classlist" visible="yes" title="" intro=""/>
-      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
-      <tab type="hierarchy" visible="yes" title="" intro=""/>
-      <tab type="classmembers" visible="yes" title="" intro=""/>
-    </tab>
-    <tab type="files" visible="yes" title="">
-      <tab type="filelist" visible="yes" title="" intro=""/>
-      <tab type="globals" visible="yes" title="" intro=""/>
-    </tab>
-    <tab type="examples" visible="no" title="" intro=""/>  
-  </navindex>
-
-  <!-- Layout definition for a class page -->
-  <class>
-    <briefdescription visible="yes"/>
-    <includes visible="$SHOW_INCLUDE_FILES"/>
-    <inheritancegraph visible="$CLASS_GRAPH"/>
-    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
-    <memberdecl>
-      <nestedclasses visible="yes" title=""/>
-      <publictypes title=""/>
-      <services title=""/>
-      <interfaces title=""/>
-      <publicslots title=""/>
-      <signals title=""/>
-      <publicmethods title=""/>
-      <publicstaticmethods title=""/>
-      <publicattributes title=""/>
-      <publicstaticattributes title=""/>
-      <protectedtypes title=""/>
-      <protectedslots title=""/>
-      <protectedmethods title=""/>
-      <protectedstaticmethods title=""/>
-      <protectedattributes title=""/>
-      <protectedstaticattributes title=""/>
-      <packagetypes title=""/>
-      <packagemethods title=""/>
-      <packagestaticmethods title=""/>
-      <packageattributes title=""/>
-      <packagestaticattributes title=""/>
-      <properties title=""/>
-      <events title=""/>
-      <privatetypes title=""/>
-      <privateslots title=""/>
-      <privatemethods title=""/>
-      <privatestaticmethods title=""/>
-      <privateattributes title=""/>
-      <privatestaticattributes title=""/>
-      <friends title=""/>
-      <related title="" subtitle=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <inlineclasses title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <services title=""/>
-      <interfaces title=""/>
-      <constructors title=""/>
-      <functions title=""/>
-      <related title=""/>
-      <variables title=""/>
-      <properties title=""/>
-      <events title=""/>
-    </memberdef>
-    <allmemberslink visible="yes"/>
-    <usedfiles visible="$SHOW_USED_FILES"/>
-    <authorsection visible="yes"/>
-  </class>
-
-  <!-- Layout definition for a namespace page -->
-  <namespace>
-    <briefdescription visible="yes"/>
-    <memberdecl>
-      <nestednamespaces visible="yes" title=""/>
-      <constantgroups visible="yes" title=""/>
-      <classes visible="yes" title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <inlineclasses title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-    </memberdef>
-    <authorsection visible="yes"/>
-  </namespace>
-
-  <!-- Layout definition for a file page -->
-  <file>
-    <briefdescription visible="yes"/>
-    <includes visible="$SHOW_INCLUDE_FILES"/>
-    <includegraph visible="$INCLUDE_GRAPH"/>
-    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
-    <sourcelink visible="yes"/>
-    <memberdecl>
-      <classes visible="yes" title=""/>
-      <namespaces visible="yes" title=""/>
-      <constantgroups visible="yes" title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-    <memberdef>
-      <inlineclasses title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <functions title=""/>
-      <variables title=""/>
-    </memberdef>
-    <authorsection/>
-  </file>
-
-  <!-- Layout definition for a group page -->
-  <group>
-    <briefdescription visible="no"/>
-    <groupgraph visible="$GROUP_GRAPHS"/>
-    <detaileddescription title=""/>
-    <memberdecl>
-      <nestedgroups visible="yes" title=""/>
-      <dirs visible="yes" title=""/>
-      <files visible="yes" title=""/>
-      <namespaces visible="yes" title=""/>
-      <classes visible="yes" title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <enumvalues title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <signals title=""/>
-      <publicslots title=""/>
-      <protectedslots title=""/>
-      <privateslots title=""/>
-      <events title=""/>
-      <properties title=""/>
-      <friends title=""/>
-      <membergroups visible="yes"/>
-    </memberdecl>
-    <memberdef>
-      <pagedocs/>
-      <inlineclasses title=""/>
-      <defines title=""/>
-      <typedefs title=""/>
-      <enums title=""/>
-      <enumvalues title=""/>
-      <functions title=""/>
-      <variables title=""/>
-      <signals title=""/>
-      <publicslots title=""/>
-      <protectedslots title=""/>
-      <privateslots title=""/>
-      <events title=""/>
-      <properties title=""/>
-      <friends title=""/>
-    </memberdef>
-    <authorsection visible="no"/>
-  </group>
-
-  <!-- Layout definition for a directory page -->
-  <directory>
-    <briefdescription visible="yes"/>
-    <directorygraph visible="yes"/>
-    <memberdecl>
-      <dirs visible="yes"/>
-      <files visible="yes"/>
-    </memberdecl>
-    <detaileddescription title=""/>
-  </directory>
-</doxygenlayout>

+ 45 - 59
doc/building.rst

@@ -87,91 +87,77 @@ Follow Ubuntu instructions without the ``apt-get`` commands as these are taken c
 Build Options
 -------------
 
-Generic CMake options
-~~~~~~~~~~~~~~~~~~~~~
-
 **CMAKE_BUILD_TYPE**
   - RelWithDebInfo: -O2 optimization with debug symbols
   - Release: -O2 optimization without debug symbols
   - Debug: -O0 optimization with debug symbols
   - MinSizeRel: -Os optimization without debug symbols
 
-BUILD_* group
+**UA_LOGLEVEL**
+   The level of logging events that are reported
+   - 600: Fatal and all below
+   - 500: Error and all below
+   - 400: Error and all below
+   - 300: Info and all below
+   - 200: Debug and all below
+   - 100: Trace and all below
+
+Further options that are not inherited from the CMake configuration are defined
+in ua_config.h. Usually there is no need to adjust them.
+
+**UA_NON_LITTLEENDIAN_ARCHITECTURE**
+   Big-endian or mixed endian platform
+**UA_MIXED_ENDIAN**
+   Mixed-endian platform (e.g., ARM7TDMI)
+
+UA_BUILD_* group
 ~~~~~~~~~~~~~
 
 By default only the shared object libopen62541.so or the library open62541.dll
 and open62541.dll.a resp. open62541.lib are build. Additional artifacts can be
 specified by the following options:
 
-**BUILD_DOCUMENTATION**
+**UA_BUILD_DOCUMENTATION**
    Generate documentation with doxygen
-**BUILD_EXAMPLECLIENT**
+**UA_BUILD_EXAMPLECLIENT**
    Compile example clients from client.c. There are a static and a dynamic binary client and client_static, respectively
-**BUILD_EXAMPLESERVER**
+**UA_BUILD_EXAMPLESERVER**
    Compile example server from server.c There are a static and a dynamic binary server and server_static, respectively
-**BUILD_UNIT_TESTS**
+**UA_BUILD_UNIT_TESTS**
    Compile unit tests with Check framework. The tests can be executed with make test
-**BUILD_EXAMPLES**
+**UA_BUILD_EXAMPLES**
    Compile specific examples from https://github.com/acplt/open62541/blob/master/examples/
+**UA_BUILD_SELFIGNED_CERTIFICATE**
+   Generate a self-signed certificate for the server (openSSL required)
 
-ENABLE_* group
+UA_ENABLE_* group
 ~~~~~~~~~~~~~~
 
 This group contains build options related to the supported OPC UA features.
 
-**ENABLE_NODEMANAGEMENT**
-   Node management services (adding and removing nodes and references) in server and client
-**ENABLE_AMALGAMATION**
+**UA_ENABLE_SUBSCRIPTIONS**
+   Enable subscriptions
+**UA_ENABLE_METHODCALLS**
+   Enable method calls in server and client
+**UA_ENABLE_NODEMANAGEMENT**
+   Node management services (adding and removing nodes and references) at runtime in server and client
+**UA_ENABLE_AMALGAMATION**
    Compile a single-file release files open62541.c and open62541.h
-**ENABLE_COVERAGE**
+**UA_ENABLE_MULTITHREADING**
+   Enable multi-threading support (experimental)
+**UA_ENABLE_COVERAGE**
    Measure the coverage of unit tests
-**ENABLE_EXTERNAL_NAMESPACES**
+
+Some options are marked as advanced. The advanced options need to be toggled to
+be visible in the cmake GUIs.
+
+**UA_ENABLE_EXTERNAL_NAMESPACES**
    Enable external namespaces in server
-**ENABLE_GNERATE_NAMESPACE0**
+**UA_ENABLE_GENERATE_NAMESPACE0**
    Enable automatic generation of NS0
-**GENERATE_NAMESPACE0_FILE**
+**UA_ENABLE_GENERATE_NAMESPACE0_FILE**
    File for NS0 generation from namespace0 folder. Default value is Opc.Ua.NodeSet2.xml
-**ENABLE_METHODCALL**
-   Enable method calls in server and client
-**ENABLE_MULTITHREADING**
-   Enable multi-threading support (experimental)
-**ENABLE_SUBSCRIPTIONS**
-   Enable subscriptions
-**GENERATE_SELFSIGNED**
-   Generate a self-signed certificate for the server (openSSL required)
-
-EXTENSION_* group
-~~~~~~~~~~~~~~~~~
-
-Extensions mark experimental extensions that are not compliant with IEC 62541 or
-other OPC UA clients
-
-**EXTENSION_STATELESS**
+**UA_ENABLE_NONSTANDARD_STATELESS**
    Stateless service calls
-**EXTENSION_UDP**
+**UA_ENABLE_NONSTANDARD_UDP**
    UDP network layer
-
-UA_* group
-~~~~~~~~~~
-
-**UA_LOGLEVEL**
-   The level of logging events that are reported
-   - 600: Fatal and all below
-   - 500: Error and all below
-   - 400: Error and all below
-   - 300: Info and all below
-   - 200: Debug and all below
-   - 100: Trace and all below
-
-C precompiler configuration options
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Options that are not inherited from the CMake configuration are defined in
-ua_config.h. Usually there is no need to adjust them.
-
-**UA_NON_LITTLEENDIAN_ARCHITECTURE**
-   Big-endian or mixed endian platform
-**UA_MIXED_ENDIAN**
-   Mixed-endian platform (e.g., ARM7TDMI)
-**UA_ALIGNED_MEMORY_ACCESS**
-   Platform with aligned memory access only (some ARM processors, e.g. Cortex M3/M4 ARM7TDMI etc.)

+ 2 - 6
doc/conf.py

@@ -29,11 +29,7 @@ import shlex
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ['breathe']
-
-breathe_projects = { "open62541-breathe": "doc/xml/" }
-breathe_default_project = "open62541-breathe"
-breathe_domain_by_extension = {"h" : "c", "c" : "c"}
+extensions = []
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -232,7 +228,7 @@ latex_documents = [
 
 # The name of an image file (relative to this directory) to place at the top of
 # the title page.
-latex_logo = "doc/open62541.png"
+latex_logo = "open62541.png"
 
 # For "manual" documents, if this is true, then toplevel headings are parts,
 # not chapters.

+ 11 - 3
doc/datatypes.rst

@@ -89,6 +89,13 @@ An integer value between 0 and 4,294,967,295.
 
   typedef uint32_t UA_UInt32;
 
+The following functions and definitions are used with UA_UInt32.
+
+.. code-block:: c
+
+  /* do not use for cryptographic entropy */
+  UA_UInt32 UA_UInt32_random(void);
+
 UA_Int64
 ^^^^^^^^
 
@@ -154,9 +161,9 @@ The following functions and definitions are used with UA_DateTime.
       UA_UInt16 year;
   } UA_DateTimeStruct;
 
-  UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
+  UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime time);
 
-  UA_String UA_EXPORT UA_DateTime_toString(UA_DateTime time);
+  UA_String UA_DateTime_toString(UA_DateTime time);
 
 UA_Guid
 ^^^^^^^
@@ -178,7 +185,8 @@ The following functions and definitions are used with UA_Guid.
 
   UA_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
 
-  UA_Guid UA_Guid_random(UA_UInt32 *seed);
+  /* do not use for cryptographic entropy */
+  UA_Guid UA_Guid_random();
 
 UA_String
 ^^^^^^^^^

+ 0 - 110
doc/mainpage.dox

@@ -1,110 +0,0 @@
-/**
-\mainpage Open62541 Developer Documentation
-
-<a href="http://en.wikipedia.org/wiki/OPC_Unified_Architecture">OPC UA</a> (short for OPC Unified
-Architecture) is a protocol for industrial communication and has been standardized in the IEC62541.
-At its core, OPC UA defines a set of services to interact with a server-side object-oriented
-information model. Besides the service-calls initiated by the client, push-notification of remote
-events (such as data changes) can be negotiated with the server. The client/server interaction is
-mapped either to a binary encoding and TCP-based transmission or to SOAP-based webservices. As of
-late, OPC UA is marketed as the one standard for non-realtime industrial communication.
-
-We believe that it is best to understand OPC UA <em>from the inside out</em>, building upon conceptually
-simple first principles. After establishing a first understanding, we go on explaining how these
-principles are realized in detail. Examples are given based on the <em>open62541</em> implementation of the
-standard.
-
-<h2>OPC UA, a collection of services</h2>
-
-In OPC UA, all communication is based on service calls, each consisting of a request and a response
-message. Be careful to note the difference between services and methods. Services are pre-defined in
-the standard and cannot be changed. But you can use the <em>Call</em> service to invoke user-defined
-methods on the server.
-
-For completeness, the following tables contain all services defined in the standard. Do not bother
-with their details yet. We will introduce the different services later in the text. In open62541,
-each service is implemented in a single function. See the \ref services section for details.
-
-<b>Establishing communication</b>
-
-<table>
-<tr> <th>Discovery Service Set </th><th>SecureChannel Service Set </th><th>Session Service Set </th></tr>
-<tr> <td>FindServers </td><td>OpenSecureChannel </td><td>CreateSession </td></tr>
-<tr> <td>GetEndpoints </td><td>CloseSecureChannel </td><td>ActivateSession </td></tr>
-<tr> <td>RegisterServer </td><td></td><td>CloseSession </td></tr>
-<tr> <td></td><td></td><td>Cancel </td></tr>
-</table>
-
-<b>Interaction with the information model</b>
-
-<table>
-<tr> <th>NodeManagement Service Set </th><th>View Service Set </th><th>Query Service Set </th><th>Attribute Service Set </th><th>Method Service Set  </th></tr>
-<tr> <td>AddNodes </td><td>Browse </td><td>QueryFirst </td><td>Read </td><td>Call </td></tr>
-<tr> <td>AddReferences </td><td>BrowseNext </td><td>QueryNext </td><td>HistoryRead </td><td></td></tr>
-<tr> <td>DeleteNodes </td><td>TranslateBrowsePathsToNodeIds </td><td></td><td>Write </td><td></td></tr>
-<tr> <td>DeleteReferences </td><td>RegisterNodes </td><td></td><td>HistoryUpdate </td><td></td></tr>
-<tr> <td></td><td>UnregisterNodes </td><td></td><td></td><td></td></tr>
-</table>
-
-<b>Notifications</b>
-
-<table>
-<tr> <th>MonitoredItem Service Set </th><th>Subscription Service Set  </th></tr>
-<tr> <td>CreateMonitoredItems </td><td>CreateSubscription </td></tr>
-<tr> <td>ModifyMonitoredItems </td><td>ModifySubscription </td></tr>
-<tr> <td>SetMonitoringMode </td><td>SetPublishingMode </td></tr>
-<tr> <td>SetTriggering </td><td>Publish </td></tr>
-<tr> <td>DeleteMonitoredItems </td><td>Republish </td></tr>
-<tr> <td></td><td>TransferSubscription </td></tr>
-<tr> <td></td><td>DeleteSubscription </td></tr>
-</table>
-
-<h2>OPC UA, a web of nodes</h2>
-
-The information model in each OPC UA server is a web of interconnected nodes. There are eight
-different types of nodes. Depending on its type, every node contains different attributes. Some
-attributes, such as the <em>NodeId</em> (unique identifier) and the <em>BrowseName</em>, are
-contained in all node types.
-
-<table>
-<tr> <td>ReferenceTypeNode</td> <td>MethodNode</td> </tr>
-<tr> <td>DataTypeNode</td> <td>ObjectTypeNode</td> </tr>
-<tr> <td>VariableTypeNode</td> <td>ObjectNode</td> </tr>
-<tr> <td>VariableNode</td> <td>ViewNode</td> </tr>
-</table>
-                                                                                                            
-Nodes are interconnected by directed reference-triples of the form <dfn>(nodeid, referencetype,
-target-nodeid)</dfn>. Therefore an OPC UA information model is easiest imagined as a <em>web of nodes</em>.
-Reference types can be
-- standard- or user-defined and
-- either non-hierarchical (e.g., indicating the type of a variable-node) or hierarchical (e.g., indicating a parent-child relationship).
-
-<h2>OPC UA, a protocol</h2>
-
-The OPC UA protocol (both binary and XML-based) is based on 25 <em>built-in</em> datatypes. In
-open62541, these are defined in ua_types.h.
-
-<table>
-<tr> <td>Boolean</td> <td>Float</td> <td>StatusCode</td> </tr>
-<tr> <td>SByte</td> <td>Double</td> <td>QualifiedName</td> </tr>
-<tr> <td>Byte</td> <td>String</td> <td>LocalizedText</td> </tr>
-<tr> <td>Int16</td> <td>DateTime</td> <td>ExtensionObject</td> </tr>
-<tr> <td>UInt16</td> <td>Guid</td> <td>DataValue</td> </tr>
-<tr> <td>Int32</td> <td>ByteString</td> <td>Variant</td> </tr>
-<tr> <td>UInt32</td> <td>XmlElement</td> <td>DiagnosticInfo</td> </tr>
-<tr> <td>Int64</td> <td>NodeId</td> <td> </td> </tr>
-<tr> <td>UInt64</td> <td>ExpandedNodeId</td> <td> </td> </tr>
-</table>
-
-The builtin datatypes are combined into more complex structures. When the structure contains an array,
-then the size of the array is stored in an Int32 value just before the array itself. A size of -1
-indicates an undefined array. Positive sizes (and zero) have the usual semantics.
-
-Most importantly, every service has a request and a response message defined as such a data
-structure. The entire OPC UA protocol revolves around the exchange of these request and response
-messages. Their exact definitions can be looked up here:
-https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml. In open62541, we autogenerate the
-C-structs to handle the standard-defined structures automatically. See ua_types_generated.h for
-comparison.
-
-*/

文件差異過大導致無法顯示
+ 0 - 336
doc/style/doxygen.css


+ 0 - 20
doc/style/footer.html

@@ -1,20 +0,0 @@
-<!-- start footer part -->
-<!--BEGIN GENERATE_TREEVIEW-->
-<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
-  <ul>
-    $navpath
-    <li class="footer">$generatedby
-    <a href="http://www.doxygen.org/index.html">
-    <img class="footer" src="doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
-  </ul>
-</div>
-<!--END GENERATE_TREEVIEW-->
-<!--BEGIN !GENERATE_TREEVIEW-->
-<address class="footer"><small>
-$generatedby &#160;<a href="http://www.doxygen.org/index.html">
-<img class="footer" src="doxygen.png" alt="doxygen"/>
-</a> $doxygenversion
-</small></address>
-<!--END !GENERATE_TREEVIEW-->
-</body>
-</html>

+ 0 - 19
doc/style/header.html

@@ -1,19 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
-<meta http-equiv="X-UA-Compatible" content="IE=9"/>
-<meta name="generator" content="Doxygen $doxygenversion"/>
-<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
-<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
-<script type="text/javascript" src="jquery-1.11.1.min.js"></script>
-<script type="text/javascript" src="dynsections.js"></script>
-<script type="text/javascript" src="load-style.js"></script>
-$treeview
-$search
-$mathjax
-<link href="doxygen.css" rel="stylesheet" type="text/css" />
-</head>
-<body>
-<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
-

文件差異過大導致無法顯示
+ 0 - 4
doc/style/jquery-1.11.1.min.js


+ 0 - 58
doc/style/load-style.js

@@ -1,58 +0,0 @@
-$( document ).ready(function() {
-
-	$('#top > div > ul > li > a').wrapInner("<b></b>");
-
-	$("div.header").prepend("<h2></h2>");
-	$("div.header > h2").text($("div.title").text());
-	$("div.headertitle").remove();
-	$("#nav-path").remove();
-	
-	$("body").wrapInner("<div class='container'><div class='row'><div class='col-md-12'></div></div></div>");
-	$("ul.tablist").addClass("nav nav-pills nav-justified");
-	$("ul.tablist").css("margin-top", "0.5em");
-	$("ul.tablist").css("margin-bottom", "0.5em");
-	$("li.current").addClass("active");
-	$(".contents").wrapInner("<div class='panel panel-default' style='margin-top:1em;'><div class='panel-body'></div></div>");
-	$(".contents").find("h2.groupheader:first").remove();
-
-	$("iframe").attr("scrolling", "yes");
-	
-	$('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> ');
-	$('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> ');
-
-	// dirty workaround since doxygen 1.7 doesn't set table ids
-	$("table").each(function() {
-		if($(this).find("tbody > tr > td.indexkey").length > 0) {
-			$(this).addClass("table table-striped");
-		}
-	});
-	
-	$("table.params").addClass("table");
-	$("div.ingroups").wrapInner("<small></small>");
-	$("div.levels").css("margin", "0.5em");
-	$("div.levels > span").addClass("btn btn-default btn-xs");
-	$("div.levels > span").css("margin-right", "0.25em");
-	
-	$("table.directory").addClass("table table-striped");
-	$("div.summary > a").addClass("btn btn-default btn-xs");
-	$("table.fieldtable").addClass("table");
-	$(".fragment").addClass("well");
-	$(".memitem").addClass("panel panel-default");
-	$(".memproto").addClass("panel-heading");
-	$(".memdoc").addClass("panel-body");
-	$("span.mlabel").addClass("label label-info");
-	
-	$("table.memberdecls").addClass("table");
-	$("[class^=memitem]").addClass("active");
-	$("td.memSeparator").remove()
-	
-	$("div.ah").addClass("btn btn-default");
-	$("span.mlabels").addClass("pull-right");
-	$("table.mlabels").css("width", "100%")
-	$("td.mlabels-right").addClass("pull-right");
-
-	$("div.ttc").addClass("panel panel-info");
-	$("div.ttname").addClass("panel-heading");
-	$("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
-});
-

+ 1 - 1
doc/tutorial_server_firstSteps.rst

@@ -292,7 +292,7 @@ If you build your stack with the above two options, you will enable the example
 Unfortunately, these examples include just about everything the stack can do... which makes them rather bad examples for newcomers seeking an easy introduction. They are also dynamically configured by the CMake options, so they might be a bit more difficult to read. Non the less you can find any of the concepts demonstrated here in these examples as well and you can build them like so (and this is what you will see when you run them)::
 
    :open62541/build> make clean
-   :open62541/build> cmake -BUILD_EXAMPLECLIENT=On -BUILD_EXAMPLESERVER=On ../
+   :open62541/build> cmake -DBUILD_EXAMPLECLIENT=On -DBUILD_EXAMPLESERVER=On ../
    :open62541/build> make
    :open62541/build> ./server &
    [07/28/2015 21:42:07.977.352] info/communication        Listening on opc.tcp://Cassandra:16664

+ 20 - 16
examples/CMakeLists.txt

@@ -10,9 +10,9 @@ if(NOT WIN32)
 else()
     list(APPEND LIBS ws2_32)
 endif()
-if(ENABLE_MULTITHREADING)
+if(UA_ENABLE_MULTITHREADING)
     list(APPEND LIBS urcu-cds urcu urcu-common)
-endif(ENABLE_MULTITHREADING)
+endif()
 
 # add_executable(server_readspeed server_readspeed.c)
 # target_link_libraries(server_readspeed ${LIBS})
@@ -29,25 +29,29 @@ target_link_libraries(server_firstSteps ${LIBS})
 add_executable(client_firstSteps client_firstSteps.c)
 target_link_libraries(client_firstSteps ${LIBS})
 
-if(NOT ENABLE_AMALGAMATION)
+if(NOT UA_ENABLE_AMALGAMATION)
 	add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/nodeset.h ${PROJECT_BINARY_DIR}/src_generated/nodeset.c
-		           PRE_BUILD
-		           COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/Opc.Ua.NodeSet2.xml ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml ${PROJECT_BINARY_DIR}/src_generated/nodeset
-		           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
-		                   ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
-		                   ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml)
-		           
+		               PRE_BUILD
+		               COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.py
+                                                    -i ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
+                                                    ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/Opc.Ua.NodeSet2.xml
+                                                    ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml
+                                                    ${PROJECT_BINARY_DIR}/src_generated/nodeset
+   		                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
+		                        ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/NodeID_Blacklist_FullNS0.txt
+		                        ${PROJECT_SOURCE_DIR}/examples/server_nodeset.xml)
+		                      
 	add_executable(server_nodeset server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c)
 	target_link_libraries(server_nodeset ${LIBS})
 endif()
 
-if(ENABLE_METHODCALLS)
+if(UA_ENABLE_METHODCALLS)
   add_executable(server_method server_method.c)
   target_link_libraries(server_method ${LIBS})
 endif()

+ 5 - 5
examples/client.c

@@ -21,7 +21,7 @@ static void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value) {
 
 int main(int argc, char *argv[]) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
-    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
+    UA_StatusCode retval = UA_Client_connect(client, UA_ClientConnectionTCP,
                                              "opc.tcp://localhost:16664");
 
     if(retval != UA_STATUSCODE_GOOD) {
@@ -61,7 +61,7 @@ int main(int argc, char *argv[]) {
     UA_BrowseRequest_deleteMembers(&bReq);
     UA_BrowseResponse_deleteMembers(&bResp);
     
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     // Create a subscription with interval 0 (immediate)...
     UA_UInt32 subId;
     UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_standard, &subId);
@@ -125,7 +125,7 @@ int main(int argc, char *argv[]) {
     UA_WriteRequest_deleteMembers(&wReq);
     UA_WriteResponse_deleteMembers(&wResp);
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     // Take another look at the.answer... this should call the handler.
     UA_Client_Subscriptions_manuallySendPublishRequest(client);
     
@@ -134,7 +134,7 @@ int main(int argc, char *argv[]) {
         printf("Subscription removed\n");
 #endif
     
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     /* Note:  This example requires Namespace 0 Node 11489 (ServerType -> GetMonitoredItems) 
        FIXME: Provide a namespace 0 independant example on the server side
      */
@@ -157,7 +157,7 @@ int main(int argc, char *argv[]) {
 
 #endif
 
-#ifdef ENABLE_NODEMANAGEMENT 
+#ifdef UA_ENABLE_NODEMANAGEMENT 
     /* New ReferenceType */
     UA_NodeId ref_id;
     UA_ReferenceTypeAttributes ref_attr;

+ 3 - 2
examples/client_firstSteps.c

@@ -14,7 +14,8 @@
 
 int main(void) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
-    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664");
+    UA_StatusCode retval = UA_Client_connect(client, UA_ClientConnectionTCP,
+                                             "opc.tcp://localhost:16664");
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         return retval;
@@ -48,5 +49,5 @@ int main(void) {
 
     UA_Client_disconnect(client);
     UA_Client_delete(client);
-    return 0;
+    return UA_STATUSCODE_GOOD;
 }

+ 0 - 696
examples/client_legacy.c

@@ -1,696 +0,0 @@
-/*
- C ECHO client example using sockets
-
- This is an example client for internal benchmarks. It works, but is not ready
- for serious use. We do not really check any of the returns from the server.
- */
-#include <stdio.h> //printf
-#include <string.h> //strlen
-#include <sys/socket.h> //socket
-#include <arpa/inet.h> //inet_addr
-#include <unistd.h> // for close
-#include <stdlib.h> // pulls in declaration of malloc, free
-
-//this legacy stuff can not be build with amalgamation options, since it need internal APIs
-#include "ua_util.h"
-#include "ua_transport_generated_encoding_binary.h"
-#include "ua_types_generated_encoding_binary.h"
-
-typedef struct ConnectionInfo {
-    UA_Int32 socket;
-    UA_UInt32 channelId;
-    UA_SequenceHeader sequenceHdr;
-    UA_NodeId authenticationToken;
-    UA_UInt32 tokenId;
-    UA_UInt32 reqestHandle;
-} ConnectionInfo;
-
-static UA_Int32 sendHello(UA_Int32 sock, UA_String *endpointURL) {
-
-    UA_TcpMessageHeader messageHeader;
-    messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_HELF;
-
-    UA_TcpHelloMessage hello;
-    UA_String_copy(endpointURL, &hello.endpointUrl);
-    hello.maxChunkCount = 1;
-    hello.maxMessageSize = 16777216;
-    hello.protocolVersion = 0;
-    hello.receiveBufferSize = 65536;
-    hello.sendBufferSize = 65536;
-
-    UA_ByteString message;
-    UA_ByteString_newMembers(&message, 1024);
-
-    size_t offset = 0;
-    UA_TcpMessageHeader_encodeBinary((UA_TcpMessageHeader const*) &messageHeader, &message, &offset);
-    UA_TcpHelloMessage_encodeBinary((UA_TcpHelloMessage const*) &hello, &message, &offset);
-    messageHeader.messageSize = offset;
-
-    offset = 0;
-    UA_TcpMessageHeader_encodeBinary((UA_TcpMessageHeader const*) &messageHeader, &message, &offset);
-    UA_TcpHelloMessage_encodeBinary((UA_TcpHelloMessage const*) &hello, &message, &offset);
-
-    UA_Int32 sendret = send(sock, message.data, offset, 0);
-
-    UA_ByteString_deleteMembers(&message);
-    free(hello.endpointUrl.data);
-    if (sendret < 0)
-        return 1;
-    return 0;
-}
-
-static int sendOpenSecureChannel(UA_Int32 sock) {
-    UA_TcpMessageHeader msghdr;
-    msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
-
-    UA_UInt32 secureChannelId = 0;
-    UA_String securityPolicy;
-    securityPolicy = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
-
-    UA_String senderCert;
-    senderCert.data = NULL;
-    senderCert.length = -1;
-
-    UA_String receiverCertThumb;
-    receiverCertThumb.data = NULL;
-    receiverCertThumb.length = -1;
-
-    UA_UInt32 sequenceNumber = 51;
-
-    UA_UInt32 requestId = 1;
-
-    UA_NodeId type;
-    type.identifier.numeric = 446; // id of opensecurechannelrequest
-    type.identifierType = UA_NODEIDTYPE_NUMERIC;
-    type.namespaceIndex = 0;
-
-    UA_OpenSecureChannelRequest opnSecRq;
-    UA_OpenSecureChannelRequest_init(&opnSecRq);
-    opnSecRq.requestHeader.timestamp = UA_DateTime_now();
-    UA_ByteString_newMembers(&opnSecRq.clientNonce, 1);
-    opnSecRq.clientNonce.data[0] = 0;
-    opnSecRq.clientProtocolVersion = 0;
-    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;
-
-    msghdr.messageSize = 135; // todo: compute the message size from the actual content
-
-    UA_ByteString message;
-    UA_ByteString_newMembers(&message, 1000);
-    size_t offset = 0;
-    UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-    UA_UInt32_encodeBinary(&secureChannelId, &message, &offset);
-    UA_String_encodeBinary(&securityPolicy, &message, &offset);
-    UA_String_encodeBinary(&senderCert, &message, &offset);
-    UA_String_encodeBinary(&receiverCertThumb, &message, &offset);
-    UA_UInt32_encodeBinary(&sequenceNumber, &message, &offset);
-    UA_UInt32_encodeBinary(&requestId, &message, &offset);
-    UA_NodeId_encodeBinary(&type, &message, &offset);
-    UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
-
-    UA_OpenSecureChannelRequest_deleteMembers(&opnSecRq);
-    //UA_String_deleteMembers(&securityPolicy);
-
-    UA_Int32 sendret = send(sock, message.data, offset, 0);
-    UA_ByteString_deleteMembers(&message);
-    if (sendret < 0) {
-        printf("send opensecurechannel failed");
-        return 1;
-    }
-    return 0;
-}
-
-static UA_Int32 sendCreateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber,
-        UA_UInt32 requestId, UA_String *endpointUrl) {
-    UA_ByteString message;
-    UA_ByteString_newMembers(&message, 65536);
-    UA_UInt32 tmpChannelId = channelId;
-    size_t offset = 0;
-
-    UA_TcpMessageHeader msghdr;
-    msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-
-    UA_NodeId type;
-    type.identifier.numeric = 461;
-    type.identifierType = UA_NODEIDTYPE_NUMERIC;
-    type.namespaceIndex = 0;
-
-    UA_CreateSessionRequest rq;
-    UA_CreateSessionRequest_init(&rq);
-    rq.requestHeader.requestHandle = 1;
-    rq.requestHeader.timestamp = UA_DateTime_now();
-    rq.requestHeader.timeoutHint = 10000;
-    rq.requestHeader.authenticationToken.identifier.numeric = 10;
-    rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
-    rq.requestHeader.authenticationToken.namespaceIndex = 10;
-    UA_String_copy(endpointUrl, &rq.endpointUrl);
-    rq.sessionName = UA_STRING("mysession");
-    rq.clientCertificate = UA_STRING("abcd");
-    UA_ByteString_newMembers(&rq.clientNonce, 1);
-    rq.clientNonce.data[0] = 0;
-    rq.requestedSessionTimeout = 1200000;
-    rq.maxResponseMessageSize = UA_INT32_MAX;
-
-    //workaround to get length calculated
-    offset = 0;
-    UA_CreateSessionRequest_encodeBinary(&rq, &message, &offset);
-    UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-    UA_NodeId_encodeBinary(&type, &message, &offset);
-    msghdr.messageSize = 16 + offset;
-    offset = 0;
-
-    UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-    UA_UInt32_encodeBinary(&tmpChannelId, &message, &offset);
-    UA_UInt32_encodeBinary(&tokenId, &message, &offset);
-    UA_UInt32_encodeBinary(&sequenceNumber, &message, &offset);
-    UA_UInt32_encodeBinary(&requestId, &message, &offset);
-    UA_NodeId_encodeBinary(&type, &message, &offset);
-    UA_CreateSessionRequest_encodeBinary(&rq, &message, &offset);
-
-    UA_Int32 sendret = send(sock, message.data, offset, 0);
-    UA_ByteString_deleteMembers(&message);
-    //fixme: potential leak
-    //UA_CreateSessionRequest_deleteMembers(&rq);
-    if (sendret < 0) {
-        printf("send opensecurechannel failed");
-        return 1;
-    }
-    return 0;
-}
-
-static UA_Int32 closeSession(ConnectionInfo *connectionInfo) {
-    size_t offset = 0;
-
-    UA_ByteString message;
-    UA_ByteString_newMembers(&message, 65536);
-
-    UA_CloseSessionRequest rq;
-    UA_CloseSessionRequest_init(&rq);
-
-    rq.requestHeader.requestHandle = connectionInfo->reqestHandle++;
-    rq.requestHeader.timestamp = UA_DateTime_now();
-    rq.requestHeader.timeoutHint = 10000;
-    rq.requestHeader.authenticationToken = connectionInfo->authenticationToken;
-    rq.deleteSubscriptions = UA_TRUE;
-
-    UA_TcpMessageHeader msghdr;
-    msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-
-    UA_NodeId type;
-    type.identifier.numeric = 473;
-    type.identifierType = UA_NODEIDTYPE_NUMERIC;
-    type.namespaceIndex = 0;
-
-    //workaround to get length calculated
-    offset = 0;
-    UA_CloseSessionRequest_encodeBinary(&rq, &message, &offset);
-    UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-    UA_NodeId_encodeBinary(&type, &message, &offset);
-    msghdr.messageSize = 16 + offset;
-    offset = 0;
-
-    UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-    UA_UInt32_encodeBinary(&connectionInfo->channelId, &message, &offset);
-    UA_UInt32_encodeBinary(&connectionInfo->tokenId, &message, &offset);
-    connectionInfo->sequenceHdr.sequenceNumber++;
-    UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.sequenceNumber, &message, &offset);
-    connectionInfo->sequenceHdr.requestId++;
-    UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.requestId, &message, &offset);
-    UA_NodeId_encodeBinary(&type, &message, &offset);
-    UA_CloseSessionRequest_encodeBinary(&rq, &message, &offset);
-
-    UA_Int32 sendret = send(connectionInfo->socket, message.data, offset, 0);
-    UA_ByteString_deleteMembers(&message);
-    UA_CloseSessionRequest_deleteMembers(&rq);
-    if(sendret < 0) {
-        printf("send closesessionrequest failed");
-        return 1;
-    }
-
-    return 0;
-}
-
-static UA_Int32 closeSecureChannel(ConnectionInfo *connectionInfo) {
-    size_t offset = 0;
-
-    UA_ByteString message;
-    UA_ByteString_newMembers(&message, 65536);
-
-    UA_CloseSecureChannelRequest rq;
-    UA_CloseSecureChannelRequest_init(&rq);
-
-    rq.requestHeader.requestHandle = 1;
-    rq.requestHeader.timestamp = UA_DateTime_now();
-    rq.requestHeader.timeoutHint = 10000;
-    rq.requestHeader.authenticationToken.identifier.numeric = 10;
-    rq.requestHeader.authenticationToken.identifierType = UA_NODEIDTYPE_NUMERIC;
-    rq.requestHeader.authenticationToken.namespaceIndex = 10;
-
-    UA_TcpMessageHeader msghdr;
-    msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_CLOF;
-
-    //workaround to get length calculated
-    offset = 0;
-    UA_CloseSecureChannelRequest_encodeBinary(&rq, &message, &offset);
-    UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-    msghdr.messageSize = 4 + offset;
-    offset = 0;
-
-    UA_TcpMessageHeader_encodeBinary(&msghdr, &message, &offset);
-    UA_UInt32_encodeBinary(&connectionInfo->channelId, &message, &offset);
-    UA_CloseSecureChannelRequest_encodeBinary(&rq, &message, &offset);
-
-    UA_Int32 sendret = send(connectionInfo->socket, message.data, offset, 0);
-    UA_ByteString_deleteMembers(&message);
-    UA_CloseSecureChannelRequest_deleteMembers(&rq);
-    if(sendret < 0) {
-        printf("send CloseSecureChannelRequest failed");
-        return 1;
-    }
-
-    return 0;
-}
-
-static UA_Int32 sendActivateSession(UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber,
-        UA_UInt32 requestId, UA_NodeId authenticationToken) {
-    UA_ByteString *message = UA_ByteString_new();
-    UA_ByteString_newMembers(message, 65536);
-    UA_UInt32 tmpChannelId = channelId;
-    size_t offset = 0;
-
-    UA_TcpMessageHeader msghdr;
-    msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-    msghdr.messageSize = 86;
-
-    UA_NodeId type;
-    type.identifier.numeric = 467;
-    type.identifierType = UA_NODEIDTYPE_NUMERIC;
-    type.namespaceIndex = 0;
-
-    UA_ActivateSessionRequest rq;
-    UA_ActivateSessionRequest_init(&rq);
-    rq.requestHeader.requestHandle = 2;
-    rq.requestHeader.authenticationToken = authenticationToken;
-    rq.requestHeader.timestamp = UA_DateTime_now();
-    rq.requestHeader.timeoutHint = 10000;
-
-    //workaround to get length calculated
-    offset = 0;
-    UA_ActivateSessionRequest_encodeBinary(&rq, message, &offset);
-    UA_TcpMessageHeader_encodeBinary(&msghdr, message, &offset);
-    UA_NodeId_encodeBinary(&type, message, &offset);
-    msghdr.messageSize = 16 + offset;
-    offset = 0;
-
-    UA_TcpMessageHeader_encodeBinary(&msghdr, message, &offset);
-    UA_UInt32_encodeBinary(&tmpChannelId, message, &offset);
-    UA_UInt32_encodeBinary(&tokenId, message, &offset);
-    UA_UInt32_encodeBinary(&sequenceNumber, message, &offset);
-    UA_UInt32_encodeBinary(&requestId, message, &offset);
-    UA_NodeId_encodeBinary(&type, message, &offset);
-    UA_ActivateSessionRequest_encodeBinary(&rq, message, &offset);
-
-    UA_Int32 sendret = send(sock, message->data, offset, 0);
-    UA_ByteString_delete(message);
-
-    if (sendret < 0) {
-        printf("send opensecurechannel failed");
-        return 1;
-    }
-    return 0;
-
-}
-
-static UA_Int64 sendReadRequest(ConnectionInfo *connectionInfo, UA_Int32 nodeIds_size,UA_NodeId* nodeIds){
-    /*UA_Int32 sock, UA_UInt32 channelId, UA_UInt32 tokenId, UA_UInt32 sequenceNumber, UA_UInt32 requestId,
-                         UA_NodeId authenticationToken, UA_Int32 nodeIds_size,UA_NodeId* nodeIds) {
-     */
-    UA_ByteString *message = UA_ByteString_new();
-    UA_ByteString_newMembers(message, 65536);
-    UA_UInt32 tmpChannelId = connectionInfo->channelId;
-    size_t offset = 0;
-
-    UA_TcpMessageHeader msghdr;
-    msghdr.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_MSGF;
-
-    UA_NodeId type;
-    type.identifier.numeric = 631;
-    type.identifierType = UA_NODEIDTYPE_NUMERIC;
-    type.namespaceIndex = 0;
-
-    UA_ReadRequest rq;
-    UA_ReadRequest_init(&rq);
-    rq.maxAge = 0;
-    rq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
-    rq.nodesToReadSize = 1;
-    for(UA_Int32 i=0;i<nodeIds_size;i++) {
-        UA_ReadValueId_init(&(rq.nodesToRead[i]));
-        rq.nodesToRead[i].attributeId = 6; //WriteMask
-        UA_NodeId_init(&(rq.nodesToRead[i].nodeId));
-        rq.nodesToRead[i].nodeId = nodeIds[i];
-        UA_QualifiedName_init(&(rq.nodesToRead[0].dataEncoding));
-    }
-    rq.requestHeader.timeoutHint = 10000;
-    rq.requestHeader.timestamp = UA_DateTime_now();
-    rq.requestHeader.authenticationToken = connectionInfo->authenticationToken;
-    rq.timestampsToReturn = 0x03;
-    rq.requestHeader.requestHandle = connectionInfo->reqestHandle++;
-
-    //workaround to get length calculated
-    offset = 0;
-    UA_ReadRequest_encodeBinary(&rq, message, &offset);
-    UA_TcpMessageHeader_encodeBinary(&msghdr, message, &offset);
-    UA_NodeId_encodeBinary(&type, message, &offset);
-    msghdr.messageSize = 16 + offset;
-    offset = 0;
-
-    UA_TcpMessageHeader_encodeBinary(&msghdr,message,&offset);
-    UA_UInt32_encodeBinary(&tmpChannelId, message, &offset);
-    UA_UInt32_encodeBinary(&connectionInfo->tokenId, message, &offset);
-    connectionInfo->sequenceHdr.sequenceNumber++;
-    UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.sequenceNumber, message, &offset);
-    connectionInfo->sequenceHdr.requestId++;
-    UA_UInt32_encodeBinary(&connectionInfo->sequenceHdr.requestId, message, &offset);
-    UA_NodeId_encodeBinary(&type,message,&offset);
-    UA_ReadRequest_encodeBinary(&rq, message, &offset);
-
-    UA_DateTime tic = UA_DateTime_now();
-    UA_Int32 sendret = send(connectionInfo->socket, message->data, offset, 0);
-    UA_Array_delete(rq.nodesToRead, &UA_TYPES[UA_TYPES_READVALUEID], nodeIds_size);
-    UA_ByteString_delete(message);
-
-    if (sendret < 0) {
-        printf("send readrequest failed");
-        return 1;
-    }
-    return tic;
-}
-
-static int ua_client_connectUA(char* ipaddress,int port, UA_String *endpointUrl, ConnectionInfo *connectionInfo,
-        UA_Boolean stateless, UA_Boolean udp) {
-    UA_ByteString reply;
-    UA_ByteString_newMembers(&reply, 65536);
-    int sock;
-    struct sockaddr_in server;
-    //Create socket
-    if(udp==UA_TRUE){
-        sock = socket(AF_INET, SOCK_DGRAM, 0);
-    }else{
-        sock = socket(AF_INET, SOCK_STREAM, 0);
-    }
-    if(sock == -1) {
-        printf("Could not create socket");
-        return 1;
-    }
-    server.sin_addr.s_addr = inet_addr(ipaddress);
-    server.sin_family = AF_INET;
-    server.sin_port = htons(port);
-
-    if(connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
-        perror("connect failed. Error");
-        return 1;
-    }
-    connectionInfo->socket = sock;
-
-    if(stateless){
-        UA_NodeId_init(&connectionInfo->authenticationToken);
-        connectionInfo->channelId=0;
-        UA_SequenceHeader_init(&connectionInfo->sequenceHdr);
-        connectionInfo->tokenId=0;
-        connectionInfo->reqestHandle = 1;
-        return 0;
-    }else{
-        sendHello(sock, endpointUrl);
-        recv(sock, reply.data, reply.length, 0);
-        sendOpenSecureChannel(sock);
-        recv(sock, reply.data, reply.length, 0);
-
-        size_t recvOffset = 0;
-        UA_TcpMessageHeader msghdr;
-        UA_TcpMessageHeader_decodeBinary(&reply, &recvOffset, &msghdr);
-
-        UA_AsymmetricAlgorithmSecurityHeader asymHeader;
-        UA_NodeId rspType;
-        UA_OpenSecureChannelResponse openSecChannelRsp;
-        UA_UInt32_decodeBinary(&reply, &recvOffset, &connectionInfo->channelId);
-        UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply,&recvOffset,&asymHeader);
-        UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
-        UA_SequenceHeader_decodeBinary(&reply,&recvOffset,&connectionInfo->sequenceHdr);
-        UA_NodeId_decodeBinary(&reply,&recvOffset,&rspType);
-        UA_OpenSecureChannelResponse_decodeBinary(&reply,&recvOffset,&openSecChannelRsp);
-        connectionInfo->tokenId = openSecChannelRsp.securityToken.tokenId;
-
-        sendCreateSession(sock, connectionInfo->channelId, openSecChannelRsp.securityToken.tokenId, 52, 2, endpointUrl);
-        recv(sock, reply.data, reply.length, 0);
-
-        UA_NodeId messageType;
-        recvOffset = 24;
-        UA_NodeId_decodeBinary(&reply,&recvOffset,&messageType);
-        UA_CreateSessionResponse createSessionResponse;
-        UA_CreateSessionResponse_decodeBinary(&reply,&recvOffset,&createSessionResponse);
-        connectionInfo->authenticationToken = createSessionResponse.authenticationToken;
-        sendActivateSession(sock, connectionInfo->channelId, connectionInfo->tokenId, 53, 3,
-                connectionInfo->authenticationToken);
-        recv(sock, reply.data, reply.length, 0);
-
-        connectionInfo->sequenceHdr.requestId = 3;
-        connectionInfo->sequenceHdr.sequenceNumber = 53;
-        connectionInfo->reqestHandle = 3;
-
-        UA_OpenSecureChannelResponse_deleteMembers(&openSecChannelRsp);
-
-        UA_String_deleteMembers(&reply);
-        UA_CreateSessionResponse_deleteMembers(&createSessionResponse);
-        return 0;
-    }
-}
-
-int main(int argc, char *argv[]) {
-    int defaultParams = argc < 8;
-
-    //start parameters
-    if(defaultParams) {
-        printf("1st parameter: number of nodes to read \n");
-        printf("2nd parameter: number of measured read-tries \n");
-        printf("3rd parameter: name of the file to save measurement data \n");
-        printf("4th parameter: 1 = read same node, 0 = read different nodes \n");
-        printf("5th parameter: ip adress \n");
-        printf("6th parameter: port \n");
-        printf("7th parameter: 0=stateful, 1=stateless\n");
-        printf("8th parameter: 0=tcp, 1=udp (only with stateless calls)\n");
-        printf("9th parameter: number of tries to run in (not measured, added to tries)\n");
-        printf("9th parameter: number of tries to run out (not measured, added to tries)\n");
-        printf("\nUsing default parameters. \n");
-    }
-
-    UA_UInt32 nodesToReadSize;
-    UA_UInt32 tries;
-    UA_Boolean alwaysSameNode;
-    UA_ByteString reply;
-    UA_ByteString_newMembers(&reply, 65536);
-    UA_Boolean stateless;
-    UA_Boolean udp;
-    UA_UInt32 runIn;
-    UA_UInt32 runOut;
-
-    if(defaultParams)
-        nodesToReadSize = 1;
-    else
-        nodesToReadSize = atoi(argv[1]);
-
-    if(defaultParams)
-        tries= 1;
-    else
-        tries = (UA_UInt32) atoi(argv[2]);
-
-    if(defaultParams){
-        alwaysSameNode = UA_TRUE;
-    }else{
-        if(atoi(argv[4]) != 0)
-            alwaysSameNode = UA_TRUE;
-        else
-            alwaysSameNode = UA_FALSE;
-    }
-
-    if(defaultParams){
-        stateless = UA_FALSE;
-    }else{
-        if(atoi(argv[7]) != 0)
-            stateless = UA_TRUE;
-        else
-            stateless = UA_FALSE;
-    }
-
-    if(defaultParams){
-        udp = UA_FALSE;
-    }else{
-        if(atoi(argv[8]) != 0)
-            udp = UA_TRUE;
-        else
-            udp = UA_FALSE;
-    }
-
-    if(defaultParams){
-        runIn = 0;
-    }else{
-        runIn = (UA_UInt32) atoi(argv[9]);
-    }
-
-    if(defaultParams){
-        runOut = 0;
-    }else{
-        runOut = (UA_UInt32) atoi(argv[10]);
-    }
-
-
-
-    //Connect to remote server
-    UA_String endpoint;
-    endpoint = UA_STRING("none");
-    ConnectionInfo connectionInfo;
-
-
-    /* REQUEST START*/
-    UA_NodeId *nodesToRead;
-    nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_NODEID], 1);
-
-    for(UA_UInt32 i = 0; i<1; i++) {
-        if(alwaysSameNode)
-            nodesToRead[i].identifier.numeric = 2253; //ask always the same node
-        else
-            nodesToRead[i].identifier.numeric = 19000 +i;
-        nodesToRead[i].identifierType = UA_NODEIDTYPE_NUMERIC;
-        nodesToRead[i].namespaceIndex = 0;
-    }
-
-    UA_DateTime tic, toc;
-    UA_Double *timeDiffs;
-    UA_Int32 received = 0;
-    timeDiffs = UA_Array_new(&UA_TYPES[UA_TYPES_DOUBLE], tries);
-    UA_Double sum = 0;
-
-    tic = UA_DateTime_now();
-
-    /**
-	UA_Double duration;
-
-	UA_UInt32 count = 0;
-	UA_Double start = 0, stop = 0;
-
-	UA_UInt32 timeToRun = 30;
-	UA_UInt32 timeToStart = 8;
-	UA_UInt32 timeToStop = 22;
-
-	do{
-		toc = UA_DateTime_now();
-		duration = ((UA_Double)toc-(UA_Double)tic)/(UA_Double)1e4;
-		if(duration>=timeToStart*1000 && duration <= timeToStop*1000){
-			if(start==0.0){
-				start=UA_DateTime_now();
-			}
-		}
-			//if(stateless || (!stateless && i==0)){
-				if(defaultParams){
-					if(ua_client_connectUA("127.0.0.1",atoi("16664"),&endpoint,&connectionInfo,stateless,udp) != 0){
-						return 0;
-					}
-				}else{
-					if(ua_client_connectUA(argv[5],atoi(argv[6]),&endpoint,&connectionInfo,stateless,udp) != 0){
-						return 0;
-					}
-				}
-			//}
-			sendReadRequest(&connectionInfo,1,nodesToRead);
-			received = recv(connectionInfo.socket, reply.data, 2000, 0);
-			if(duration>=timeToStart*1000 && duration <= timeToStop*1000){
-				count++;
-			}
-
-			if(!stateless){
-			closeSession(&connectionInfo);
-			recv(connectionInfo.socket, reply.data, 2000, 0);
-
-			closeSecureChannel(&connectionInfo);
-			}
-			//if(stateless || (!stateless && i==tries-1)){
-				close(connectionInfo.socket);
-			//}
-		if(duration >= timeToStop*1000 && stop==0){
-			stop=UA_DateTime_now();
-			printf("%i messages in %f secs, rate %f m/s\n", count, (stop-start)/(UA_Double)1e7, (UA_Double)count/((stop-start)/(UA_Double)1e7));
-		}
-
-	}while(duration<timeToRun*1000);
-
-	exit(0);
-     **/
-
-    for(UA_UInt32 i = 0; i < tries + runIn + runOut; i++) {
-        if(i >= runIn && i < runIn+tries)
-            tic = UA_DateTime_now();
-        if(defaultParams){
-            if(ua_client_connectUA("127.0.0.1",atoi("16664"),&endpoint,&connectionInfo,stateless,udp) != 0){
-                return 0;
-            }
-        }else{
-            if(ua_client_connectUA(argv[5],atoi(argv[6]),&endpoint,&connectionInfo,stateless,udp) != 0){
-                return 0;
-            }
-        }
-        for(UA_UInt32 i = 0; i < nodesToReadSize; i++) {
-            sendReadRequest(&connectionInfo,1,nodesToRead);
-            received = recv(connectionInfo.socket, reply.data, 2000, 0);
-        }
-
-        if(!stateless){
-            closeSession(&connectionInfo);
-            recv(connectionInfo.socket, reply.data, 2000, 0);
-            closeSecureChannel(&connectionInfo);
-        }
-        close(connectionInfo.socket);
-        if(i >= runIn && i < runIn+tries){
-            toc = UA_DateTime_now() - tic;
-            timeDiffs[i-runIn] = (UA_Double)toc/(UA_Double)1e4;
-            sum = sum + timeDiffs[i-runIn];
-        }
-    }
-
-    /* REQUEST END*/
-
-    UA_Double mean = sum / tries;
-    printf("total time for requests: %16.10f ms \n",sum);
-    printf("mean time for handling request: %16.10f ms \n",mean);
-
-    if(received>0)
-        printf("received: %i\n",received); // dummy
-
-
-    //save to file
-    char data[100];
-    const char flag = 'a';
-    FILE* fHandle = NULL;
-    if (defaultParams) {
-        fHandle =  fopen("client.log", &flag);
-    }else{
-        fHandle =  fopen(argv[3], &flag);
-    }
-    //header
-
-    UA_Int32 bytesToWrite = 0;//sprintf(data, "measurement %s in ms, nodesToRead %d \n", argv[3], 1);
-    //fwrite(data,1,bytesToWrite,fHandle);
-    for(UA_UInt32 i=0;i<tries;i++) {
-        bytesToWrite = sprintf(data,"%16.10f \n",timeDiffs[i]);
-        fwrite(data,1,bytesToWrite,fHandle);
-    }
-    fclose(fHandle);
-
-    UA_String_deleteMembers(&reply);
-    UA_Array_delete(nodesToRead,&UA_TYPES[UA_TYPES_NODEID], 1);
-    UA_free(timeDiffs);
-
-    return 0;
-}

+ 7 - 16
examples/client_stateless.c

@@ -14,8 +14,7 @@
 #include "ua_types_generated_encoding_binary.h"
 
 
-int main(int argc , char *argv[])
-{
+int main(int argc , char *argv[]) {
 	int sock;
 	struct sockaddr_in server;
 	UA_ByteString message;
@@ -26,13 +25,12 @@ int main(int argc , char *argv[])
 	unsigned int messagepos = 0;
 
 	//Create socket
-#ifdef EXTENSION_UDP
+#ifdef UA_ENABLE_NONSTANDARD_UDP
 	sock = socket(AF_INET , SOCK_DGRAM , 0);
 #else
 	sock = socket(AF_INET , SOCK_STREAM , 0);
 #endif
-	if (sock == -1)
-	{
+	if(sock == -1) {
 		printf("Could not create socket");
 	}
 	server.sin_addr.s_addr = inet_addr("127.0.0.1");
@@ -40,13 +38,11 @@ int main(int argc , char *argv[])
 	server.sin_port = htons( 16664 );
 
 	//Connect to remote server
-	if (connect(sock , (struct sockaddr *)&server , sizeof(server)) < 0)
-	{
+	if(connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
 		perror("connect failed. Error");
 		return 1;
 	}
 
-
 	UA_TcpMessageHeader reqTcpHeader;
 	UA_UInt32 reqSecureChannelId = 0;
 	UA_UInt32 reqTokenId = 0;
@@ -61,7 +57,6 @@ int main(int argc , char *argv[])
 	reqRequestType.identifierType = UA_NODEIDTYPE_NUMERIC;
 	reqRequestType.identifier.numeric = 631; //read request
 
-
 	UA_SequenceHeader_init(&reqSequenceHeader);
 	reqSequenceHeader.sequenceNumber = 42;
 
@@ -83,7 +78,6 @@ int main(int argc , char *argv[])
 	req.nodesToRead[0].nodeId.identifier.numeric = 2255;
 	UA_QualifiedName_init(&(req.nodesToRead[0].dataEncoding));
 
-
 	/**messageEncodedLength = UA_TcpMessageHeader_calcSizeBinary(&reqTcpHeader) +
 			UA_UInt32_calcSizeBinary(&reqSecureChannelId)+
 			UA_UInt32_calcSizeBinary(&reqTokenId)+
@@ -110,24 +104,21 @@ int main(int argc , char *argv[])
     UA_NodeId_encodeBinary(&reqRequestType, &message, &messagepos);
     UA_ReadRequest_encodeBinary(&req, &message, &messagepos);
 
-
 	//Send some data
-	if( send(sock , message.data, messagepos , 0) < 0)
-	{
+	if(send(sock , message.data, messagepos , 0) < 0) {
 		puts("Send failed");
 		return 1;
 	}
 
 	//Receive a reply from the server
 	int received = recv(sock , server_reply , 2000 , 0);
-	if(received < 0)
-	{
+	if(received < 0) {
 		puts("recv failed");
 		return 1;
 	}
 
 
-	for(int i=0;i<received;i++){
+	for(int i=0;i<received;i++) {
 		  //show only printable ascii
 		  if(server_reply[i] >= 32 && server_reply[i]<= 126)
 			  printf("%c",server_reply[i]);

+ 37 - 24
examples/server.c

@@ -27,7 +27,7 @@
 # include <unistd.h> //access
 #endif
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 # ifdef UA_NO_AMALGAMATION
 #  ifndef __USE_XOPEN2K
 #   define __USE_XOPEN2K
@@ -99,7 +99,7 @@ readTemperature(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp
 /*************************/
 /* Read-write status led */
 /*************************/
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 pthread_rwlock_t writeLock;
 #endif
 FILE* triggerFile = NULL;
@@ -132,7 +132,7 @@ writeLedStatus(void *handle, const UA_NodeId nodeid,
     if(range)
         return UA_STATUSCODE_BADINDEXRANGEINVALID;
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	pthread_rwlock_wrlock(&writeLock);
 #endif
 	if(data->data)
@@ -148,13 +148,13 @@ writeLedStatus(void *handle, const UA_NodeId nodeid,
 			fprintf(ledFile, "%s", "0");
 		fflush(ledFile);
 	}
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	pthread_rwlock_unlock(&writeLock);
 #endif
 	return UA_STATUSCODE_GOOD;
 }
 
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
 static UA_StatusCode
 getMonitoredItems(void *methodHandle, const UA_NodeId objectId,
                   size_t inputSize, const UA_Variant *input,
@@ -200,18 +200,25 @@ nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, voi
     return UA_STATUSCODE_GOOD;
 }
 
+static UA_StatusCode
+instantiationHandle(UA_NodeId newNodeId, UA_NodeId templateId, void *handle ) {
+  printf("Instantiated Node ns=%d; id=%d from ns=%d; id=%d\n", newNodeId.namespaceIndex, newNodeId.identifier.numeric, templateId.namespaceIndex, templateId.identifier.numeric);
+  return UA_STATUSCODE_GOOD;
+}
+
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     pthread_rwlock_init(&writeLock, 0);
 #endif
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_ByteString certificate = loadCertificate();
-    UA_Server_setServerCertificate(server, certificate);
-    UA_ByteString_deleteMembers(&certificate);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.serverCertificate = loadCertificate();
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
     // add node with the datetime data source
     UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
@@ -287,8 +294,12 @@ int main(int argc, char** argv) {
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    /* Instantiation Callback can be used when a typeDefinition creates new nodes under this added one.
+     * The method will be called for each created node.
+     */
+    UA_InstantiationCallback theAnswerCallback = {.method=instantiationHandle, .handle=(void*) server};
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                              myIntegerName, UA_NODEID_NULL, myVar, NULL);
+                              myIntegerName, UA_NODEID_NULL, myVar, &theAnswerCallback, NULL);
     UA_Variant_deleteMembers(&myVar.value);
 
     /**************/
@@ -303,7 +314,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 #define SCALARID 50001
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
@@ -311,7 +322,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Scalar"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 #define ARRAYID 50002
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
@@ -319,14 +330,14 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Array"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 #define MATRIXID 50003
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
     UA_UInt32 id = 51000; // running id in namespace 0
     for(UA_UInt32 type = 0; type < UA_TYPES_DIAGNOSTICINFO; type++) {
@@ -346,7 +357,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, SCALARID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
 
         /* add an array node for every built-in type */
@@ -355,7 +366,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, ARRAYID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
 
         /* add an matrix node for every built-in type */
@@ -370,11 +381,11 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, MATRIXID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
     }
 
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
     inputArguments.arrayDimensionsSize = 0;
@@ -414,13 +425,14 @@ int main(int argc, char** argv) {
   
     // Some easy localization
     UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("de_DE", "Objekte");
-    UA_Server_writeDisplayNameAttribute(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
+    UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
   
     //start server
-    UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
+    UA_StatusCode retval = UA_Server_run(server, &running); //blocks until running=false
 
     //ctrl-c received -> clean up
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
 
     if(temperatureFile)
         fclose(temperatureFile);
@@ -435,9 +447,10 @@ int main(int argc, char** argv) {
     if(ledFile)
         fclose(ledFile);
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     pthread_rwlock_destroy(&writeLock);
 #endif
 
+    UA_ByteString_deleteMembers(&config.serverCertificate);
     return retval;
 }

+ 11 - 7
examples/server.cpp

@@ -7,7 +7,7 @@
 #include <iostream>
 #include <cstring>
 
-#ifdef NOT_AMALGATED
+#ifdef UA_NO_AMALGAMATION
 # include "ua_server.h"
 # include "logger_stdout.h"
 # include "networklayer_tcp.h"
@@ -23,7 +23,7 @@
 
 using namespace std;
 
-UA_Boolean running = 1;
+UA_Boolean running = UA_TRUE;
 UA_Logger logger = Logger_Stdout;
 
 static void stopHandler(int sign) {
@@ -34,9 +34,12 @@ static void stopHandler(int sign) {
 int main() {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-    UA_Server_setLogger(server, logger);
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
     // add a variable node to the adresspace
     UA_VariableAttributes attr;
@@ -51,15 +54,16 @@ int main() {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, attr, NULL);
+                              UA_NODEID_NULL, attr, NULL, NULL);
 
     /* allocations on the heap need to be freed */
     UA_VariableAttributes_deleteMembers(&attr);
     UA_NodeId_deleteMembers(&myIntegerNodeId);
     UA_QualifiedName_deleteMembers(&myIntegerName);
 
-    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
 	UA_Server_delete(server);
+    nl.deleteMembers(&nl);
 
 	return retval;
 }

+ 22 - 13
examples/server_datasource.c

@@ -15,7 +15,7 @@
 # include "open62541.h"
 #endif
 
-UA_Boolean running = 1;
+UA_Boolean running = UA_TRUE;
 UA_Logger logger = Logger_Stdout;
 
 static void stopHandler(int sign) {
@@ -23,21 +23,27 @@ static void stopHandler(int sign) {
     running = 0;
 }
 
-static UA_StatusCode readInteger(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *dataValue) {
+static UA_StatusCode
+readInteger(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+            const UA_NumericRange *range, UA_DataValue *dataValue) {
     dataValue->hasValue = UA_TRUE;
     UA_Variant_setScalarCopy(&dataValue->value, (UA_UInt32*)handle, &UA_TYPES[UA_TYPES_INT32]);
-    //note that this is only possible if the identifier is a string - but we are sure to have one here
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node read %.*s",nodeid.identifier.string.length, nodeid.identifier.string.data);
+    // we know the nodeid is a string
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node read %.*s",
+                nodeid.identifier.string.length, nodeid.identifier.string.data);
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "read value %i", *(UA_UInt32*)handle);
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode writeInteger(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range){
+static UA_StatusCode
+writeInteger(void *handle, const UA_NodeId nodeid,
+             const UA_Variant *data, const UA_NumericRange *range) {
     if(UA_Variant_isScalar(data) && data->type == &UA_TYPES[UA_TYPES_INT32] && data->data){
         *(UA_UInt32*)handle = *(UA_Int32*)data->data;
     }
-    //note that this is only possible if the identifier is a string - but we are sure to have one here
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node written %.*s",nodeid.identifier.string.length, nodeid.identifier.string.data);
+    // we know the nodeid is a string
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node written %.*s",
+                nodeid.identifier.string.length, nodeid.identifier.string.data);
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "written value %i", *(UA_UInt32*)handle);
     return UA_STATUSCODE_GOOD;
 }
@@ -46,13 +52,15 @@ static UA_StatusCode writeInteger(void *handle, const UA_NodeId nodeid, const UA
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-
-    UA_Int32 myInteger = 42;
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
     /* add a variable node to the address space */
+    UA_Int32 myInteger = 42;
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_DataSource dateDataSource = (UA_DataSource) {
@@ -67,8 +75,9 @@ int main(int argc, char** argv) {
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                         myIntegerName, UA_NODEID_NULL, attr, dateDataSource, NULL);
 
-    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
 
     return retval;
 }

+ 11 - 11
examples/server_firstSteps.c

@@ -13,9 +13,7 @@
 # include "open62541.h"
 #endif
 
-UA_Boolean running;
-UA_Logger logger = Logger_Stdout;
-
+UA_Boolean running = UA_TRUE;
 static void stopHandler(int signal) {
     running = UA_FALSE;
 }
@@ -24,13 +22,15 @@ int main(void) {
     signal(SIGINT,  stopHandler);
     signal(SIGTERM, stopHandler);
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
-    running = UA_TRUE;
-    UA_Server_run(server, 1, &running);
-    UA_Server_delete(server);
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, Logger_Stdout);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
-    printf("Terminated\n");
-    return 0;
+    UA_StatusCode retval = UA_Server_run(server, &running);
+    UA_Server_delete(server);
+    nl.deleteMembers(&nl);
+    return retval;
 }

+ 18 - 13
examples/server_method.c

@@ -15,12 +15,13 @@
 # include "open62541.h"
 #endif
 
-UA_Boolean running = UA_TRUE;
+UA_Boolean running = true;
 UA_Logger logger = Logger_Stdout;
 
 static UA_StatusCode
-helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input,
-                 UA_Variant *output, void *handle) {
+
+helloWorldMethod(void *handle, const UA_NodeId objectId, size_t inputSize, const UA_Variant *input,
+                 size_t outputSize, UA_Variant *output) {
         UA_String *inputStr = (UA_String*)input->data;
         UA_String tmp = UA_STRING_ALLOC("Hello ");
         if(inputStr->length > 0) {
@@ -35,8 +36,8 @@ helloWorldMethod(const UA_NodeId objectId, const UA_Variant *input,
 } 
 
 static UA_StatusCode
-IncInt32ArrayValuesMethod(const UA_NodeId objectId, const UA_Variant *input,
-                          UA_Variant *output, void *handle) {
+IncInt32ArrayValuesMethod(void *handle, const UA_NodeId objectId, size_t inputSize,
+                          const UA_Variant *input, size_t outputSize, UA_Variant *output) {
 	UA_Variant_setArrayCopy(output, input->data, 5, &UA_TYPES[UA_TYPES_INT32]);
 	for(size_t i = 0; i< input->arrayLength; i++)
 		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;
@@ -52,9 +53,12 @@ int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
     /* initialize the server */
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
     //EXAMPLE 1
     /* add the method node with the callback */
@@ -80,8 +84,8 @@ int main(int argc, char** argv) {
     UA_MethodAttributes_init(&helloAttr);
     helloAttr.description = UA_LOCALIZEDTEXT("en_US","Say `Hello World`");
     helloAttr.displayName = UA_LOCALIZEDTEXT("en_US","Hello World");
-    helloAttr.executable = UA_TRUE;
-    helloAttr.userExecutable = UA_TRUE;
+    helloAttr.executable = true;
+    helloAttr.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
@@ -121,8 +125,8 @@ int main(int argc, char** argv) {
     UA_MethodAttributes_init(&incAttr);
     incAttr.description = UA_LOCALIZEDTEXT("en_US","1dArrayExample");
     incAttr.displayName = UA_LOCALIZEDTEXT("en_US","1dArrayExample");
-    incAttr.executable = UA_TRUE;
-    incAttr.userExecutable = UA_TRUE;
+    incAttr.executable = true;
+    incAttr.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), 
@@ -132,12 +136,13 @@ int main(int argc, char** argv) {
     //END OF EXAMPLE 2
 
     /* start server */
-    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
 
     /* ctrl-c received -> clean up */
     UA_UInt32_delete(pInputDimensions);
     UA_UInt32_delete(pOutputDimensions);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
 
     return retval;
 }

+ 10 - 6
examples/server_nodeset.c

@@ -18,29 +18,33 @@
 /* files nodeset.h and nodeset.c are created from server_nodeset.xml in the /src_generated directory by CMake */
 #include "nodeset.h"
 
-UA_Boolean running = UA_TRUE;
 UA_Logger logger = Logger_Stdout;
+UA_Boolean running = UA_TRUE;
 
 static void stopHandler(int sign) {
     UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
-    running = 0;
+    running = UA_FALSE;
 }
 
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
     /* initialize the server */
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
     /* create nodes from nodeset */
     nodeset(server);
 
     /* start server */
-    UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
+    UA_StatusCode retval = UA_Server_run(server, &running); //UA_blocks until running=false
 
     /* ctrl-c received -> clean up */
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
     return retval;
 }

+ 8 - 4
examples/server_repeated_job.c

@@ -29,16 +29,20 @@ static void testCallback(UA_Server *server, void *data) {
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
     /* add a repeated job to the server */
     UA_Job job = {.type = UA_JOBTYPE_METHODCALL,
                   .job.methodCall = {.method = testCallback, .data = NULL} };
     UA_Server_addRepeatedJob(server, job, 2000, NULL); // call every 2 sec
 
-    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
     return retval;
 }

+ 10 - 8
examples/server_variable.c

@@ -14,7 +14,7 @@
 # include "open62541.h"
 #endif
 
-UA_Boolean running = 1;
+UA_Boolean running = UA_TRUE;
 UA_Logger logger = Logger_Stdout;
 
 static void stopHandler(int sign) {
@@ -36,11 +36,12 @@ static void onWrite(void *h, const UA_NodeId nodeid, const UA_Variant *data,
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_ServerNetworkLayer *nl;
-    nl = ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664);
-    UA_Server_addNetworkLayer(server, nl);
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
     /* add a variable node to the address space */
     UA_VariableAttributes attr;
@@ -55,13 +56,14 @@ int main(int argc, char** argv) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, attr, NULL);
+                              UA_NODEID_NULL, attr, NULL, NULL);
 
     UA_ValueCallback callback = {(void*)7, onRead, onWrite};
     UA_Server_setVariableNode_valueCallback(server, myIntegerNodeId, callback);
 
-    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
 
     return retval;
 }

+ 1 - 1
include/ua_client.h

@@ -298,7 +298,7 @@ UA_Client_Service_call(UA_Client *client, const UA_CallRequest request) {
                         &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]);
     return response; }
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 /* MonitoredItem Service Set */
 
 /**

+ 1 - 1
include/ua_client_highlevel.h

@@ -255,7 +255,7 @@ UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId meth
 /* Subscriptions Handling */
 /**************************/
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 
 typedef struct {
     UA_Double requestedPublishingInterval;

+ 71 - 25
include/ua_config.h.in

@@ -3,14 +3,21 @@
 
 #ifndef _XOPEN_SOURCE
 # define _XOPEN_SOURCE 500
+# define _BSD_SOURCE
 #endif
 
 #define UA_LOGLEVEL ${UA_LOGLEVEL}
-#cmakedefine UA_MULTITHREADING
-#cmakedefine ENABLE_METHODCALLS
-#cmakedefine ENABLE_SUBSCRIPTIONS
-#cmakedefine ENABLE_TYPEINTROSPECTION
-#cmakedefine UA_EMBEDDED_LIBC
+#cmakedefine UA_ENABLE_MULTITHREADING
+#cmakedefine UA_ENABLE_METHODCALLS
+#cmakedefine UA_ENABLE_SUBSCRIPTIONS
+#cmakedefine UA_ENABLE_TYPENAMES
+#cmakedefine UA_ENABLE_EMBEDDED_LIBC
+#cmakedefine UA_ENABLE_GENERATE_NAMESPACE0
+#cmakedefine UA_ENABLE_EXTERNAL_NAMESPACES
+#cmakedefine UA_ENABLE_NODEMANAGEMENT
+
+#cmakedefine UA_ENABLE_NONSTANDARD_UDP
+#cmakedefine UA_ENABLE_NONSTANDARD_STATELESS
 
 /* Function Export */
 #ifdef _WIN32
@@ -36,37 +43,76 @@
 #endif
 
 /* Endianness */
-#if defined(__linux__) || defined(__APPLE__)
-#  ifndef __QNX__
-#    if defined(__APPLE__) || defined(__MACH__)
-#     include <machine/endian.h>
-#    else
-#     include <endian.h>
-#    endif
+// UA_NON_LITTLEENDIAN_ARCHITECTURE disables memcpying integer arrays directly
+// onto the message buffer. UA_MIXED_ENDIAN enables special encoding for floats
+// and doubles. Otherwise, they are endianness-switched similar to integers.
+
+#if defined(__LITTLE_ENDIAN__) || defined(_WIN32) || (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+# define htole16(x) (x)
+# define htole32(x) (x)
+# define htole64(x) (x)
+# define le16toh(x) (x)
+# define le32toh(x) (x)
+# define le64toh(x) (x)
+#else
+# if defined(__linux__)
+#  include <endian.h>
+# elif defined(__OpenBSD__)
+#  include <sys/endian.h>
+# elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+#  include <sys/endian.h>
+#  define le16toh(x) letoh16(x)
+#  define le32toh(x) letoh32(x)
+#  define le64toh(x) letoh64(x)
+# elif defined(__APPLE__)
+#  include <libkern/OSByteOrder.h>
+#  define htole16(x) OSSwapHostToLittleInt16(x)
+#  define htole32(x) OSSwapHostToLittleInt32(x)
+#  define htole64(x) OSSwapHostToLittleInt64(x)
+#  define le16toh(x) OSSwapLittleToHostInt16(x)
+#  define le32toh(x) OSSwapLittleToHostInt32(x)
+#  define le64toh(x) OSSwapLittleToHostInt64(x)
+#  define __BYTE_ORDER BYTE_ORDER
+# elif defined(__QNX__) || defined(__QNXNTO__)
+#  include <gulliver.h>
+#  if defined(__LITTLEENDIAN__)
+#   define __BYTE_ORDER __LITTLE_ENDIAN
 #  endif
+#  define htole16(x) ENDIAN_LE16(x)
+#  define htole32(x) ENDIAN_LE32(x)
+#  define htole64(x) ENDIAN_LE64(x)
+#  define le16toh(x) ENDIAN_LE16(x)
+#  define le32toh(x) ENDIAN_LE32(x)
+#  define le64toh(x) ENDIAN_LE64(x)
+# endif
 # if ( __BYTE_ORDER != __LITTLE_ENDIAN )
 #  define UA_NON_LITTLEENDIAN_ARCHITECTURE
 # endif
 #endif
 
-/* Force non-little endian manually by setting the following. */
-// #define UA_NON_LITTLEENDIAN_ARCHITECTURE
-// #define htole16(x) {...}(x)
-// #define htole32(x) {...}(x)
-// #define htole64(x) {...}(x)
-// #define le16toh(x) {...}(x)
-// #define le32toh(x) {...}(x)
-// #define le64toh(x) {...}(x)
+/* Manually override */
+// If required, define UA_NON_LITTLEENDIAN_ARCHITECTURE, UA_MIXED_ENDIAN, and
+// the htole / letoh functions here. Even better, post an issue on github or the
+// mailing list, so we can include the architecture in the standard release.
+#define swap16(u16) ((u16 >> 8) | (u16 << 8))
+#define swap32(u32) ((u32 >> 24) | ((u32 << 8) & 0x00FF0000) | ((u32 >> 8) & 0x0000FF00) | (u32 << 24))
+#define swap64(u64) ((u64 >> 56) | ((u64 << 40) & 0x00FF000000000000) | ((u64 << 24) & 0x0000FF0000000000) | \
+                     ((u64 << 8) & 0x000000FF00000000) | ((u64 >> 8) & 0x00000000FF000000) |                 \
+                     ((u64 >> 24) & 0x0000000000FF0000) | ((u64 >> 40) & 0x000000000000FF00) | (u64 << 56))
 
-/* Mixed Endian */
 #ifdef __ARM_ARCH_4T__
 # define UA_MIXED_ENDIAN
 # define UA_NON_LITTLEENDIAN_ARCHITECTURE
+# define htole16(x) swap16(x)
+# define htole32(x) swap32(x)
+# define htole64(x) swap64(x)
+# define le16toh(x) swap16(x)
+# define le32toh(x) swap32(x)
+# define le64toh(x) swap64(x)
 #endif
 
-/* Aligned Memory Access */
-#if defined(__arm__) && !defined(__ARM_FEATURE_UNALIGNED)
-# define UA_ALIGNED_MEMORY_ACCESS
+#ifndef htole16
+# error The endianness of the architecture not known
 #endif
 
 /* Inline Functions */
@@ -99,7 +145,7 @@
 #endif
 
 #include <stddef.h>
-#ifdef UA_EMBEDDED_LIBC
+#ifdef UA_ENABLE_EMBEDDED_LIBC
   void *memcpy(void *UA_RESTRICT dest, const void *UA_RESTRICT src, size_t n);
   void *memset(void *dest, int c, size_t n);
   size_t strlen(const char *s);

+ 152 - 131
include/ua_server.h

@@ -28,51 +28,58 @@ extern "C" {
 #include "ua_job.h"
 #include "ua_connection.h"
 
-/*********************************/
-/* Initialize and run the server */
-/*********************************/
+/*****************/
+/* Server Config */
+/*****************/
 
-typedef struct UA_ServerConfig {
-    UA_Boolean  Login_enableAnonymous;
+struct UA_ServerNetworkLayer; // forwards declaration
+typedef struct UA_ServerNetworkLayer UA_ServerNetworkLayer;    
 
-    UA_Boolean  Login_enableUsernamePassword;
-    char**      Login_usernames;
-    char**      Login_passwords;
-    UA_UInt32   Login_loginsCount;
+typedef struct {
+    UA_String username;
+    UA_String password;
+} UA_UsernamePasswordLogin;
 
-    char*       Application_applicationURI;
-    char*       Application_applicationName;
+typedef struct {
+    UA_UInt16 nThreads; // only if multithreading is enabled
+    UA_Logger logger;
+
+    UA_BuildInfo buildInfo;
+    UA_ApplicationDescription applicationDescription;
+    UA_ByteString serverCertificate;
+
+    size_t networkLayersSize;
+    UA_ServerNetworkLayer *networkLayers;
+
+    UA_Boolean enableAnonymousLogin;
+    UA_Boolean enableUsernamePasswordLogin;
+    size_t usernamePasswordLoginsSize;
+    UA_UsernamePasswordLogin usernamePasswordLogins[];
 } UA_ServerConfig;
 
 extern UA_EXPORT const UA_ServerConfig UA_ServerConfig_standard;
 
-UA_Server UA_EXPORT * UA_Server_new(UA_ServerConfig config);
-void UA_EXPORT UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate);
-void UA_EXPORT UA_Server_delete(UA_Server *server);
+/*********************************/
+/* Initialize and run the server */
+/*********************************/
 
-/** Sets the logger used by the server */
-void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
+UA_Server UA_EXPORT * UA_Server_new(const UA_ServerConfig config);
+void UA_EXPORT UA_Server_delete(UA_Server *server);
 
 /**
  * Runs the main loop of the server. In each iteration, this calls into the networklayers to see if
  * jobs have arrived and checks if repeated jobs need to be triggered.
- *
- * @param server The server object
- * @param nThreads The number of worker threads. Is ignored if MULTITHREADING is not activated.
- * @param running Points to a boolean value on the heap. When running is set to false, the worker
- *        threads and the main loop close and the server is shut down.
- * @return Indicates whether the server shut down cleanly
  */
-UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
+UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, volatile UA_Boolean *running);
 
 /** 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);
+UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server);
 
 /** One iteration of UA_Server_run (no need to use if you call UA_Server_run) */
-UA_StatusCode UA_EXPORT UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running);
+UA_StatusCode UA_EXPORT UA_Server_run_iterate(UA_Server *server);
+
+/** 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);
 
 /**
  * @param server The server object.
@@ -97,6 +104,9 @@ UA_StatusCode UA_EXPORT UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
  */
 UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId);
 
+/** @brief Add a new namespace to the server. Returns the index of the new namespace */
+UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
+
 /**
  * Interface to the binary network layers. This structure is returned from the
  * function that initializes the network layer. The layer is already bound to a
@@ -104,9 +114,9 @@ UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid j
  * in parallel but only sequentially from the server's main loop. So the network
  * layer does not need to be thread-safe.
  */
-typedef struct UA_ServerNetworkLayer {
+struct UA_ServerNetworkLayer {
+    void *handle; // pointer to internal data
     UA_String discoveryUrl;
-    UA_Logger logger; ///< Set during _start
 
     /**
      * Starts listening on the the networklayer.
@@ -115,7 +125,7 @@ typedef struct UA_ServerNetworkLayer {
      * @param logger The logger
      * @return Returns UA_STATUSCODE_GOOD or an error code.
      */
-    UA_StatusCode (*start)(struct UA_ServerNetworkLayer *nl, UA_Logger logger);
+    UA_StatusCode (*start)(UA_ServerNetworkLayer *nl);
     
     /**
      * Gets called from the main server loop and returns the jobs (accumulated messages and close
@@ -127,7 +137,7 @@ typedef struct UA_ServerNetworkLayer {
      * @param timeout The timeout during which an event must arrive in microseconds
      * @return The size of the jobs array. If the result is negative, an error has occurred.
      */
-    size_t (*getJobs)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
+    size_t (*getJobs)(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
 
     /**
      * Closes the network connection and returns all the jobs that need to be finished before the
@@ -138,22 +148,11 @@ typedef struct UA_ServerNetworkLayer {
      * returned size.
      * @return The size of the jobs array. If the result is negative, an error has occurred.
      */
-    size_t (*stop)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs);
-
-    /** Deletes the network layer. Call only after a successful shutdown. */
-    void (*deleteMembers)(struct UA_ServerNetworkLayer *nl);
-} UA_ServerNetworkLayer;
-
-/**
- * Adds a network layer to the server. The network layer is destroyed together
- * with the server. Do not use it after adding it as it might be moved around on
- * the heap.
- */
-void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *networkLayer);
-
-/** @brief Add a new namespace to the server. Returns the index of the new namespace */
-UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
+    size_t (*stop)(UA_ServerNetworkLayer *nl, UA_Job **jobs);
 
+    /** Deletes the network content. Call only after stopping. */
+    void (*deleteMembers)(UA_ServerNetworkLayer *nl);
+};
 
 /**********************/
 /* Set Node Callbacks */
@@ -162,7 +161,7 @@ UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
 /**
  * Datasources are the interface to local data providers. It is expected that
  * the read and release callbacks are implemented. The write callback can be set
- * to null.
+ * to null. The read callback is set to null will result in a BADINTERNALERROR.
  */
 typedef struct {
     void *handle; ///> A custom pointer to reuse the same datasource functions for multiple sources
@@ -225,8 +224,8 @@ typedef struct {
 } UA_ObjectLifecycleManagement;
 
 UA_StatusCode UA_EXPORT
-UA_Server_setObjectTypeNode_instanceLifecycleManagement(UA_Server *server, UA_NodeId nodeId,
-                                                        UA_ObjectLifecycleManagement olm);
+UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server, UA_NodeId nodeId,
+                                                UA_ObjectLifecycleManagement olm);
 
 /* Iterate over all nodes referenced by parentNodeId by calling the callback
    function for each child node */
@@ -241,6 +240,11 @@ UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
 /* Node Management */
 /*******************/
 
+typedef struct UA_InstantiationCallback_s {
+  UA_StatusCode (*method)(UA_NodeId objectId, UA_NodeId definitionId, void *handle);
+  void *handle;
+} UA_InstantiationCallback;
+
 UA_StatusCode UA_EXPORT
 UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
                        const UA_ExpandedNodeId targetId, UA_Boolean isForward);
@@ -258,70 +262,71 @@ UA_StatusCode UA_EXPORT
 __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                    const UA_NodeAttributes *attr, const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
+                    const UA_NodeAttributes *attr, const UA_DataType *attributeType, 
+                    UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId);
 
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                          const UA_VariableAttributes attr, UA_NodeId *outNewNodeId) {
+                          const UA_VariableAttributes attr, UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                               const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
-                              UA_NodeId *outNewNodeId) {
+                              UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
+                        const UA_ObjectAttributes attr, UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                             const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                             const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
-                            UA_NodeId *outNewNodeId) {
+                            UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                       const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                       const UA_QualifiedName browseName, const UA_ViewAttributes attr,
-                      UA_NodeId *outNewNodeId) {
+                      UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
-                               UA_NodeId *outNewNodeId) {
+                               UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
-                          UA_NodeId *outNewNodeId) {
+                          UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 UA_StatusCode UA_EXPORT
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
@@ -330,7 +335,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
                                     const UA_VariableAttributes attr, const UA_DataSource dataSource,
                                     UA_NodeId *outNewNodeId);
 
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
 typedef UA_StatusCode (*UA_MethodCallback)(void *methodHandle, const UA_NodeId objectId,
                                            size_t inputSize, const UA_Variant *input,
                                            size_t outputSize, UA_Variant *output);
@@ -349,13 +354,13 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 /* Write Node Attributes */
 /*************************/
 
-/* The following node attributes cannot be changed once the node is created
+/* The following node attributes cannot be written
    - NodeClass
    - NodeId
    - Symmetric
    - ContainsNoLoop
    
-   The following attributes cannot be written, as there is no "user" in the server
+   The following attributes cannot be written from the server, as there is no "user" in the server
    - UserWriteMask
    - UserAccessLevel
    - UserExecutable
@@ -371,51 +376,52 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 
 /* Don't use this function. There are typed versions with no additional overhead. */
 UA_StatusCode UA_EXPORT
-__UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId, const UA_DataType *type, const void *value);
+__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId, const UA_AttributeId attributeId,
+                  const UA_DataType *type, const void *value);
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeBrowseNameAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); }
+UA_Server_writeBrowseName(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeDisplayNameAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText displayName) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); }
+UA_Server_writeDisplayName(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText displayName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeDescriptionAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText description) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); }
+UA_Server_writeDescription(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText description) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeWriteMaskAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 writeMask) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK, &UA_TYPES[UA_TYPES_UINT32], &writeMask); }
+UA_Server_writeWriteMask(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 writeMask) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, &UA_TYPES[UA_TYPES_UINT32], &writeMask); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeIsAbstractAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean isAbstract) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); }
+UA_Server_writeIsAbstract(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean isAbstract) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeInverseNameAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText inverseName) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); }
+UA_Server_writeInverseName(UA_Server *server, const UA_NodeId nodeId, const UA_LocalizedText inverseName) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeEventNotifierAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Byte eventNotifier) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); }
+UA_Server_writeEventNotifier(UA_Server *server, const UA_NodeId nodeId, const UA_Byte eventNotifier) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeValueAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Variant value) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); }
+UA_Server_writeValue(UA_Server *server, const UA_NodeId nodeId, const UA_Variant value) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeAccessLevelAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 accessLevel) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }
+UA_Server_writeAccessLevel(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 accessLevel) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeMinimumSamplingIntervalAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Double miniumSamplingInterval) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval); }
+UA_Server_writeMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, const UA_Double miniumSamplingInterval) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_writeExecutableAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean executable) {
-    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE, &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
+UA_Server_writeExecutable(UA_Server *server, const UA_NodeId nodeId, const UA_Boolean executable) {
+    return __UA_Server_write(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
 
 /************************/
 /* Read Node Attributes */
@@ -429,84 +435,99 @@ UA_Server_writeExecutableAttribute(UA_Server *server, const UA_NodeId nodeId, co
 
 /* Don't use this function. There are typed versions for every supported attribute. */
 UA_StatusCode UA_EXPORT
-__UA_Server_readAttribute(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void *v);
+__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId, UA_AttributeId attributeId, void *v);
   
 static UA_INLINE UA_StatusCode
-UA_Server_readNodeIdAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outNodeId) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
+UA_Server_readNodeId(UA_Server *server, const UA_NodeId nodeId, UA_NodeId *outNodeId) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readNodeClassAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
+UA_Server_readNodeClass(UA_Server *server, const UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readBrowseNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
+UA_Server_readBrowseName(UA_Server *server, const UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readDisplayNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
+UA_Server_readDisplayName(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readDescriptionAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDescription) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
+UA_Server_readDescription(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *outDescription) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readWriteMaskAttribute(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK, outWriteMask); }
+UA_Server_readWriteMask(UA_Server *server, const UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_WRITEMASK, outWriteMask); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readIsAbstractAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
+UA_Server_readIsAbstract(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readSymmetricAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outSymmetric) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
+UA_Server_readSymmetric(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outSymmetric) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readInverseNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
+UA_Server_readInverseName(UA_Server *server, const UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readContainsNoLoopAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
+UA_Server_readContainsNoLoop(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readEventNotifierAttribute(UA_Server *server, UA_NodeId nodeId, UA_Byte *outEventNotifier) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
+UA_Server_readEventNotifier(UA_Server *server, const UA_NodeId nodeId, UA_Byte *outEventNotifier) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readValueAttribute(UA_Server *server, UA_NodeId nodeId, UA_Variant *outValue) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
+UA_Server_readValue(UA_Server *server, const UA_NodeId nodeId, UA_Variant *outValue) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readDataTypeAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outDataType) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
+UA_Server_readDataType(UA_Server *server, const UA_NodeId nodeId, UA_NodeId *outDataType) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readValueRankAttribute(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outValueRank) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
+UA_Server_readValueRank(UA_Server *server, const UA_NodeId nodeId, UA_Int32 *outValueRank) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
 
-// todo: fetch an array with a length field
+/* Returns a variant with an int32 array */
 static UA_INLINE UA_StatusCode
-UA_Server_readArrayDimensionsAttribute(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outArrayDimensions) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
+UA_Server_readArrayDimensions(UA_Server *server, const UA_NodeId nodeId, UA_Variant *outArrayDimensions) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readAccessLevelAttribute(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, outAccessLevel); }
+UA_Server_readAccessLevel(UA_Server *server, const UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, outAccessLevel); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readMinimumSamplingIntervalAttribute(UA_Server *server, UA_NodeId nodeId, UA_Double *outMinimumSamplingInterval) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, outMinimumSamplingInterval); }
+UA_Server_readMinimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId, UA_Double *outMinimumSamplingInterval) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL, outMinimumSamplingInterval); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readHistorizingAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outHistorizing) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
+UA_Server_readHistorizing(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outHistorizing) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_readExecutableAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outExecutable) {
-    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE, outExecutable); }
+UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId, UA_Boolean *outExecutable) {
+    return __UA_Server_read(server, &nodeId, UA_ATTRIBUTEID_EXECUTABLE, outExecutable); }
+
+/****************/
+/* Browse Nodes */
+/****************/
+
+UA_BrowseResult UA_EXPORT UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs, const UA_BrowseDescription *descr);
+UA_BrowseResult UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint, const UA_ByteString *continuationPoint);
+
+/***************/
+/* Call Method */
+/***************/
+
+#ifdef UA_ENABLE_METHODCALLS
+UA_CallMethodResult UA_EXPORT UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
+#endif
 
 #ifdef __cplusplus
 }

+ 56 - 33
include/ua_types.h

@@ -72,6 +72,9 @@ typedef uint32_t UA_UInt32;
 #define UA_UINT32_MAX 4294967295
 #define UA_UINT32_MIN 0
 
+/* do not use for cryptographic entropy */
+UA_EXPORT UA_UInt32 UA_UInt32_random(void);
+
 /** Int64: An integer value between -10 223 372 036 854 775 808 and 9 223 372 036 854 775 807 */
 typedef int64_t UA_Int64;
 #define UA_INT64_MAX (int64_t)9223372036854775807
@@ -112,11 +115,24 @@ UA_Boolean UA_EXPORT UA_String_equal(const UA_String *s1, const UA_String *s2);
 /*********************************/
 /* DateTime: An instance in time */
 /*********************************/
+
 /* A DateTime value is encoded as a 64-bit signed integer which represents the
    number of 100 nanosecond intervals since January 1, 1601 (UTC) */
 typedef UA_Int64 UA_DateTime;
 
-UA_DateTime UA_EXPORT UA_DateTime_now(void); ///> The current time
+/* Multiply to convert units for time difference computations */
+#define UA_USEC_TO_DATETIME 10LL
+#define UA_MSEC_TO_DATETIME (UA_USEC_TO_DATETIME * 1000LL)
+#define UA_SEC_TO_DATETIME (UA_MSEC_TO_DATETIME * 1000LL)
+
+/* Datetime of 1 Jan 1970 00:00 UTC */
+#define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_SEC_TO_DATETIME)
+
+/* The current time */
+UA_DateTime UA_EXPORT UA_DateTime_now(void);
+
+/* CPU clock invariant to system time changes. Use only for time diffs, not current time */
+UA_DateTime UA_EXPORT UA_DateTime_nowMonotonic(void);
 
 typedef struct UA_DateTimeStruct {
     UA_UInt16 nanoSec;
@@ -146,18 +162,20 @@ typedef struct {
 
 UA_Boolean UA_EXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
 
-UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
+/* do not use for cryptographic entropy */
+UA_Guid UA_EXPORT UA_Guid_random(void);
 
 /************************************/
 /* ByteString: A sequence of octets */
 /************************************/
 typedef UA_String UA_ByteString;
 
-static UA_INLINE UA_Boolean UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2) {
+static UA_INLINE UA_Boolean
+UA_ByteString_equal(const UA_ByteString *string1, const UA_ByteString *string2) {
     return UA_String_equal((const UA_String*)string1, (const UA_String*)string2); }
 
 /* Allocates memory of size length for the bytestring. The content is not set to zero. */
-UA_StatusCode UA_EXPORT UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+UA_StatusCode UA_EXPORT UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length);
 
 UA_EXPORT extern const UA_ByteString UA_BYTESTRING_NULL;
 
@@ -342,8 +360,8 @@ typedef struct {
 } UA_Variant;
 
 /**
- * Returns true if the variant contains a scalar value. Note that empty variants contain an array of
- * length -1 (undefined).
+ * Returns true if the variant contains a scalar value. Note that empty variants
+ * contain an array of length -1 (undefined).
  *
  * @param v The variant
  * @return Does the variant contain a scalar value.
@@ -352,14 +370,15 @@ static UA_INLINE UA_Boolean UA_Variant_isScalar(const UA_Variant *v) {
     return (v->arrayLength == 0 && v->data > UA_EMPTY_ARRAY_SENTINEL); }
     
 /**
- * Set the variant to a scalar value that already resides in memory. The value takes on the
- * lifecycle of the variant and is deleted with it.
+ * Set the variant to a scalar value that already resides in memory. The value
+ * takes on the lifecycle of the variant and is deleted with it.
  *
  * @param v The variant
  * @param p A pointer to the value data
  * @param type The datatype of the value in question
  */
-void UA_EXPORT UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type);
+void UA_EXPORT
+UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const UA_DataType *type);
 
 /**
  * Set the variant to a scalar value that is copied from an existing variable.
@@ -369,11 +388,12 @@ void UA_EXPORT UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p, const U
  * @param type The datatype of the value
  * @return Indicates whether the operation succeeded or returns an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type);
+UA_StatusCode UA_EXPORT
+UA_Variant_setScalarCopy(UA_Variant *v, const void *p, const UA_DataType *type);
 
 /**
- * Set the variant to an array that already resides in memory. The array takes on the lifecycle of
- * the variant and is deleted with it.
+ * Set the variant to an array that already resides in memory. The array takes
+ * on the lifecycle of the variant and is deleted with it.
  *
  * @param v The variant
  * @param array A pointer to the array data
@@ -381,7 +401,8 @@ UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, c
  * @param type The datatype of the array
  */
 void UA_EXPORT
-UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_DataType *type);
+UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array,
+                    size_t arraySize, const UA_DataType *type);
 
 /**
  * Set the variant to an array that is copied from an existing array.
@@ -393,7 +414,8 @@ UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, c
  * @return Indicates whether the operation succeeded or returns an error code
  */
 UA_StatusCode UA_EXPORT
-UA_Variant_setArrayCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_DataType *type);
+UA_Variant_setArrayCopy(UA_Variant *v, const void *array,
+                        size_t arraySize, const UA_DataType *type);
 
 /* NumericRanges are used to indicate subsets of a (multidimensional) variant
  * array. NumericRange has no official type structure in the standard. On the
@@ -432,7 +454,8 @@ UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRan
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
 UA_StatusCode UA_EXPORT
-UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_NumericRange range);
+UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array,
+                    size_t arraySize, const UA_NumericRange range);
 
 /**
  * Deep-copy a range of data into an existing variant.
@@ -444,7 +467,8 @@ UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, c
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
 UA_StatusCode UA_EXPORT
-UA_Variant_setRangeCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_NumericRange range);
+UA_Variant_setRangeCopy(UA_Variant *v, const void *array,
+                        size_t arraySize, const UA_NumericRange range);
 
 /**************************************************************************/
 /* DataValue: A data value with an associated status code and timestamps. */
@@ -459,9 +483,9 @@ typedef struct {
     UA_Variant    value;
     UA_StatusCode status;
     UA_DateTime   sourceTimestamp;
-    UA_Int16      sourcePicoseconds;
+    UA_UInt16     sourcePicoseconds;
     UA_DateTime   serverTimestamp;
-    UA_Int16      serverPicoseconds;
+    UA_UInt16     serverPicoseconds;
 } UA_DataValue;
 
 /***************************************************************************/
@@ -489,24 +513,24 @@ typedef struct UA_DiagnosticInfo {
 /* Generic Type Handling */
 /*************************/
 
-#define UA_MAX_TYPE_MEMBERS 13 // Maximum number of members per structured type
-
 typedef struct {
-#ifdef ENABLE_TYPEINTROSPECTION
+#ifdef UA_ENABLE_TYPENAMES
     const char *memberName;
 #endif
     UA_UInt16   memberTypeIndex;   ///< Index of the member in the datatypetable
-    UA_Byte     padding;           /**< How much padding is there before this member element? For 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) */
-    UA_Boolean  namespaceZero : 1; /**< The type of the member is defined in namespace zero. In this
-                                        implementation, types from custom namespace may contain
-                                        members from the same namespace or ns0 only.*/
+    UA_Byte     padding;           /**< How much padding is there before this member
+                                        element? For arrays this is the padding before the
+                                        size_t lenght member. (No padding between size_t
+                                        and the following ptr.) */
+    UA_Boolean  namespaceZero : 1; /**< The type of the member is defined in namespace
+                                        zero. In this implementation, types from custom
+                                        namespace may contain members from the same
+                                        namespace or ns0 only.*/
     UA_Boolean  isArray       : 1; ///< The member is an array of the given type
 } UA_DataTypeMember;
     
 struct UA_DataType {
-#ifdef ENABLE_TYPEINTROSPECTION
+#ifdef UA_ENABLE_TYPENAMES
     const char *typeName;
 #endif
     UA_NodeId   typeId;           ///< The nodeid of the type
@@ -516,7 +540,7 @@ struct UA_DataType {
     UA_Boolean  builtin      : 1; ///< The type is "builtin" and has dedicated de- and encoding functions
     UA_Boolean  fixedSize    : 1; ///< The type (and its members) contains no pointers
     UA_Boolean  zeroCopyable : 1; ///< The type can be copied directly off the stream (given that the endianness matches)
-    UA_DataTypeMember members[UA_MAX_TYPE_MEMBERS];
+    UA_DataTypeMember *members;
 };
 
 /**
@@ -546,7 +570,7 @@ static UA_INLINE void UA_init(void *p, const UA_DataType *type) {
  * @return Indicates whether the operation succeeded or returns an error code
  */
 UA_StatusCode UA_EXPORT
-UA_copy(const void *src, void *dst, const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+UA_copy(const void *src, void *dst, const UA_DataType *type);
 
 /**
  * Deletes the dynamically assigned content of a variable (e.g. a member-array).
@@ -647,11 +671,10 @@ typedef enum {
 /***************************/
 
 /**
- * If UA_MULTITHREADING is enabled, then the seed is stored in thread local storage. The seed is
- * initialized for every thread in the server/client.
+ * If UA_ENABLE_MULTITHREADING is defined, then the seed is stored in thread local
+ * storage. The seed is initialized for every thread in the server/client.
  */
 UA_EXPORT void UA_random_seed(UA_UInt64 seed);
-UA_EXPORT UA_UInt32 UA_random(void);
 
 #ifdef __cplusplus
 } // extern "C"

+ 8 - 10
src/client/ua_client.c

@@ -35,7 +35,7 @@ static void UA_Client_init(UA_Client* client, UA_ClientConfig config,
     client->config = config;
     client->scExpiresAt = 0;
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     client->monitoredItemHandles = 0;
     LIST_INIT(&client->pendingNotificationsAcks);
     LIST_INIT(&client->subscriptions);
@@ -58,7 +58,7 @@ static void UA_Client_deleteMembers(UA_Client* client) {
     if(client->endpointUrl.data)
         UA_String_deleteMembers(&client->endpointUrl);
     UA_UserTokenPolicy_deleteMembers(&client->token);
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     UA_Client_NotificationsAckNumber *n, *tmp;
     LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) {
         LIST_REMOVE(n, listEntry);
@@ -201,12 +201,12 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to renew the SecureChannel");
     } else {
         opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
-        UA_ByteString_init(&client->channel.clientNonce);
-        UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce);
-        opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "Requesting to open a SecureChannel");
     }
 
+    UA_ByteString_copy(&client->channel.clientNonce, &opnSecRq.clientNonce);
+    opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
+
     UA_ByteString message;
     UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD) {
@@ -288,15 +288,13 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     if(retval != UA_STATUSCODE_GOOD)
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
                      "SecureChannel could not be opened / renewed");
-    else if(!renew) {
+    else {
         UA_ChannelSecurityToken_copy(&response.securityToken, &client->channel.securityToken);
         /* if the handshake is repeated, replace the old nonce */
         UA_ByteString_deleteMembers(&client->channel.serverNonce);
         UA_ByteString_copy(&response.serverNonce, &client->channel.serverNonce);
-        UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened");
-    } else
-        UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel renewed");
-
+        UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL, "SecureChannel opened/renewed");
+    }
     UA_OpenSecureChannelResponse_deleteMembers(&response);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
     return retval;

+ 2 - 2
src/client/ua_client_internal.h

@@ -8,7 +8,7 @@
 /* Subscriptions Handling */
 /**************************/
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 
 typedef struct UA_Client_NotificationsAckNumber_s {
     UA_SubscriptionAcknowledgement subAck;
@@ -68,7 +68,7 @@ struct UA_Client {
     UA_NodeId authenticationToken;
     UA_UInt32 requestHandle;
     
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     UA_Int32 monitoredItemHandles;
     LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
     LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;

+ 3 - 3
src/server/ua_nodes.c

@@ -328,7 +328,7 @@ UA_MethodNode * UA_MethodNode_new(void) {
 }
 
 void UA_MethodNode_deleteMembers(UA_MethodNode *p) {
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     p->attachedMethod = NULL;
 #endif
     UA_Node_deleteMembers((UA_Node*)p);
@@ -336,7 +336,7 @@ void UA_MethodNode_deleteMembers(UA_MethodNode *p) {
 
 void UA_MethodNode_delete(UA_MethodNode *p) {
     UA_MethodNode_deleteMembers(p);
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     p->methodHandle   = NULL;
     p->attachedMethod = NULL;
 #endif
@@ -349,7 +349,7 @@ UA_StatusCode UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
         return retval;
     dst->executable = src->executable;
     dst->userExecutable = src->userExecutable;
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     dst->methodHandle  = src->methodHandle;
     dst->attachedMethod = src->attachedMethod;
 #endif

+ 1 - 1
src/server/ua_nodes.h

@@ -127,7 +127,7 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_Boolean executable;
     UA_Boolean userExecutable;
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     void *methodHandle;
     UA_MethodCallback attachedMethod;
 #endif

+ 1 - 1
src/server/ua_nodestore.h

@@ -26,7 +26,7 @@
  */
 
 /* For multithreading, nodes in the nodestore are immutable */
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 # define UA_MT_CONST const
 #else
 # define UA_MT_CONST

+ 3 - 3
src/server/ua_securechannel_manager.c

@@ -33,7 +33,7 @@ void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_Dat
         if(timeout < now || !entry->channel.connection) {
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
-#ifndef UA_MULTITHREADING
+#ifndef UA_ENABLE_MULTITHREADING
             cm->currentChannelCount--;
 #else
             cm->currentChannelCount = uatomic_add_return(
@@ -57,7 +57,7 @@ UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
     channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
     if(!entry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
-#ifndef UA_MULTITHREADING
+#ifndef UA_ENABLE_MULTITHREADING
     cm->currentChannelCount++;
 #else
     cm->currentChannelCount = uatomic_add_return(&cm->currentChannelCount, 1);
@@ -141,7 +141,7 @@ UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
             UA_free(entry);
-#ifndef UA_MULTITHREADING
+#ifndef UA_ENABLE_MULTITHREADING
             cm->currentChannelCount--;
 #else
             cm->currentChannelCount = uatomic_add_return(&cm->currentChannelCount, -1);

+ 142 - 204
src/server/ua_server.c

@@ -6,20 +6,50 @@
 #include "ua_services.h"
 #include "ua_nodeids.h"
 
-#ifdef ENABLE_GENERATE_NAMESPACE0
+#ifdef UA_ENABLE_GENERATE_NAMESPACE0
 #include "ua_namespaceinit_generated.h"
 #endif
 
-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" };
-
-#if defined(UA_MULTITHREADING) && !defined(NDEBUG)
+#define MANUFACTURER_NAME "open62541"
+#define PRODUCT_NAME "open62541 OPC UA Server"
+#define PRODUCT_URI "urn:unconfigured:open62541"
+#define UA_STRING_STATIC(s) {sizeof(s)-1, (UA_Byte*)s}
+#define UA_STRING_STATIC_NULL {0, NULL}
+
+const UA_ServerConfig UA_ServerConfig_standard = {
+    .nThreads = 1,
+    .logger = NULL,
+
+    .buildInfo = {
+        .productUri = UA_STRING_STATIC(PRODUCT_URI),
+        .manufacturerName = UA_STRING_STATIC(MANUFACTURER_NAME),
+        .productName = UA_STRING_STATIC(PRODUCT_NAME),
+        .softwareVersion = UA_STRING_STATIC("0"),
+        .buildNumber = UA_STRING_STATIC("0"),
+        .buildDate = 0},
+    .applicationDescription = {
+        .applicationUri = UA_STRING_STATIC("urn:unconfigured:application"),
+        .productUri = UA_STRING_STATIC("urn:unconfigured:product"),
+        .applicationName = { .locale = UA_STRING_STATIC(""), .text = UA_STRING_STATIC("open62541Server") },
+        .applicationType = UA_APPLICATIONTYPE_SERVER,
+        .gatewayServerUri = UA_STRING_STATIC_NULL,
+        .discoveryProfileUri = UA_STRING_STATIC_NULL,
+        .discoveryUrlsSize = 0,
+        .discoveryUrls = NULL
+    },
+    .serverCertificate = UA_STRING_STATIC_NULL,
+
+    .networkLayersSize = 0, .networkLayers = NULL,
+
+    .enableAnonymousLogin = UA_TRUE,
+    .enableUsernamePasswordLogin = UA_TRUE,
+    .usernamePasswordLogins =
+    { { UA_STRING_STATIC("user1"), UA_STRING_STATIC("password") },
+      { UA_STRING_STATIC("uset2"), UA_STRING_STATIC("password1") } },
+    .usernamePasswordLoginsSize = 2
+};
+
+#if defined(UA_ENABLE_MULTITHREADING) && !defined(NDEBUG)
 UA_THREAD_LOCAL bool rcu_locked = UA_FALSE;
 #endif
 
@@ -44,7 +74,7 @@ static const UA_ExpandedNodeId expandedNodeIdBaseDataVariabletype = {
                .identifier.numeric = UA_NS0ID_BASEDATAVARIABLETYPE},
     .namespaceUri = {.length = -1, .data = NULL}, .serverIndex = 0};
 
-#ifndef ENABLE_GENERATE_NAMESPACE0
+#ifndef UA_ENABLE_GENERATE_NAMESPACE0
 static const UA_NodeId nodeIdNonHierarchicalReferences = {
         .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
         .identifier.numeric = UA_NS0ID_NONHIERARCHICALREFERENCES};
@@ -54,7 +84,7 @@ static const UA_NodeId nodeIdNonHierarchicalReferences = {
 /* Namespace Handling */
 /**********************/
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 static void UA_ExternalNamespace_init(UA_ExternalNamespace *ens) {
     ens->index = 0;
     UA_String_init(&ens->url);
@@ -96,7 +126,7 @@ UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex,
     server->externalNamespacesSize++;
     return UA_STATUSCODE_GOOD;
 }
-#endif /* UA_EXTERNAL_NAMESPACES*/
+#endif /* UA_ENABLE_EXTERNAL_NAMESPACES*/
 
 UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
     server->namespaces = UA_realloc(server->namespaces,
@@ -106,8 +136,8 @@ UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
     return (UA_UInt16)server->namespacesSize - 1;
 }
 
-UA_StatusCode UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
-                                   UA_Boolean deleteReferences) {
+UA_StatusCode
+UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId, UA_Boolean deleteReferences) {
     UA_RCU_LOCK();
     UA_StatusCode retval = Service_DeleteNodes_single(server, &adminSession, &nodeId, deleteReferences);
     UA_RCU_UNLOCK();
@@ -192,7 +222,8 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                     const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
-                    const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
+                    const UA_DataType *attributeType, 
+                    UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
     item.parentNodeId.nodeId = parentNodeId;
@@ -206,7 +237,7 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
     UA_RCU_LOCK();
-    Service_AddNodes_single(server, &adminSession, &item, &result);
+    Service_AddNodes_single(server, &adminSession, &item, &result, instantiationCallback);
     UA_RCU_UNLOCK();
 
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
@@ -216,48 +247,6 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
     return result.statusCode;
 }
 
-/*****************/
-/* Configuration */
-/*****************/
-
-void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *networkLayer) {
-    UA_ServerNetworkLayer **newlayers =
-        UA_realloc(server->networkLayers, sizeof(void*)*(server->networkLayersSize+1));
-    if(!newlayers) {
-        UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Networklayer added");
-        return;
-    }
-    server->networkLayers = newlayers;
-    server->networkLayers[server->networkLayersSize] = networkLayer;
-    server->networkLayersSize++;
-
-    UA_String* newUrls = UA_realloc(server->description.discoveryUrls,
-                                    sizeof(UA_String)*(server->description.discoveryUrlsSize+1));
-    if(!newUrls) {
-        UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Adding discoveryUrl");
-        return;
-    }
-    server->description.discoveryUrls = newUrls;
-    UA_String_copy(&networkLayer->discoveryUrl,
-                   &server->description.discoveryUrls[server->description.discoveryUrlsSize]);
-    server->description.discoveryUrlsSize++;
-    for(size_t i = 0; i < server->endpointDescriptionsSize; i++) {
-        if(!server->endpointDescriptions[i].endpointUrl.data)
-            UA_String_copy(&networkLayer->discoveryUrl,
-                           &server->endpointDescriptions[i].endpointUrl);
-    }
-}
-
-void UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate) {
-    for(size_t i = 0; i < server->endpointDescriptionsSize; i++)
-        UA_ByteString_copy(&certificate,
-                           &server->endpointDescriptions[i].serverCertificate);
-}
-
-void UA_Server_setLogger(UA_Server *server, UA_Logger logger) {
-    server->logger = logger;
-}
-
 /**********/
 /* Server */
 /**********/
@@ -269,29 +258,18 @@ void UA_Server_delete(UA_Server *server) {
     UA_Server_deleteAllRepeatedJobs(server);
 
     // Delete all internal data
-    UA_ApplicationDescription_deleteMembers(&server->description);
     UA_SecureChannelManager_deleteMembers(&server->secureChannelManager);
     UA_SessionManager_deleteMembers(&server->sessionManager, server);
     UA_NodeStore_delete(server->nodestore);
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
     UA_Server_deleteExternalNamespaces(server);
 #endif
-    UA_ByteString_deleteMembers(&server->serverCertificate);
     UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
     UA_Array_delete(server->endpointDescriptions, server->endpointDescriptionsSize,
                     &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
 
-    // Delete the network layers
-    for(size_t i = 0; i < server->networkLayersSize; i++) {
-        UA_String_deleteMembers(&server->networkLayers[i]->discoveryUrl);
-        server->networkLayers[i]->deleteMembers(server->networkLayers[i]);
-        UA_free(server->networkLayers[i]);
-    }
-    UA_free(server->networkLayers);
-
     UA_RCU_UNLOCK();
-#ifdef UA_MULTITHREADING
-    /* so the workers don't spin if the queue is empty */
+#ifdef UA_ENABLE_MULTITHREADING
     pthread_cond_destroy(&server->dispatchQueue_condition);
     rcu_barrier(); // wait for all scheduled call_rcu work to complete
    	rcu_unregister_thread();
@@ -306,22 +284,6 @@ static void UA_Server_cleanup(UA_Server *server, void *nothing) {
     UA_SecureChannelManager_cleanupTimedOut(&server->secureChannelManager, now);
 }
 
-#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 getBuildInfo(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, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
            const UA_NumericRange *range, UA_DataValue *value) {
@@ -336,7 +298,6 @@ readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
     status->startTime = server->startTime;
     status->currentTime = UA_DateTime_now();
     status->state = UA_SERVERSTATE_RUNNING;
-    getBuildInfo(server, &status->buildInfo);
     status->secondsTillShutdown = 0;
 
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
@@ -444,16 +405,15 @@ addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletyp
     addNodeInternal(server, (UA_Node*)variabletype, UA_NODEID_NUMERIC(0, parent), nodeIdHasSubType);
 }
 
-UA_Server * UA_Server_new(UA_ServerConfig config) {
+UA_Server * UA_Server_new(const UA_ServerConfig config) {
     UA_Server *server = UA_calloc(1, sizeof(UA_Server));
     if(!server)
         return NULL;
 
-    //FIXME: config contains strings, for now its okay, but consider copying them aswell
     server->config = config;
 
     LIST_INIT(&server->repeatedJobs);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     rcu_init();
    	rcu_register_thread();
     cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
@@ -461,65 +421,54 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_RCU_LOCK();
 #endif
 
-    // random seed
-    server->random_seed = (UA_UInt32)UA_DateTime_now();
-
-    // mockup application description
-    UA_ApplicationDescription_init(&server->description);
-    server->description.productUri = UA_STRING_ALLOC(PRODUCT_URI);
-    server->description.applicationUri = UA_STRING_ALLOC(server->config.Application_applicationURI);
-
-    server->description.applicationName =
-        UA_LOCALIZEDTEXT_ALLOC("en_US", server->config.Application_applicationName);
-    server->description.applicationType = UA_APPLICATIONTYPE_SERVER;
+    /* uncomment for non-reproducible server runs */
+    //UA_random_seed(UA_DateTime_now());
 
     /* ns0 and ns1 */
     server->namespaces = UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
     server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
-    UA_String_copy(&server->description.applicationUri, &server->namespaces[1]);
+    UA_String_copy(&server->config.applicationDescription.applicationUri, &server->namespaces[1]);
     server->namespacesSize = 2;
 
-    UA_EndpointDescription *endpoint = UA_EndpointDescription_new(); // todo: check return code
-    if(endpoint) {
+    server->endpointDescriptions = UA_Array_new(server->config.networkLayersSize,
+                                                &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+    server->endpointDescriptionsSize = server->config.networkLayersSize;
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_EndpointDescription *endpoint = &server->endpointDescriptions[i];
         endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
         endpoint->securityPolicyUri =
             UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
         endpoint->transportProfileUri =
             UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
 
-        int size = 0;
-        if(server->config.Login_enableAnonymous){
-            size++;
-        }
-        if(server->config.Login_enableUsernamePassword){
-            size++;
-        }
-        endpoint->userIdentityTokensSize = size;
-        endpoint->userIdentityTokens = UA_Array_new(size, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+        size_t policies = 0;
+        if(server->config.enableAnonymousLogin)
+            policies++;
+        if(server->config.enableUsernamePasswordLogin)
+            policies++;
+        endpoint->userIdentityTokensSize = policies;
+        endpoint->userIdentityTokens = UA_Array_new(policies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
 
-        int currentIndex = 0;
-        if(server->config.Login_enableAnonymous){
+        size_t currentIndex = 0;
+        if(server->config.enableAnonymousLogin) {
             UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
             endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
-            endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY); // defined per server
+            endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY);
             currentIndex++;
         }
-
-        if(server->config.Login_enableUsernamePassword){
+        if(server->config.enableUsernamePasswordLogin) {
             UA_UserTokenPolicy_init(&endpoint->userIdentityTokens[currentIndex]);
             endpoint->userIdentityTokens[currentIndex].tokenType = UA_USERTOKENTYPE_USERNAME;
-            endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(USERNAME_POLICY); // defined per server
-            currentIndex++;
+            endpoint->userIdentityTokens[currentIndex].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
         }
 
         /* The standard says "the HostName specified in the Server Certificate is the
            same as the HostName contained in the endpointUrl provided in the
            EndpointDescription */
-        /* UA_String_copy(endpointUrl, &endpoint->endpointUrl); */
-        /* UA_String_copy(&server->serverCertificate, &endpoint->serverCertificate); */
-        UA_ApplicationDescription_copy(&server->description, &endpoint->server);
-        server->endpointDescriptions = endpoint;
-        server->endpointDescriptionsSize = 1;
+        UA_String_copy(&server->config.networkLayers[i].discoveryUrl, &endpoint->endpointUrl);
+        UA_String_copy(&server->config.serverCertificate, &endpoint->serverCertificate);
+
+        UA_ApplicationDescription_copy(&server->config.applicationDescription, &endpoint->server);
     } 
 
 #define MAXCHANNELCOUNT 100
@@ -545,46 +494,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     /**********************/
 
     server->startTime = UA_DateTime_now();
-    static struct tm ct;
-    ct.tm_year = (__DATE__[7] - '0') * 1000 + (__DATE__[8] - '0') * 100 +
-        (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0')- 1900;
-
-    if(__DATE__[0]=='J' && __DATE__[1]=='a' && __DATE__[2]=='n') ct.tm_mon = 1-1;
-    else if(__DATE__[0]=='F' && __DATE__[1]=='e' && __DATE__[2]=='b') ct.tm_mon = 2-1;
-    else if(__DATE__[0]=='M' && __DATE__[1]=='a' && __DATE__[2]=='r') ct.tm_mon = 3-1;
-    else if(__DATE__[0]=='A' && __DATE__[1]=='p' && __DATE__[2]=='r') ct.tm_mon = 4-1;
-    else if(__DATE__[0]=='M' && __DATE__[1]=='a' && __DATE__[2]=='y') ct.tm_mon = 5-1;
-    else if(__DATE__[0]=='J' && __DATE__[1]=='u' && __DATE__[2]=='n') ct.tm_mon = 6-1;
-    else if(__DATE__[0]=='J' && __DATE__[1]=='u' && __DATE__[2]=='l') ct.tm_mon = 7-1;
-    else if(__DATE__[0]=='A' && __DATE__[1]=='u' && __DATE__[2]=='g') ct.tm_mon = 8-1;
-    else if(__DATE__[0]=='S' && __DATE__[1]=='e' && __DATE__[2]=='p') ct.tm_mon = 9-1;
-    else if(__DATE__[0]=='O' && __DATE__[1]=='c' && __DATE__[2]=='t') ct.tm_mon = 10-1;
-    else if(__DATE__[0]=='N' && __DATE__[1]=='o' && __DATE__[2]=='v') ct.tm_mon = 11-1;
-    else if(__DATE__[0]=='D' && __DATE__[1]=='e' && __DATE__[2]=='c') ct.tm_mon = 12-1;
-
-    // special case to handle __DATE__ not inserting leading zero on day of month
-    // if Day of month is less than 10 - it inserts a blank character
-    // this results in a negative number for tm_mday
-
-    if(__DATE__[4] == ' ')
-        ct.tm_mday = __DATE__[5]-'0';
-    else
-        ct.tm_mday = (__DATE__[4]-'0')*10 + (__DATE__[5]-'0');
-    ct.tm_hour = ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0');
-    ct.tm_min = ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0');
-    ct.tm_sec = ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0');
-    ct.tm_isdst = -1; // information is not available.
-
-    //FIXME: next 3 lines are copy-pasted from ua_types.c
-#define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
-#define HUNDRED_NANOSEC_PER_USEC 10LL
-#define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
-    server->buildDate = (mktime(&ct) + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC;
     
     /**************/
     /* References */
     /**************/
-#ifndef ENABLE_GENERATE_NAMESPACE0
+#ifndef UA_ENABLE_GENERATE_NAMESPACE0
     /* Bootstrap by manually inserting "references" and "hassubtype" */
     UA_ReferenceTypeNode *references = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)references, "References");
@@ -916,7 +830,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
                                 UA_NS0ID_BASEVARIABLETYPE, UA_FALSE);
 #endif
 
-#ifdef ENABLE_GENERATE_NAMESPACE0
+#ifdef UA_ENABLE_GENERATE_NAMESPACE0
     //load the generated namespace
     ua_namespaceinit_generated(server);
 #endif
@@ -948,11 +862,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_VariableNode *serverArray = UA_VariableNode_new();
     copyNames((UA_Node*)serverArray, "ServerArray");
     serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
-    serverArray->value.variant.value.data = UA_Array_new(1, &UA_TYPES[UA_TYPES_STRING]);
-    serverArray->value.variant.value.arrayLength = 1;
-    serverArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-    *(UA_String *)serverArray->value.variant.value.data =
-        UA_STRING_ALLOC(server->config.Application_applicationURI);
+    UA_Variant_setArrayCopy(&serverArray->value.variant.value,
+                            &server->config.applicationDescription.applicationUri, 1,
+                            &UA_TYPES[UA_TYPES_STRING]);
     serverArray->valueRank = 1;
     serverArray->minimumSamplingInterval = 1.0;
     addNodeInternal(server, (UA_Node*)serverArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
@@ -1000,13 +912,13 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_UInt16 profileArraySize = 0;
     ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NanoEmbeddedDevice");
 
-#ifdef ENABLE_SERVICESET_NODEMANAGEMENT
+#ifdef UA_ENABLE_SERVICESET_NODEMANAGEMENT
     ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement");
 #endif
-#ifdef ENABLE_SERVICESET_METHOD
+#ifdef UA_ENABLE_SERVICESET_METHOD
     ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods");
 #endif
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/EmbeddedDataChangeSubscription");
 #endif
 
@@ -1092,9 +1004,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     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.value.data = UA_BuildInfo_new();
-    buildinfo->value.variant.value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
-    getBuildInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
+    UA_Variant_setScalarCopy(&buildinfo->value.variant.value,
+                             &server->config.buildInfo,
+                             &UA_TYPES[UA_TYPES_BUILDINFO]);
     addNodeInternal(server, (UA_Node*)buildinfo,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
@@ -1114,9 +1026,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     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.value.data = UA_String_new();
-    *((UA_String*)manufacturername->value.variant.value.data) = UA_STRING_ALLOC(MANUFACTURER_NAME);
-    manufacturername->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    UA_Variant_setScalarCopy(&manufacturername->value.variant.value,
+                             &server->config.buildInfo.manufacturerName,
+                             &UA_TYPES[UA_TYPES_STRING]);
     addNodeInternal(server, (UA_Node*)manufacturername,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
@@ -1125,9 +1037,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     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.value.data = UA_String_new();
-    *((UA_String*)productname->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_NAME);
-    productname->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    UA_Variant_setScalarCopy(&productname->value.variant.value, &server->config.buildInfo.productName,
+                             &UA_TYPES[UA_TYPES_STRING]);
     addNodeInternal(server, (UA_Node*)productname,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
@@ -1136,9 +1047,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     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.value.data = UA_String_new();
-    *((UA_String*)softwareversion->value.variant.value.data) = UA_STRING_ALLOC(SOFTWARE_VERSION);
-    softwareversion->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    UA_Variant_setScalarCopy(&softwareversion->value.variant.value, &server->config.buildInfo.softwareVersion,
+                             &UA_TYPES[UA_TYPES_STRING]);
     addNodeInternal(server, (UA_Node*)softwareversion,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
@@ -1147,9 +1057,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     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.value.data = UA_String_new();
-    *((UA_String*)buildnumber->value.variant.value.data) = UA_STRING_ALLOC(BUILD_NUMBER);
-    buildnumber->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    UA_Variant_setScalarCopy(&buildnumber->value.variant.value, &server->config.buildInfo.buildNumber,
+                             &UA_TYPES[UA_TYPES_STRING]);
     addNodeInternal(server, (UA_Node*)buildnumber,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
@@ -1158,9 +1067,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     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.value.storageType = UA_VARIANT_DATA_NODELETE;
-    builddate->value.variant.value.data = &server->buildDate;
-    builddate->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
+    UA_Variant_setScalarCopy(&builddate->value.variant.value, &server->config.buildInfo.buildDate,
+                             &UA_TYPES[UA_TYPES_DATETIME]);
     addNodeInternal(server, (UA_Node*)builddate,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
@@ -1190,25 +1098,28 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 }
 
 UA_StatusCode
-__UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId,
-                             const UA_AttributeId attributeId, const UA_DataType *type,
-                             const void *value) {
+__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
+                  const UA_AttributeId attributeId, const UA_DataType *type,
+                  const void *value) {
     UA_WriteValue wvalue;
     UA_WriteValue_init(&wvalue);
-    wvalue.nodeId = nodeId;
+    wvalue.nodeId = *nodeId;
     wvalue.attributeId = attributeId;
     if(attributeId != UA_ATTRIBUTEID_VALUE)
         /* hacked cast. the target WriteValue is used as const anyway */
         UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value, type);
-    else
+    else {
+        if(type != &UA_TYPES[UA_TYPES_VARIANT])
+            return UA_STATUSCODE_BADTYPEMISMATCH;
         wvalue.value.value = *(const UA_Variant*)value;
+    }
     wvalue.value.hasValue = UA_TRUE;
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
     return retval;
 }
 
-static UA_StatusCode setValueCallback(UA_Server *server, UA_Session *session, UA_VariableNode *node,
-                                      UA_ValueCallback *callback) {
+static UA_StatusCode
+setValueCallback(UA_Server *server, UA_Session *session, UA_VariableNode *node, UA_ValueCallback *callback) {
     if(node->nodeClass != UA_NODECLASS_VARIABLE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
     node->value.variant.callback = *callback;
@@ -1251,18 +1162,17 @@ setObjectTypeLifecycleManagement(UA_Server *server, UA_Session *session, UA_Obje
 }
 
 UA_StatusCode UA_EXPORT
-UA_Server_setObjectTypeNode_instanceLifecycleManagement(UA_Server *server, UA_NodeId nodeId,
-                                                        UA_ObjectLifecycleManagement olm) {
+UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server, UA_NodeId nodeId,
+                                                UA_ObjectLifecycleManagement olm) {
     return UA_Server_editNode(server, &adminSession, &nodeId,
                               (UA_EditNodeCallback)setObjectTypeLifecycleManagement, &olm);
 }
 
 UA_StatusCode
-__UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
-                          const UA_AttributeId attributeId, void *v) {
+__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId, const UA_AttributeId attributeId, void *v) {
     UA_ReadValueId item;
     UA_ReadValueId_init(&item);
-    item.nodeId = nodeId;
+    item.nodeId = *nodeId;
     item.attributeId = attributeId;
     UA_DataValue dv;
     UA_DataValue_init(&dv);
@@ -1277,7 +1187,8 @@ __UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
         UA_DataValue_deleteMembers(&dv);
         return retval;
     }
-    if(attributeId == UA_ATTRIBUTEID_VALUE)
+    if(attributeId == UA_ATTRIBUTEID_VALUE ||
+       attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS)
         memcpy(v, &dv.value, sizeof(UA_Variant));
     else {
         memcpy(v, dv.value.data, dv.value.type->memSize);
@@ -1287,3 +1198,30 @@ __UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
     }
     return UA_STATUSCODE_GOOD;
 }
+
+UA_BrowseResult
+UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs, const UA_BrowseDescription *descr) {
+    UA_BrowseResult result;
+    UA_BrowseResult_init(&result);
+    Service_Browse_single(server, &adminSession, NULL, descr, maxrefs, &result);
+    return result;
+}
+
+UA_BrowseResult
+UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
+                     const UA_ByteString *continuationPoint) {
+    UA_BrowseResult result;
+    UA_BrowseResult_init(&result);
+    UA_Server_browseNext_single(server, &adminSession, releaseContinuationPoint,
+                                continuationPoint, &result);
+    return result;
+}
+
+#ifdef UA_ENABLE_METHODCALLS
+UA_CallMethodResult UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) {
+    UA_CallMethodResult result;
+    UA_CallMethodResult_init(&result);
+    Service_Call_single(server, &adminSession, request, &result);
+    return result;
+}
+#endif

+ 30 - 19
src/server/ua_server_binary.c

@@ -97,7 +97,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     }
 
     /* send the response with an asymmetric security header */
-#ifndef UA_MULTITHREADING
+#ifndef UA_ENABLE_MULTITHREADING
     seqHeader.sequenceNumber = ++channel->sequenceNumber;
 #else
     seqHeader.sequenceNumber = uatomic_add_return(&channel->sequenceNumber, 1);
@@ -142,7 +142,6 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
 
 static void init_response_header(const UA_RequestHeader *p, UA_ResponseHeader *r) {
     r->requestHandle = p->requestHandle;
-    r->stringTableSize = 0;
     r->timestamp = UA_DateTime_now();
 }
 
@@ -211,14 +210,13 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
         *responseType = &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE];
         break;
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     case UA_NS0ID_CREATESUBSCRIPTIONREQUEST:
         *service = (UA_Service)Service_CreateSubscription;
         *requestType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE];
         break;
     case UA_NS0ID_PUBLISHREQUEST:
-        *service = (UA_Service)Service_Publish;
         *requestType = &UA_TYPES[UA_TYPES_PUBLISHREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_PUBLISHRESPONSE];
         break;
@@ -249,7 +247,7 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
         break;
 #endif
 
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     case UA_NS0ID_CALLREQUEST:
         *service = (UA_Service)Service_Call;
         *requestType = &UA_TYPES[UA_TYPES_CALLREQUEST];
@@ -257,7 +255,7 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
 	break;
 #endif
 
-#ifdef ENABLE_NODEMANAGEMENT
+#ifdef UA_ENABLE_NODEMANAGEMENT
     case UA_NS0ID_ADDNODESREQUEST:
         *service = (UA_Service)Service_AddNodes;
         *requestType = &UA_TYPES[UA_TYPES_ADDNODESREQUEST];
@@ -329,7 +327,7 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     if(tokenId != channel->securityToken.tokenId) {
         if(tokenId != channel->nextSecurityToken.tokenId) {
             /* close the securechannel but keep the connection open */
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Request with a wrong security token. Closing the SecureChannel %i.",
                         channel->securityToken.channelId);
             Service_CloseSecureChannel(server, channel->securityToken.channelId);
@@ -351,21 +349,22 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     const UA_DataType *requestType = NULL;
     const UA_DataType *responseType = NULL;
     getServicePointers(requestTypeId.identifier.numeric, &requestType, &responseType, &service);
-    if(!service) {
+    if(!requestType) {
         /* The service is not supported */
         if(requestTypeId.identifier.numeric==787)
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
                         "Client requested a subscription that are not supported, "
                         "the message will be skipped");
         else
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Unknown request: NodeId(ns=%d, i=%d)",
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                        "Unknown request: NodeId(ns=%d, i=%d)",
                         requestTypeId.namespaceIndex, requestTypeId.identifier.numeric);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
         return;
     }
 
     /* Most services can only be called with a valid securechannel */
-#ifndef EXTENSION_STATELESS
+#ifndef UA_ENABLE_NONSTANDARD_STATELESS
     if(channel == &anonymousChannel &&
        requestType->typeIndex > UA_TYPES_OPENSECURECHANNELREQUEST) {
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSECURECHANNELIDINVALID);
@@ -395,21 +394,33 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
 
     /* Test if the session is valid */
     if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) {
-        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service with a non-activated session");
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                    "Client tries to call a service with a non-activated session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         return;
     }
-#ifndef EXTENSION_STATELESS
+#ifndef UA_ENABLE_NONSTANDARD_STATELESS
     if(session == &anonymousSession &&
        requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) {
-        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service without a session");
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                    "Client tries to call a service without a session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
         return;
     }
 #endif
 
-    /* Call the service */
     UA_Session_updateLifetime(session);
+
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+    /* The publish request is answered with a delay */
+    if(requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY == UA_NS0ID_PUBLISHREQUEST) {
+        Service_Publish(server, session, request, sequenceHeader.requestId);
+        UA_deleteMembers(request, requestType);
+        return;
+    }
+#endif
+        
+    /* Call the service */
     void *response = UA_alloca(responseType->memSize);
     UA_init(response, responseType);
     init_response_header(request, response);
@@ -449,7 +460,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
     UA_TcpMessageHeader tcpMessageHeader;
     do {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader)) {
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK, "Decoding of message header failed");
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK, "Decoding of message header failed");
             connection->close(connection);
             break;
         }
@@ -463,7 +474,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             processOPN(connection, server, msg, &pos);
             break;
         case UA_MESSAGETYPEANDFINAL_MSGF & 0xffffff:
-#ifndef EXTENSION_STATELESS
+#ifndef UA_ENABLE_NONSTANDARD_STATELESS
             if(connection->state != UA_CONNECTION_ESTABLISHED) {
                 connection->close(connection);
                 return;
@@ -476,13 +487,13 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             connection->close(connection);
             return;
         default:
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
                         "Unknown request type on Connection %i", connection->sockfd);
         }
 
         UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
         if(pos != targetpos) {
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
                         "Message on Connection %i was not entirely processed. "
                         "Arrived at position %i, skip after the announced length to position %i",
                         connection->sockfd, pos, targetpos);

+ 21 - 26
src/server/ua_server_internal.h

@@ -8,15 +8,14 @@
 #include "ua_securechannel_manager.h"
 #include "ua_nodestore.h"
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 #include "ua_subscription_manager.h"
 #endif
 
-#define PRODUCT_URI "http://open62541.org"
 #define ANONYMOUS_POLICY "open62541-anonymous-policy"
 #define USERNAME_POLICY "open62541-username-policy"
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 /** Mapping of namespace-id and url to an external nodestore. For namespaces
     that have no mapping defined, the internal nodestore is used by default. */
 typedef struct UA_ExternalNamespace {
@@ -26,25 +25,24 @@ typedef struct UA_ExternalNamespace {
 } UA_ExternalNamespace;
 #endif
 
-struct UA_Server {
-    /* Config */
-    UA_ServerConfig config;
-    UA_Logger logger;
-    UA_UInt32 random_seed;
+#ifdef UA_ENABLE_MULTITHREADING
+typedef struct {
+    UA_Server *server;
+    pthread_t thr;
+    UA_UInt32 counter;
+    volatile UA_Boolean running;
+    char padding[64 - sizeof(void*) - sizeof(pthread_t) -
+                 sizeof(UA_UInt32) - sizeof(UA_Boolean)]; // separate cache lines
+} UA_Worker;
+#endif
 
+struct UA_Server {
     /* Meta */
     UA_DateTime startTime;
-    UA_DateTime buildDate;
-    UA_ApplicationDescription description;
     size_t endpointDescriptionsSize;
     UA_EndpointDescription *endpointDescriptions;
 
-    /* Communication */
-    size_t networkLayersSize;
-    UA_ServerNetworkLayer **networkLayers;
-
     /* Security */
-    UA_ByteString serverCertificate;
     UA_SecureChannelManager secureChannelManager;
     UA_SessionManager sessionManager;
 
@@ -53,7 +51,7 @@ struct UA_Server {
     size_t namespacesSize;
     UA_String *namespaces;
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
     size_t externalNamespacesSize;
     UA_ExternalNamespace *externalNamespaces;
 #endif
@@ -61,23 +59,20 @@ struct UA_Server {
     /* Jobs with a repetition interval */
     LIST_HEAD(RepeatedJobsList, RepeatedJobs) repeatedJobs;
     
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     /* Dispatch queue head for the worker threads (the tail should not be in the same cache line) */
 	struct cds_wfcq_head dispatchQueue_head;
-
-    UA_Boolean *running;
-    UA_UInt16 nThreads;
-    UA_UInt32 **workerCounters;
-    pthread_t *thr;
-
+    UA_Worker *workers; /* there are nThread workers in a running server */
     struct cds_lfs_stack mainLoopJobs; /* Work that shall be executed only in the main loop and not
                                           by worker threads */
     struct DelayedJobs *delayedJobs;
-
     pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */
-    /* Dispatch queue tail for the worker threads */
-	struct cds_wfcq_tail dispatchQueue_tail;
+	struct cds_wfcq_tail dispatchQueue_tail; /* Dispatch queue tail for the worker threads */
 #endif
+
+    /* Config is the last element so that MSVC allows the usernamePasswordLogins
+       field with zero-sized array */
+    UA_ServerConfig config;
 };
 
 /* The node is assumed to be "finished", i.e. no instantiation from inheritance is necessary */

+ 103 - 120
src/server/ua_server_worker.c

@@ -1,11 +1,6 @@
 #include "ua_util.h"
 #include "ua_server_internal.h"
 
-#if defined(__APPLE__) || defined(__MACH__)
-#include <mach/clock.h>
-#include <mach/mach.h>
-#endif
-
 /**
  * There are four types of job execution:
  *
@@ -72,7 +67,8 @@ static void processJobs(UA_Server *server, UA_Job *jobs, UA_Int32 jobsSize) {
             job->job.methodCall.method(server, job->job.methodCall.data);
             break;
         default:
-            UA_LOG_WARNING(server->logger, UA_LOGCATEGORY_SERVER, "Trying to execute a job of unknown type");
+            UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
+                           "Trying to execute a job of unknown type");
             break;
         }
     }
@@ -82,7 +78,7 @@ static void processJobs(UA_Server *server, UA_Job *jobs, UA_Int32 jobsSize) {
 /* Worker Threads and Dispatch */
 /*******************************/
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 
 struct MainLoopJob {
     struct cds_lfs_node node;
@@ -98,7 +94,8 @@ struct DispatchJobsList {
 
 /** Dispatch jobs to workers. Slices the job array up if it contains more than BATCHSIZE items. The jobs
     array is freed in the worker threads. */
-static void dispatchJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
+static void
+dispatchJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
     size_t startIndex = jobsSize; // start at the end
     while(jobsSize > 0) {
         size_t size = BATCHSIZE;
@@ -121,67 +118,46 @@ static void dispatchJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
     }
 }
 
-// throwaway struct to bring data into the worker threads
-struct workerStartData {
-    UA_Server *server;
-    UA_UInt32 **workerCounter;
-};
-
-/** Waits until jobs arrive in the dispatch queue and processes them. */
-static void * workerLoop(struct workerStartData *startInfo) {
-    /* Initialized the (thread local) random seed */
-    UA_random_seed((uintptr_t)startInfo);
-
+static void *
+workerLoop(UA_Worker *worker) {
+    UA_Server *server = worker->server;
+    UA_UInt32 *counter = &worker->counter;
+    volatile UA_Boolean *running = &worker->running;
+    
+    /* Initialize the (thread local) random seed with the ram address of worker */
+    UA_random_seed((uintptr_t)worker);
    	rcu_register_thread();
-    UA_UInt32 *c = UA_malloc(sizeof(UA_UInt32));
-    uatomic_set(c, 0);
-    *startInfo->workerCounter = c;
-    UA_Server *server = startInfo->server;
-    UA_free(startInfo);
 
     pthread_mutex_t mutex; // required for the condition variable
     pthread_mutex_init(&mutex,0);
     pthread_mutex_lock(&mutex);
-    struct timespec to;
 
-    while(*server->running) {
+    while(*running) {
         struct DispatchJobsList *wln = (struct DispatchJobsList*)
             cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
-        if(wln) {
-            UA_RCU_LOCK();
-            processJobs(server, wln->jobs, wln->jobsSize);
-            UA_free(wln->jobs);
-            UA_free(wln);
-            UA_RCU_UNLOCK();
-        } else {
+        if(!wln) {
+            uatomic_inc(counter);
             /* sleep until a work arrives (and wakes up all worker threads) */
-            #if defined(__APPLE__) || defined(__MACH__) // OS X does not have clock_gettime, use clock_get_time
-              clock_serv_t cclock;
-              mach_timespec_t mts;
-              host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
-              clock_get_time(cclock, &mts);
-              mach_port_deallocate(mach_task_self(), cclock);
-              to.tv_sec = mts.tv_sec;
-              to.tv_nsec = mts.tv_nsec;
-            #else
-              clock_gettime(CLOCK_REALTIME, &to);
-            #endif
-            to.tv_sec += 2;
-            pthread_cond_timedwait(&server->dispatchQueue_condition, &mutex, &to);
+            pthread_cond_wait(&server->dispatchQueue_condition, &mutex);
+            continue;
         }
-        uatomic_inc(c); // increase the workerCounter;
+        UA_RCU_LOCK();
+        processJobs(server, wln->jobs, wln->jobsSize);
+        UA_free(wln->jobs);
+        UA_free(wln);
+        UA_RCU_UNLOCK();
+        uatomic_inc(counter);
     }
+
     pthread_mutex_unlock(&mutex);
     pthread_mutex_destroy(&mutex);
-
-    rcu_barrier(); // wait for all scheduled call_rcu work to complete
+    rcu_barrier();
    	rcu_unregister_thread();
-
-    /* we need to return _something_ for pthreads */
     return NULL;
 }
 
-static void emptyDispatchQueue(UA_Server *server) {
+static void
+emptyDispatchQueue(UA_Server *server) {
     while(!cds_wfcq_empty(&server->dispatchQueue_head, &server->dispatchQueue_tail)) {
         struct DispatchJobsList *wln = (struct DispatchJobsList*)
             cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
@@ -229,7 +205,7 @@ static UA_StatusCode addRepeatedJob(UA_Server *server, struct AddRepeatedJob * U
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
 
     /* search for matching entry */
-    UA_DateTime firstTime = UA_DateTime_now() + arw->interval;
+    UA_DateTime firstTime = UA_DateTime_nowMonotonic() + arw->interval;
     tempTw = LIST_FIRST(&server->repeatedJobs);
     while(tempTw) {
         if(arw->interval == tempTw->interval) {
@@ -271,7 +247,7 @@ static UA_StatusCode addRepeatedJob(UA_Server *server, struct AddRepeatedJob * U
     matchingTw->jobsSize++;
 
  cleanup:
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     UA_free(arw);
 #endif
     return retval;
@@ -283,7 +259,7 @@ UA_StatusCode UA_Server_addRepeatedJob(UA_Server *server, UA_Job job, UA_UInt32
         return UA_STATUSCODE_BADINTERNALERROR;
     interval *= 10000; // from ms to 100ns resolution
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     struct AddRepeatedJob *arw = UA_malloc(sizeof(struct AddRepeatedJob));
     if(!arw)
         return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -291,7 +267,7 @@ UA_StatusCode UA_Server_addRepeatedJob(UA_Server *server, UA_Job job, UA_UInt32
     arw->interval = interval;
     arw->job.job = job;
     if(jobId) {
-        arw->job.id = UA_Guid_random(&server->random_seed);
+        arw->job.id = UA_Guid_random();
         *jobId = arw->job.id;
     } else
         UA_Guid_init(&arw->job.id);
@@ -310,7 +286,7 @@ UA_StatusCode UA_Server_addRepeatedJob(UA_Server *server, UA_Job job, UA_UInt32
     arw.interval = interval;
     arw.job.job = job;
     if(jobId) {
-        arw.job.id = UA_Guid_random(&server->random_seed);
+        arw.job.id = UA_Guid_random();
         *jobId = arw.job.id;
     } else
         UA_Guid_init(&arw.job.id);
@@ -321,18 +297,19 @@ UA_StatusCode UA_Server_addRepeatedJob(UA_Server *server, UA_Job job, UA_UInt32
 
 /* Returns the timeout until the next repeated job in ms */
 static UA_UInt16 processRepeatedJobs(UA_Server *server) {
-    UA_DateTime current = UA_DateTime_now();
+    UA_DateTime current = UA_DateTime_nowMonotonic();
     struct RepeatedJobs *tw = NULL;
 
     while((tw = LIST_FIRST(&server->repeatedJobs)) != NULL) {
         if(tw->nextTime > current)
             break;
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
         // copy the entry and insert at the new location
         UA_Job *jobsCopy = UA_malloc(sizeof(UA_Job) * tw->jobsSize);
         if(!jobsCopy) {
-            UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Not enough memory to dispatch delayed jobs");
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Not enough memory to dispatch delayed jobs");
             break;
         }
         for(size_t i=0;i<tw->jobsSize;i++)
@@ -393,14 +370,14 @@ static void removeRepeatedJob(UA_Server *server, UA_Guid *jobId) {
         }
     }
  finish:
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     UA_free(jobId);
 #endif
     return;
 }
 
 UA_StatusCode UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     UA_Guid *idptr = UA_malloc(sizeof(UA_Guid));
     if(!idptr)
         return UA_STATUSCODE_BADOUTOFMEMORY;
@@ -429,7 +406,7 @@ void UA_Server_deleteAllRepeatedJobs(UA_Server *server) {
 /* Delayed Jobs */
 /****************/
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 
 #define DELAYEDJOBSSIZE 100 // Collect delayed jobs until we have DELAYEDWORKSIZE items
 
@@ -442,9 +419,9 @@ struct DelayedJobs {
 
 /* Dispatched as an ordinary job when the DelayedJobs list is full */
 static void getCounters(UA_Server *server, struct DelayedJobs *delayed) {
-    UA_UInt32 *counters = UA_malloc(server->nThreads * sizeof(UA_UInt32));
-    for(UA_UInt16 i = 0;i<server->nThreads;i++)
-        counters[i] = *server->workerCounters[i];
+    UA_UInt32 *counters = UA_malloc(server->config.nThreads * sizeof(UA_UInt32));
+    for(UA_UInt16 i = 0; i < server->config.nThreads; i++)
+        counters[i] = server->workers[i].counter;
     delayed->workerCounters = counters;
 }
 
@@ -457,7 +434,8 @@ static void addDelayedJob(UA_Server *server, UA_Job *job) {
         /* create a new DelayedJobs and add it to the linked list */
         dj = UA_malloc(sizeof(struct DelayedJobs));
         if(!dj) {
-            UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Not enough memory to add a delayed job");
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Not enough memory to add a delayed job");
             return;
         }
         dj->jobsCount = 0;
@@ -509,8 +487,8 @@ static void dispatchDelayedJobs(UA_Server *server, void *data /* not used, but n
             continue;
         }
         UA_Boolean allMoved = UA_TRUE;
-        for(UA_UInt16 i=0;i<server->nThreads;i++) {
-            if(dw->workerCounters[i] == *server->workerCounters[i]) {
+        for(size_t i = 0; i < server->config.nThreads; i++) {
+            if(dw->workerCounters[i] == server->workers[i].counter) {
                 allMoved = UA_FALSE;
                 break;
             }
@@ -537,7 +515,7 @@ static void dispatchDelayedJobs(UA_Server *server, void *data /* not used, but n
 /* Main Server Loop */
 /********************/
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 static void processMainLoopJobs(UA_Server *server) {
     /* no synchronization required if we only use push and pop_all */
     struct cds_lfs_head *head = __cds_lfs_pop_all(&server->mainLoopJobs);
@@ -554,38 +532,41 @@ static void processMainLoopJobs(UA_Server *server) {
 }
 #endif
 
-UA_StatusCode UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
-UA_StatusCode result = UA_STATUSCODE_GOOD;
-
-#ifdef UA_MULTITHREADING
-    /* Prepare the worker threads */
-    server->running = running; // the threads need to access the variable
-    server->nThreads = nThreads;
+UA_StatusCode UA_Server_run_startup(UA_Server *server) {
+#ifdef UA_ENABLE_MULTITHREADING
+    /* Spin up the worker threads */
+    UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                "Spinning up %u worker thread(s)", server->config.nThreads);
     pthread_cond_init(&server->dispatchQueue_condition, 0);
-    server->thr = UA_malloc(nThreads * sizeof(pthread_t));
-    server->workerCounters = UA_malloc(nThreads * sizeof(UA_UInt32 *));
-    for(UA_UInt32 i=0;i<nThreads;i++) {
-        struct workerStartData *startData = UA_malloc(sizeof(struct workerStartData));
-        startData->server = server;
-        startData->workerCounter = &server->workerCounters[i];
-        pthread_create(&server->thr[i], NULL, (void* (*)(void*))workerLoop, startData);
+    server->workers = UA_malloc(server->config.nThreads * sizeof(UA_Worker));
+    if(!server->workers)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    for(size_t i = 0; i < server->config.nThreads; i++) {
+        UA_Worker *worker = &server->workers[i];
+        worker->server = server;
+        worker->counter = 0;
+        worker->running = true;
+        pthread_create(&worker->thr, NULL, (void* (*)(void*))workerLoop, worker);
     }
 
-    /* try to execute the delayed callbacks every 10 sec */
+    /* Try to execute delayed callbacks every 10 sec */
     UA_Job processDelayed = {.type = UA_JOBTYPE_METHODCALL,
                              .job.methodCall = {.method = dispatchDelayedJobs, .data = NULL} };
     UA_Server_addRepeatedJob(server, processDelayed, 10000, NULL);
 #endif
 
     /* Start the networklayers */
-    for(size_t i = 0; i < server->networkLayersSize; i++)
-        result |= server->networkLayers[i]->start(server->networkLayers[i], server->logger);
+    UA_StatusCode result = UA_STATUSCODE_GOOD;
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
+        result |= nl->start(nl);
+    }
 
     return result;
 }
 
-UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
-#ifdef UA_MULTITHREADING
+UA_StatusCode UA_Server_run_iterate(UA_Server *server) {
+#ifdef UA_ENABLE_MULTITHREADING
     /* Run Work in the main loop */
     processMainLoopJobs(server);
 #endif
@@ -593,21 +574,19 @@ UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
     UA_UInt16 timeout = processRepeatedJobs(server);
 
     /* Get work from the networklayer */
-    for(size_t i = 0; i < server->networkLayersSize; i++) {
-        UA_ServerNetworkLayer *nl = server->networkLayers[i];
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
         UA_Job *jobs;
-        UA_Int32 jobsSize;
-        if(*running) {
-            if(i == server->networkLayersSize-1)
-                jobsSize = nl->getJobs(nl, &jobs, timeout);
-            else
-                jobsSize = nl->getJobs(nl, &jobs, 0);
-        } else
-            jobsSize = server->networkLayers[i]->stop(nl, &jobs);
-
-#ifdef UA_MULTITHREADING
+        size_t jobsSize;
+        if(i == server->config.networkLayersSize-1)
+            /* only the last networklayer waits on the tieout */
+            jobsSize = nl->getJobs(nl, &jobs, timeout);
+        else
+            jobsSize = nl->getJobs(nl, &jobs, 0);
+
+#ifdef UA_ENABLE_MULTITHREADING
         /* Filter out delayed work */
-        for(UA_Int32 k=0;k<jobsSize;k++) {
+        for(size_t k = 0; k < jobsSize; k++) {
             if(jobs[k].type != UA_JOBTYPE_METHODCALL_DELAYED)
                 continue;
             addDelayedJob(server, &jobs[k]);
@@ -629,21 +608,26 @@ UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads){
+UA_StatusCode UA_Server_run_shutdown(UA_Server *server) {
     UA_Job *stopJobs;
-    for(size_t i = 0; i < server->networkLayersSize; i++) {
-        size_t stopJobsSize = server->networkLayers[i]->stop(server->networkLayers[i], &stopJobs);
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
+        size_t stopJobsSize = nl->stop(nl, &stopJobs);
         processJobs(server, stopJobs, stopJobsSize);
         UA_free(stopJobs);
     }
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
+    UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                "Shutting down %u worker thread(s)", server->config.nThreads);
     /* Wait for all worker threads to finish */
-    for(UA_UInt32 i=0;i<nThreads;i++) {
-        pthread_join(server->thr[i], NULL);
-        UA_free(server->workerCounters[i]);
-    }
-    UA_free(server->workerCounters);
-    UA_free(server->thr);
+    for(size_t i = 0; i < server->config.nThreads; i++)
+        server->workers[i].running = false;
+    pthread_cond_broadcast(&server->dispatchQueue_condition);
+    for(size_t i = 0; i < server->config.nThreads; i++)
+        pthread_join(server->workers[i].thr, NULL);
+    UA_free(server->workers);
+    UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                "Workers shut down");
 
     /* Manually finish the work still enqueued */
     emptyDispatchQueue(server);
@@ -661,12 +645,11 @@ UA_StatusCode UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads){
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
-    if(UA_STATUSCODE_GOOD == UA_Server_run_startup(server, nThreads, running)){
-        while(*running) {
-            UA_Server_run_mainloop(server, running);
-        }
-    }
-    UA_Server_run_shutdown(server, nThreads);
-    return UA_STATUSCODE_GOOD;
+UA_StatusCode UA_Server_run(UA_Server *server, volatile UA_Boolean *running) {
+    UA_StatusCode retval = UA_Server_run_startup(server);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    while(*running)
+            UA_Server_run_iterate(server);
+    return UA_Server_run_shutdown(server);
 }

+ 11 - 6
src/server/ua_services.h

@@ -116,7 +116,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session,
                       const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response);
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result);
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback);
 
 /** Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session,
@@ -173,6 +173,8 @@ void Service_Browse_single(UA_Server *server, UA_Session *session,
 void Service_BrowseNext(UA_Server *server, UA_Session *session,
                         const UA_BrowseNextRequest *request,
                         UA_BrowseNextResponse *response);
+void UA_Server_browseNext_single(UA_Server *server, UA_Session *session, UA_Boolean releaseContinuationPoint,
+                                 const UA_ByteString *continuationPoint, UA_BrowseResult *result);
 
 /** Used to translate textual node paths to their respective ids. */
 void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
@@ -216,7 +218,7 @@ void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
  */
 
 /* Mock-Up of the function signature for Unit Tests */
-#ifdef BUILD_UNIT_TESTS
+#ifdef UA_BUILD_UNIT_TESTS
 UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range);
 #endif
 
@@ -262,15 +264,19 @@ Service_Write_single(UA_Server *server, UA_Session *session, const UA_WriteValue
  *
  * @{
  */
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
 void
 Service_Call(UA_Server *server, UA_Session *session,
              const UA_CallRequest *request,
              UA_CallResponse *response);
+void
+Service_Call_single(UA_Server *server, UA_Session *session,
+                    const UA_CallMethodRequest *request,
+                    UA_CallMethodResult *result);
 #endif
 /** @} */
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 /**
  * @name MonitoredItem Service Set
  *
@@ -327,8 +333,7 @@ Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
                                      
 void
 Service_Publish(UA_Server *server, UA_Session *session,
-                const UA_PublishRequest *request,
-                UA_PublishResponse *response);
+                const UA_PublishRequest *request, UA_UInt32 requestId);
 
 void
 Service_Republish(UA_Server *server, UA_Session *session,

+ 34 - 29
src/server/ua_services_attribute.c

@@ -39,7 +39,7 @@ static size_t readDimension(UA_Byte *buf, UA_Int32 buflen, struct UA_NumericRang
     return progress + progress2 + 1;
 }
 
-#ifndef BUILD_UNIT_TESTS
+#ifndef UA_BUILD_UNIT_TESTS
 static
 #endif
 UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
@@ -136,10 +136,14 @@ static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_Ti
         if(retval == UA_STATUSCODE_GOOD)
             handleSourceTimestamps(timestamps, v);
     } else {
-        UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
-                                      timestamps == UA_TIMESTAMPSTORETURN_BOTH);
-        retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId,
-                                           sourceTimeStamp, rangeptr, v);
+        if(vn->value.dataSource.read == NULL) {
+            retval = UA_STATUSCODE_BADINTERNALERROR;
+        } else {
+            UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
+                                          timestamps == UA_TIMESTAMPSTORETURN_BOTH);
+            retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId,
+                                               sourceTimeStamp, rangeptr, v);
+        }
     }
 
     if(rangeptr)
@@ -153,6 +157,8 @@ static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataV
         forceVariantSetScalar(&v->value, &vn->value.variant.value.type->typeId,
                               &UA_TYPES[UA_TYPES_NODEID]);
     } else {
+        if(vn->value.dataSource.read == NULL)
+            return UA_STATUSCODE_BADINTERNALERROR;
         /* Read from the datasource to see the data type */
         UA_DataValue val;
         UA_DataValue_init(&val);
@@ -172,6 +178,8 @@ static UA_StatusCode getVariableNodeArrayDimensions(const UA_VariableNode *vn, U
                             vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
         v->value.storageType = UA_VARIANT_DATA_NODELETE;
     } else {
+        if(vn->value.dataSource.read == NULL)
+            return UA_STATUSCODE_BADINTERNALERROR;
         /* Read the datasource to see the array dimensions */
         UA_DataValue val;
         UA_DataValue_init(&val);
@@ -353,7 +361,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
         return;
     }
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
     UA_Boolean isExternal[size];
     UA_UInt32 indices[size];
     memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
@@ -375,14 +383,14 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 #endif
 
     for(size_t i = 0;i < size;i++) {
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
             Service_Read_single(server, session, request->timestampsToReturn,
                                 &request->nodesToRead[i], &response->results[i]);
     }
 
-#ifdef EXTENSION_STATELESS
+#ifdef UA_ENABLE_NONSTANDARD_STATELESS
     /* Add an expiry header for caching */
     if(session==&anonymousSession){
 		UA_ExtensionObject additionalHeader;
@@ -428,7 +436,7 @@ UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const U
         UA_MT_CONST UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
-#ifndef UA_MULTITHREADING
+#ifndef UA_ENABLE_MULTITHREADING
         retval = callback(server, session, node, data);
         return retval;
 #else
@@ -469,6 +477,9 @@ Service_Write_single_ValueDataSource(UA_Server *server, UA_Session *session, con
     UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
     UA_assert(node->valueSource == UA_VALUESOURCE_DATASOURCE);
 
+    if(node->value.dataSource.write == NULL)
+        return UA_STATUSCODE_BADWRITENOTSUPPORTED;
+
     UA_StatusCode retval;
     if(wvalue->indexRange.length <= 0) {
         retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId,
@@ -561,11 +572,16 @@ CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
 }
 
 static UA_StatusCode
-CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
+                      UA_Node *node, const UA_WriteValue *wvalue) {
+    if(!wvalue->value.hasValue)
+        return UA_STATUSCODE_BADNODATA;
+
     void *value = wvalue->value.value.data;
     void *target = NULL;
     const UA_DataType *type = NULL;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
 	switch(wvalue->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODECLASS:
@@ -624,7 +640,10 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, con
 		break;
 	case UA_ATTRIBUTEID_VALUE:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue);
+        if(((const UA_VariableNode*)node)->valueSource == UA_VALUESOURCE_VARIANT)
+            retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue);
+        else
+            retval = Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)node, wvalue);
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
@@ -668,21 +687,7 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, con
 }
 
 UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, const UA_WriteValue *wvalue) {
-    if(!wvalue->value.hasValue || !wvalue->value.value.data)
-        return UA_STATUSCODE_BADNODATA; // TODO: is this the right return code?
-    if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE) {
-        const UA_Node *orig = UA_NodeStore_get(server->nodestore, &wvalue->nodeId);
-        if(!orig)
-            return UA_STATUSCODE_BADNODEIDUNKNOWN;
-        if(orig->nodeClass & (UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLE) &&
-           ((const UA_VariableNode*)orig)->valueSource == UA_VALUESOURCE_DATASOURCE) {
-            UA_StatusCode retval =
-                Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)orig, wvalue);
-            return retval;
-        }
-    }
-    return UA_Server_editNode(server, session, &wvalue->nodeId,
-                              (UA_EditNodeCallback)CopyAttributeIntoNode, wvalue);
+    return UA_Server_editNode(server, session, &wvalue->nodeId, (UA_EditNodeCallback)CopyAttributeIntoNode, wvalue);
 }
 
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
@@ -703,7 +708,7 @@ void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest
         return;
     }
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
     UA_Boolean isExternal[request->nodesToWriteSize];
     UA_UInt32 indices[request->nodesToWriteSize];
     memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
@@ -727,7 +732,7 @@ void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest
     
     response->resultsSize = request->nodesToWriteSize;
     for(size_t i = 0;i < request->nodesToWriteSize;i++) {
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
 		  response->results[i] = Service_Write_single(server, session, &request->nodesToWrite[i]);

+ 4 - 4
src/server/ua_services_call.c

@@ -105,9 +105,9 @@ argConformsToDefinition(const UA_VariableNode *argRequirements, size_t argsSize,
     return retval;
 }
 
-static void
-callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request,
-           UA_CallMethodResult *result) {
+void
+Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *request,
+                    UA_CallMethodResult *result) {
     const UA_MethodNode *methodCalled =
         (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
     if(!methodCalled) {
@@ -206,5 +206,5 @@ void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *
     response->resultsSize = request->methodsToCallSize;
     
     for(size_t i = 0; i < request->methodsToCallSize;i++)
-        callMethod(server, session, &request->methodsToCall[i], &response->results[i]);
+        Service_Call_single(server, session, &request->methodsToCall[i], &response->results[i]);
 }

+ 48 - 11
src/server/ua_services_discovery.c

@@ -4,31 +4,67 @@
 
 void Service_FindServers(UA_Server *server, UA_Session *session,
                          const UA_FindServersRequest *request, UA_FindServersResponse *response) {
-    response->servers = UA_malloc(sizeof(UA_ApplicationDescription));
-    if(!response->servers) {
+    /* copy ApplicationDescription from the config */
+    UA_ApplicationDescription *descr = UA_malloc(sizeof(UA_ApplicationDescription));
+    if(!descr) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
-    if(UA_ApplicationDescription_copy(&server->description, response->servers) != UA_STATUSCODE_GOOD) {
-        UA_free(response->servers);
+    response->responseHeader.serviceResult =
+        UA_ApplicationDescription_copy(&server->config.applicationDescription, descr);
+    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
+        UA_free(descr);
+        return;
+    }
+
+    /* add the discoveryUrls from the networklayers */
+    UA_String *disc = UA_realloc(descr->discoveryUrls, sizeof(UA_String) *
+                                 (descr->discoveryUrlsSize + server->config.networkLayersSize));
+    if(!disc) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+        UA_ApplicationDescription_delete(descr);
         return;
     }
-	response->serversSize = 1;
+    size_t index = descr->discoveryUrlsSize;
+    descr->discoveryUrls = disc;
+    descr->discoveryUrlsSize += server->config.networkLayersSize;
+        
+    // TODO: Add nl only if discoveryUrl not already present
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
+        UA_String_copy(&nl->discoveryUrl, &descr->discoveryUrls[index + i]);
+    }
+
+    response->servers = descr;
+    response->serversSize = 1;
 }
 
-void Service_GetEndpoints(UA_Server *server, UA_Session *session,
-                          const UA_GetEndpointsRequest *request, UA_GetEndpointsResponse *response) {
+void Service_GetEndpoints(UA_Server *server, UA_Session *session, const UA_GetEndpointsRequest *request,
+                          UA_GetEndpointsResponse *response) {
+    /* Test if one of the networklayers exposes the discoveryUrl of the requested endpoint */
+    /* Disabled, servers in a virtualbox don't know their external hostname */
+    /* UA_Boolean foundUri = UA_FALSE; */
+    /* for(size_t i = 0; i < server->config.networkLayersSize; i++) { */
+    /*     if(UA_String_equal(&request->endpointUrl, &server->config.networkLayers[i].discoveryUrl)) { */
+    /*         foundUri = UA_TRUE; */
+    /*         break; */
+    /*     } */
+    /* } */
+    /* if(!foundUri) { */
+    /*     response->endpointsSize = 0; */
+    /*     return; */
+    /* } */
+    
     /* test if the supported binary profile shall be returned */
 #ifdef NO_ALLOCA
 	UA_Boolean relevant_endpoints[server->endpointDescriptionsSize];
 #else
-	UA_Boolean *relevant_endpoints = UA_alloca(sizeof(UA_Boolean)*server->endpointDescriptionsSize);
-#endif /*NO_ALLOCA */
+	UA_Boolean *relevant_endpoints = UA_alloca(sizeof(UA_Byte) * server->endpointDescriptionsSize);
+#endif
     size_t relevant_count = 0;
     for(size_t j = 0; j < server->endpointDescriptionsSize; j++) {
         relevant_endpoints[j] = UA_FALSE;
-        if(request->profileUrisSize <= 0) {
+        if(request->profileUrisSize == 0) {
             relevant_endpoints[j] = UA_TRUE;
             relevant_count++;
             continue;
@@ -56,9 +92,10 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
     size_t k = 0;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(size_t j = 0; j < server->endpointDescriptionsSize && retval == UA_STATUSCODE_GOOD; j++) {
-        if(relevant_endpoints[j] != UA_TRUE)
+        if(!relevant_endpoints[j])
             continue;
         retval = UA_EndpointDescription_copy(&server->endpointDescriptions[j], &response->endpoints[k]);
+        retval |= UA_String_copy(&request->endpointUrl, &response->endpoints[k].endpointUrl);
         k++;
     }
 

+ 81 - 55
src/server/ua_services_nodemanagement.c

@@ -80,16 +80,18 @@ UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session,
-                        const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                        const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                        UA_InstantiationCallback *instantiationCallback);
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                      UA_InstantiationCallback *instantiationCallback);
 
 /* copy an existing variable under the given parent. then instantiate the
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                     const UA_NodeId *referenceType, const UA_NodeId *parent) {
+                     const UA_NodeId *referenceType, const UA_NodeId *parent, UA_InstantiationCallback *instantiationCallback) {
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -127,7 +129,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     // add the new variable
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_VariableAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
 
@@ -139,9 +141,12 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
             continue;
-        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
-
+    
+    if (instantiationCallback != NULL)
+      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+    
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
 }
@@ -150,7 +155,8 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                   const UA_NodeId *referenceType, const UA_NodeId *parent) {
+                   const UA_NodeId *referenceType, const UA_NodeId *parent, 
+                   UA_InstantiationCallback *instantiationCallback) {
     const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -180,7 +186,7 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
     // add the new object
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_ObjectAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
 
@@ -192,9 +198,12 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
             continue;
-        instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+        instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
-
+    
+    if (instantiationCallback != NULL)
+      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+    
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
 }
@@ -209,13 +218,14 @@ setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* n
 
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                      UA_InstantiationCallback *instantiationCallback) {   
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(type->nodeClass != UA_NODECLASS_OBJECTTYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-
+    
     /* Add all the child nodes */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
@@ -244,9 +254,9 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
             item.targetNodeClass = UA_NODECLASS_METHOD;
             Service_AddReferences_single(server, session, &item);
         } else if(rd->nodeClass == UA_NODECLASS_VARIABLE)
-            copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+          copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
         else if(rd->nodeClass == UA_NODECLASS_OBJECT)
-            copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+          copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
 
     /* add a hastypedefinition reference */
@@ -269,13 +279,13 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                        const UA_NodeId *typeId) {
+                        const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(type->nodeClass != UA_NODECLASS_VARIABLETYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-
+    
     /* get the references to child properties */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
@@ -294,7 +304,7 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     /* add the child properties */
     for(size_t i = 0; i < browseResult.referencesSize; i++) {
         UA_ReferenceDescription *rd = &browseResult.references[i];
-        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
 
     /* add a hastypedefinition reference */
@@ -434,7 +444,7 @@ dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttribu
 }
 
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result) {
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback) {
     if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
        !item->nodeAttributes.content.decoded.type) {
         result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -512,15 +522,18 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_Ad
         UA_Node_deleteAnyNodeClass(node);
         return;
     }
-
+    
     /* instantiate if it has a type */
     if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
+        if (instantiationCallback != NULL)
+          instantiationCallback->method(result->addedNodeId, item->typeDefinition.nodeId, instantiationCallback->handle); 
+        
         if(item->nodeClass == UA_NODECLASS_OBJECT)
             result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
-                                                       &item->typeDefinition.nodeId);
+                                                       &item->typeDefinition.nodeId, instantiationCallback);
         else if(item->nodeClass == UA_NODECLASS_VARIABLE)
             result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
-                                                         &item->typeDefinition.nodeId);
+                                                         &item->typeDefinition.nodeId, instantiationCallback);
     }
 
     /* if instantiation failed, remove the node */
@@ -542,7 +555,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         return;
     }
     
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 #ifdef _MSVC_VER
     UA_Boolean *isExternal = UA_alloca(size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32)*size);
@@ -571,10 +584,10 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
     
     response->resultsSize = size;
     for(size_t i = 0; i < size; i++) {
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
-            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i]);
+            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i], NULL);
     }
 }
 
@@ -639,7 +652,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     return result.statusCode;
 }
 
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
@@ -695,36 +708,49 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     parent.nodeId = result.addedNodeId;
     
     /* create InputArguments */
-    UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
-    inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
-    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-    inputArgumentsVariableNode->valueRank = 1;
-    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
-                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    UA_AddNodesResult inputAddRes;
+    /* FIXME:   The namespace compiler does currently not recognize the interdependancy between methods
+     *          and arguments - everything is treated as a standalone node.
+     *          In order to allow the compiler to create methods with arguments from an XML, this routine
+     *          must be coerced into *not* creating arguments, as these will be added by the compiler as
+     *          standalone nodes later. A semantic of inputArgumentsSize < 0 is used to signal this.
+     * 
+     *          This is not a production feature and should be fixed on the compiler side! (@ichrispa)
+     */
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
-                              &parent.nodeId, &hasproperty, &inputAddRes);
-    // todo: check if adding succeeded
-    UA_AddNodesResult_deleteMembers(&inputAddRes);
-
+    if (inputArgumentsSize >= 0) {
+      UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
+      inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+      inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
+      inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+      inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+      inputArgumentsVariableNode->valueRank = 1;
+      UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
+                              inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+      UA_AddNodesResult inputAddRes;
+      UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
+                                &parent.nodeId, &hasproperty, &inputAddRes);
+      // todo: check if adding succeeded
+      UA_AddNodesResult_deleteMembers(&inputAddRes);
+    }
+    
     /* create OutputArguments */
-    UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
-    outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
-    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-    outputArgumentsVariableNode->valueRank = 1;
-    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
-                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-    UA_AddNodesResult outputAddRes;
-    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
-                              &parent.nodeId, &hasproperty, &outputAddRes);
-    // todo: check if adding succeeded
-    UA_AddNodesResult_deleteMembers(&outputAddRes);
-
+    /* FIXME:   See comment in inputArguments */
+    if (outputArgumentsSize >= 0) {
+      UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
+      outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+      outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
+      outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+      outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+      outputArgumentsVariableNode->valueRank = 1;
+      UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
+                              outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+      UA_AddNodesResult outputAddRes;
+      UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
+                                &parent.nodeId, &hasproperty, &outputAddRes);
+      // todo: check if adding succeeded
+      UA_AddNodesResult_deleteMembers(&outputAddRes);
+    }
+    
     if(outNewNodeId)
         *outNewNodeId = result.addedNodeId;
     else
@@ -795,7 +821,7 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 	}
 	response->resultsSize = size;
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 #ifdef NO_ALLOCA
     UA_Boolean isExternal[size];
     UA_UInt32 indices[size];
@@ -824,7 +850,7 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 
 	response->resultsSize = size;
 	for(size_t i = 0; i < response->resultsSize; i++) {
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 		if(!isExternal[i])
 #endif
             Service_AddReferences_single(server, session, &request->referencesToAdd[i]);

+ 6 - 6
src/server/ua_services_session.c

@@ -99,7 +99,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
     */
 
     /* anonymous login */
-    if(server->config.Login_enableAnonymous &&
+    if(server->config.enableAnonymousLogin &&
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
         const UA_AnonymousIdentityToken *token = request->userIdentityToken.content.decoded.data;
         if(token->policyId.data && !UA_String_equal(&token->policyId, &ap)) {
@@ -115,7 +115,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
     }
 
     /* username login */
-    if(server->config.Login_enableUsernamePassword &&
+    if(server->config.enableUsernamePasswordLogin &&
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
         const UA_UserNameIdentityToken *token = request->userIdentityToken.content.decoded.data;
         if(!UA_String_equal(&token->policyId, &up)) {
@@ -128,10 +128,10 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
             return;
         }
         /* ok, trying to match the username */
-        for(size_t i = 0; i < server->config.Login_loginsCount; ++i) {
-            UA_String user = UA_STRING(server->config.Login_usernames[i]);
-            UA_String pw = UA_STRING(server->config.Login_passwords[i]);
-            if(!UA_String_equal(&token->userName, &user) || !UA_String_equal(&token->password, &pw))
+        for(size_t i = 0; i < server->config.usernamePasswordLoginsSize; i++) {
+            UA_String *user = &server->config.usernamePasswordLogins[i].username;
+            UA_String *pw = &server->config.usernamePasswordLogins[i].password;
+            if(!UA_String_equal(&token->userName, user) || !UA_String_equal(&token->password, pw))
                 continue;
             /* success - activate */
             if(foundSession->channel && foundSession->channel != channel)

+ 44 - 32
src/server/ua_services_subscription.c

@@ -130,28 +130,36 @@ void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
         createMonitoredItems(server, session, sub, &request->itemsToCreate[i], &response->results[i]);
 }
 
-void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishRequest *request,
-                     UA_PublishResponse *response) {
+void
+Service_Publish(UA_Server *server, UA_Session *session,
+                const UA_PublishRequest *request, UA_UInt32 requestId) {
     UA_SubscriptionManager *manager= &session->subscriptionManager;
     if(!manager)
         return;
+
+    UA_PublishResponse response;
+    UA_PublishResponse_init(&response);
+    response.responseHeader.requestHandle = request->requestHeader.requestHandle;
+    response.responseHeader.timestamp = UA_DateTime_now();
     
     // Delete Acknowledged Subscription Messages
-    response->resultsSize = request->subscriptionAcknowledgementsSize;
-    response->results     = UA_malloc(sizeof(UA_StatusCode)*(response->resultsSize));
+    response.resultsSize = request->subscriptionAcknowledgementsSize;
+    response.results = UA_calloc(response.resultsSize, sizeof(UA_StatusCode));
     for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; i++) {
-        response->results[i] = UA_STATUSCODE_GOOD;
-        UA_Subscription *sub =
-            SubscriptionManager_getSubscriptionByID(&session->subscriptionManager,
-                                                    request->subscriptionAcknowledgements[i].subscriptionId);
+        response.results[i] = UA_STATUSCODE_GOOD;
+        UA_UInt32 sid = request->subscriptionAcknowledgements[i].subscriptionId;
+        UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(manager, sid);
         if(!sub) {
-            response->results[i] = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
+            response.results[i] = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
             continue;
         }
-        if(Subscription_deleteUnpublishedNotification(request->subscriptionAcknowledgements[i].sequenceNumber, false, sub) == 0)
-            response->results[i] = UA_STATUSCODE_BADSEQUENCENUMBERINVALID;
+        UA_UInt32 sn = request->subscriptionAcknowledgements[i].sequenceNumber;
+        if(Subscription_deleteUnpublishedNotification(sn, false, sub) == 0)
+            response.results[i] = UA_STATUSCODE_BADSEQUENCENUMBERINVALID;
     }
     
+    UA_Boolean have_response = UA_FALSE;
+
     // See if any new data is available
     UA_Subscription *sub;
     LIST_FOREACH(sub, &manager->serverSubscriptions, listEntry) {
@@ -181,39 +189,43 @@ void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishReq
             continue;
     
         // We found an unpublished notification message in this subscription, which we will now publish.
-        response->subscriptionId = sub->subscriptionID;
-        Subscription_copyNotificationMessage(&response->notificationMessage, notification);
+        response.subscriptionId = sub->subscriptionID;
+        Subscription_copyNotificationMessage(&response.notificationMessage, notification);
         // Mark this notification as published
         notification->publishedOnce = UA_TRUE;
         if(notification->notification.sequenceNumber > sub->sequenceNumber) {
             // If this is a keepalive message, its seqNo is the next seqNo to be used for an actual msg.
-            response->availableSequenceNumbersSize = 0;
+            response.availableSequenceNumbersSize = 0;
             // .. and must be deleted
             Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
         } else {
-            response->availableSequenceNumbersSize = sub->unpublishedNotificationsSize;
-            response->availableSequenceNumbers = Subscription_getAvailableSequenceNumbers(sub);
+            response.availableSequenceNumbersSize = sub->unpublishedNotificationsSize;
+            response.availableSequenceNumbers = Subscription_getAvailableSequenceNumbers(sub);
         }	  
-        // FIXME: This should be in processMSG();
-        session->validTill = UA_DateTime_now() + session->timeout * 10000;
-        return;
+        have_response = UA_TRUE;
     }
     
-    // FIXME: At this point, we would return nothing and "queue" the publish
-    // request, but currently we need to return something to the client. If no
-    // subscriptions have notifications, force one to generate a keepalive so we
-    // don't return an empty message
-    sub = LIST_FIRST(&manager->serverSubscriptions);
-    if(sub) {
-        response->subscriptionId = sub->subscriptionID;
-        sub->keepAliveCount.currentValue=sub->keepAliveCount.minValue;
-        Subscription_generateKeepAlive(sub);
-        Subscription_copyNotificationMessage(&response->notificationMessage, sub->unpublishedNotifications.lh_first);
-        Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
+    if(!have_response) {
+        // FIXME: At this point, we would return nothing and "queue" the publish
+        // request, but currently we need to return something to the client. If no
+        // subscriptions have notifications, force one to generate a keepalive so we
+        // don't return an empty message
+        sub = LIST_FIRST(&manager->serverSubscriptions);
+        if(sub) {
+            response.subscriptionId = sub->subscriptionID;
+            sub->keepAliveCount.currentValue=sub->keepAliveCount.minValue;
+            Subscription_generateKeepAlive(sub);
+            Subscription_copyNotificationMessage(&response.notificationMessage,
+                                                 LIST_FIRST(&sub->unpublishedNotifications));
+            Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
+        }
     }
     
-    // FIXME: This should be in processMSG();
-    session->validTill = UA_DateTime_now() + session->timeout * 10000;
+    UA_SecureChannel *channel = session->channel;
+    if(channel)
+        UA_SecureChannel_sendBinaryMessage(channel, requestId, &response,
+                                           &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
+    UA_PublishResponse_deleteMembers(&response);
 }
 
 void Service_ModifySubscription(UA_Server *server, UA_Session *session,

+ 28 - 23
src/server/ua_services_view.c

@@ -33,7 +33,7 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
     return retval;
 }
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 static const UA_Node *
 returnRelevantNodeExternal(UA_ExternalNodeStore *ens, const UA_BrowseDescription *descr,
                            const UA_ReferenceNode *reference) {
@@ -109,7 +109,7 @@ returnRelevantNode(UA_Server *server, const UA_BrowseDescription *descr, UA_Bool
             return NULL;
     }
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
     /* return the node from an external namespace*/
 	for(size_t nsIndex = 0; nsIndex < server->externalNamespacesSize; nsIndex++) {
 		if(reference->targetId.nodeId.namespaceIndex != server->externalNamespaces[nsIndex].index)
@@ -302,7 +302,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
                                                descr->resultMask, &result->references[referencesCount]);
             referencesCount++;
         }
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         /* relevant_node returns a node malloced with UA_ObjectNode_new
            if it is external (there is no UA_Node_new function) */
         if(isExternal == UA_TRUE)
@@ -350,8 +350,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
         cp->maxReferences = maxrefs;
         cp->continuationIndex = referencesCount;
         UA_Guid *ident = UA_Guid_new();
-        UA_UInt32 seed = (uintptr_t)cp;
-        *ident = UA_Guid_random(&seed);
+        *ident = UA_Guid_random();
         cp->identifier.data = (UA_Byte*)ident;
         cp->identifier.length = sizeof(UA_Guid);
         UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
@@ -385,7 +384,7 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
     }
     response->resultsSize = size;
     
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 #ifdef NO_ALLOCA
     UA_Boolean isExternal[size];
     UA_UInt32 indices[size];
@@ -412,7 +411,7 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
 #endif
 
     for(size_t i = 0; i < size; i++) {
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
             Service_Browse_single(server, session, NULL, &request->nodesToBrowse[i],
@@ -420,6 +419,23 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
     }
 }
 
+void
+UA_Server_browseNext_single(UA_Server *server, UA_Session *session, UA_Boolean releaseContinuationPoint,
+                            const UA_ByteString *continuationPoint, UA_BrowseResult *result) {
+    result->statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
+    struct ContinuationPointEntry *cp, *temp;
+    LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) {
+        if(UA_ByteString_equal(&cp->identifier, continuationPoint)) {
+            result->statusCode = UA_STATUSCODE_GOOD;
+            if(!releaseContinuationPoint)
+                Service_Browse_single(server, session, cp, NULL, 0, result);
+            else
+                removeCp(cp, session);
+            break;
+        }
+    }
+}
+
 void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseNextRequest *request,
                         UA_BrowseNextResponse *response) {
     UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
@@ -437,20 +453,9 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
    }
 
    response->resultsSize = size;
-   for(size_t i = 0; i < size; i++) {
-       response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
-       struct ContinuationPointEntry *cp, *temp;
-       LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) {
-           if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
-               response->results[i].statusCode = UA_STATUSCODE_GOOD;
-               if(!request->releaseContinuationPoints)
-                   Service_Browse_single(server, session, cp, NULL, 0, &response->results[i]);
-               else
-                   removeCp(cp, session);
-               break;
-           }
-       }
-   }
+   for(size_t i = 0; i < size; i++)
+       UA_Server_browseNext_single(server, session, request->releaseContinuationPoints,
+                                   &request->continuationPoints[i], &response->results[i]);
 }
 
 /***********************/
@@ -579,7 +584,7 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
         return;
     }
 
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 #ifdef NO_ALLOCA
     UA_Boolean isExternal[size];
     UA_UInt32 indices[size];
@@ -607,7 +612,7 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
 
     response->resultsSize = size;
     for(size_t i = 0; i < size; i++) {
-#ifdef UA_EXTERNAL_NAMESPACES
+#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
     	if(!isExternal[i])
 #endif
     		Service_TranslateBrowsePathsToNodeIds_single(server, session, &request->browsePaths[i],

+ 1 - 2
src/server/ua_session_manager.c

@@ -62,8 +62,7 @@ UA_SessionManager_createSession(UA_SessionManager *sessionManager, UA_SecureChan
     sessionManager->currentSessionCount++;
     UA_Session_init(&newentry->session);
     newentry->session.sessionId = UA_NODEID_NUMERIC(1, sessionManager->lastSessionId++);
-    UA_UInt32 randSeed = (UA_UInt32)(sessionManager->lastSessionId + UA_DateTime_now());
-    newentry->session.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random(&randSeed));
+    newentry->session.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());
 
     if(request->requestedSessionTimeout <= sessionManager->maxSessionLifeTime &&
        request->requestedSessionTimeout > 0)

+ 10 - 7
src/server/ua_subscription.c

@@ -316,7 +316,6 @@ UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, cons
     UA_Boolean samplingError = UA_TRUE; 
     UA_DataValue sourceDataValue;
     UA_DataValue_init(&sourceDataValue);
-    const UA_VariableNode *srcAsVariableNode = (const UA_VariableNode*)src;
   
     // FIXME: Not all attributeIDs can be monitored yet
     switch(attributeID) {
@@ -368,17 +367,18 @@ UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, cons
     case UA_ATTRIBUTEID_VALUE: 
         if(src->nodeClass == UA_NODECLASS_VARIABLE) {
             const UA_VariableNode *vsrc = (const UA_VariableNode*)src;
-            if(srcAsVariableNode->valueSource == UA_VALUESOURCE_VARIANT) {
+            if(vsrc->valueSource == UA_VALUESOURCE_VARIANT) {
+                if(vsrc->value.variant.callback.onRead)
+                    vsrc->value.variant.callback.onRead(vsrc->value.variant.callback.handle, vsrc->nodeId,
+                                                        &dst->value, NULL);
                 UA_Variant_copy(&vsrc->value.variant.value, &dst->value);
                 dst->hasValue = UA_TRUE;
-                //no onRead callback here since triggered by a subscription
                 samplingError = UA_FALSE;
             } else {
-                if(srcAsVariableNode->valueSource != UA_VALUESOURCE_DATASOURCE)
+                if(vsrc->valueSource != UA_VALUESOURCE_DATASOURCE || vsrc->value.dataSource.read == NULL)
                     break;
-                // todo: handle numeric ranges
-                if(srcAsVariableNode->value.dataSource.read(vsrc->value.dataSource.handle, vsrc->nodeId, UA_TRUE, NULL,
-                                                            &sourceDataValue) != UA_STATUSCODE_GOOD)
+                if(vsrc->value.dataSource.read(vsrc->value.dataSource.handle, vsrc->nodeId, UA_TRUE,
+                                               NULL, &sourceDataValue) != UA_STATUSCODE_GOOD)
                     break;
                 UA_DataValue_copy(&sourceDataValue, dst);
                 if(sourceDataValue.value.data) {
@@ -470,6 +470,9 @@ void MonitoredItem_QueuePushDataValue(UA_Server *server, UA_MonitoredItem *monit
     newValueAsByteString.length = 512; // Todo: Hack! We should make a copy of the value, not encode it. UA_calcSizeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE]);
     newValueAsByteString.data   = UA_malloc(newValueAsByteString.length);
     UA_StatusCode retval = UA_encodeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE], &newValueAsByteString, &encodingOffset);
+    //FIXME: Stasik0 workaround to fix due to the absence of calcSizeBinary #496, still a better solution is needed to ensure the comparisson works for values greater than 512 bytes
+    newValueAsByteString.length = encodingOffset;
+
     if(retval != UA_STATUSCODE_GOOD)
         UA_ByteString_deleteMembers(&newValueAsByteString);
   

+ 1 - 28
src/server/ua_subscription_manager.c

@@ -16,34 +16,7 @@ void SubscriptionManager_init(UA_Session *session) {
     manager->globalQueueSize = (UA_UInt32_BoundedValue) { .maxValue = 100, .minValue = 0, .currentValue=0 };
     LIST_INIT(&manager->serverSubscriptions);
     manager->lastSessionID = (UA_UInt32) UA_DateTime_now();
-    
-    // Initialize a GUID with a 2^64 time dependant part, then fold the time in on itself to provide a more randomish
-    // Counter
-    // NOTE: On a 32 bit plattform, assigning 64 bit (2 regs) is allowed by the compiler, but shifting though multiple
-    //       regs is usually not. To support both 32 and 64bit, the struct splits the 64Bit timestamp into two parts.
-    typedef union {
-        struct {
-            UA_UInt32 ui32h;
-            UA_UInt32 ui32l;
-        } individual;
-        UA_UInt64 ui64;
-    } guidInit;
-    guidInit guidInitH;
-    guidInitH.ui64 = (UA_UInt64) UA_DateTime_now();
-    manager->lastJobGuid.data1 = guidInitH.individual.ui32h;
-    manager->lastJobGuid.data2 = (UA_UInt16) (guidInitH.individual.ui32l >> 16);
-    manager->lastJobGuid.data3 = (UA_UInt16) (guidInitH.individual.ui32l);
-
-    guidInit guidInitL;
-    guidInitL.ui64 = (UA_UInt64) UA_DateTime_now();
-    manager->lastJobGuid.data4[0] = (UA_Byte) guidInitL.individual.ui32l;
-    manager->lastJobGuid.data4[1] = (UA_Byte) (guidInitL.individual.ui32l >> 8);
-    manager->lastJobGuid.data4[2] = (UA_Byte) (guidInitL.individual.ui32l >> 16);
-    manager->lastJobGuid.data4[3] = (UA_Byte) (guidInitL.individual.ui32l >> 24);
-    manager->lastJobGuid.data4[4] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.individual.ui32h);
-    manager->lastJobGuid.data4[5] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.individual.ui32h >> 8);
-    manager->lastJobGuid.data4[6] = (UA_Byte) (manager->lastJobGuid.data4[1]) ^ (guidInitL.individual.ui32h >> 16);
-    manager->lastJobGuid.data4[7] = (UA_Byte) (manager->lastJobGuid.data4[0]) ^ (guidInitL.individual.ui32h >> 24);
+    manager->lastJobGuid = UA_Guid_random();
 }
 
 void SubscriptionManager_deleteMembers(UA_Session *session, UA_Server *server) {

+ 2 - 2
src/ua_connection.c

@@ -130,7 +130,7 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RES
 }
 
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     UA_SecureChannel *channel = connection->channel;
     if(channel)
         uatomic_cmpxchg(&channel->connection, connection, NULL);
@@ -143,7 +143,7 @@ void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 }
 
 void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_cmpxchg(&channel->connection, NULL, connection) == NULL)
         uatomic_set(&connection->channel, channel);
 #else

+ 2 - 2
src/ua_securechannel.c

@@ -55,7 +55,7 @@ void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *sessi
     if(!se)
         return;
     se->session = session;
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_cmpxchg(&session->channel, NULL, channel) != NULL) {
         UA_free(se);
         return;
@@ -144,7 +144,7 @@ UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_U
 
     /* now write the header with the size */
     respHeader.messageHeader.messageSize = messagePos;
-#ifndef UA_MULTITHREADING
+#ifndef UA_ENABLE_MULTITHREADING
     seqHeader.sequenceNumber = ++channel->sequenceNumber;
 #else
     seqHeader.sequenceNumber = uatomic_add_return(&channel->sequenceNumber, 1);

+ 2 - 2
src/ua_session.c

@@ -41,7 +41,7 @@ void UA_Session_init(UA_Session *session) {
     session->timeout = 0;
     UA_DateTime_init(&session->validTill);
     session->channel = NULL;
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     SubscriptionManager_init(session);
 #endif
     session->availableContinuationPoints = MAXCONTINUATIONPOINTS;
@@ -62,7 +62,7 @@ void UA_Session_deleteMembersCleanup(UA_Session *session, UA_Server* server) {
     }
     if(session->channel)
         UA_SecureChannel_detachSession(session->channel, session);
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
     SubscriptionManager_deleteMembers(session, server);
 #endif
 }

+ 2 - 2
src/ua_session.h

@@ -8,7 +8,7 @@
 
 #define MAXCONTINUATIONPOINTS 5
 
-#ifdef ENABLE_SUBSCRIPTIONS
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 #include "server/ua_subscription_manager.h"
 #endif
 
@@ -36,7 +36,7 @@ struct UA_Session {
     UA_UInt32         maxResponseMessageSize;
     UA_Int64          timeout; // [ms]
     UA_DateTime       validTill;
-    #ifdef ENABLE_SUBSCRIPTIONS
+    #ifdef UA_ENABLE_SUBSCRIPTIONS
         UA_SubscriptionManager subscriptionManager;
     #endif
     UA_SecureChannel *channel;

+ 115 - 62
src/ua_types.c

@@ -23,13 +23,14 @@ UA_EXPORT void UA_random_seed(UA_UInt64 seed) {
     pcg32_srandom_r(&UA_rng, seed, UA_DateTime_now());
 }
 
-UA_EXPORT UA_UInt32 UA_random(void) {
-    return (UA_UInt32)pcg32_random_r(&UA_rng);
-}
-
 /*****************/
 /* Builtin Types */
 /*****************/
+
+UA_EXPORT UA_UInt32 UA_UInt32_random(void) {
+    return (UA_UInt32)pcg32_random_r(&UA_rng);
+}
+
 UA_String UA_String_fromChars(char const src[]) {
     UA_String str = UA_STRING_NULL;
     size_t length = strlen(src);
@@ -52,41 +53,44 @@ UA_Boolean UA_String_equal(const UA_String *string1, const UA_String *string2) {
 }
 
 /* DateTime */
-#define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
-#define HUNDRED_NANOSEC_PER_USEC 10LL
-#define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
-
-#if defined(__MINGW32__) && !defined(_TIMEZONE_DEFINED)
-# define _TIMEZONE_DEFINED
-struct timezone {
-  int tz_minuteswest;
-  int tz_dsttime;
-};
-#endif
-
+UA_DateTime UA_DateTime_now(void) {
 #ifdef _WIN32
-static const UA_UInt64 epoch = 116444736000000000;
-int gettimeofday(struct timeval *tp, struct timezone *tzp);
-int gettimeofday(struct timeval *tp, struct timezone *tzp) {
-    FILETIME       ft;
-    SYSTEMTIME     st;
-    ULARGE_INTEGER ul;
+    /* Windows filetime has the same definition as UA_DateTime */
+    FILETIME ft;
+    SYSTEMTIME st;
     GetSystemTime(&st);
     SystemTimeToFileTime(&st, &ft);
-    ul.LowPart  = ft.dwLowDateTime;
+    ULARGE_INTEGER ul;
+    ul.LowPart = ft.dwLowDateTime;
     ul.HighPart = ft.dwHighDateTime;
-    tp->tv_sec  = (long)((ul.QuadPart - epoch) / 10000000L);
-    tp->tv_usec = st.wMilliseconds * 1000;
-    return 0;
-}
-#endif
-
-UA_DateTime UA_DateTime_now(void) {
-    UA_DateTime dateTime;
+    return (UA_DateTime)ul.QuadPart;
+#else
     struct timeval tv;
     gettimeofday(&tv, NULL);
-    dateTime = (tv.tv_sec + UNIX_EPOCH_BIAS_SEC) * HUNDRED_NANOSEC_PER_SEC + tv.tv_usec * HUNDRED_NANOSEC_PER_USEC;
-    return dateTime;
+    return (tv.tv_sec * UA_SEC_TO_DATETIME) + (tv.tv_usec * UA_USEC_TO_DATETIME) + UA_DATETIME_UNIX_EPOCH;
+#endif
+}
+
+UA_DateTime UA_DateTime_nowMonotonic(void) {
+#ifdef _WIN32
+    LARGE_INTEGER freq, ticks;
+    QueryPerformanceFrequency(&freq);
+    QueryPerformanceCounter(&ticks);
+    UA_Double ticks2dt = UA_SEC_TO_DATETIME;
+    ticks2dt /= freq.QuadPart;
+    return (UA_DateTime)(ticks.QuadPart * ticks2dt);
+#elif defined(__APPLE__) || defined(__MACH__) // OS X does not have clock_gettime, use clock_get_time
+    clock_serv_t cclock;
+    mach_timespec_t mts;
+    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+    clock_get_time(cclock, &mts);
+    mach_port_deallocate(mach_task_self(), cclock);
+    return (mts.tv_sec * UA_SEC_TO_DATETIME) + (mts.tv_nsec / 100);
+#else
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+    return (ts.tv_sec * UA_SEC_TO_DATETIME) + (ts.tv_nsec / 100);
+#endif
 }
 
 UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
@@ -97,7 +101,7 @@ UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
     dateTimeStruct.milliSec = (UA_UInt16)((atime % 10000000) / 10000);
 
     /* Calculating the unix time with #include <time.h> */
-    time_t secSinceUnixEpoch = (atime/10000000) - UNIX_EPOCH_BIAS_SEC;
+    time_t secSinceUnixEpoch = (atime - UA_DATETIME_UNIX_EPOCH) / UA_SEC_TO_DATETIME;
     struct tm ts = *gmtime(&secSinceUnixEpoch);
     dateTimeStruct.sec    = (UA_UInt16)ts.tm_sec;
     dateTimeStruct.min    = (UA_UInt16)ts.tm_min;
@@ -149,7 +153,7 @@ UA_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) {
     return UA_FALSE;
 }
 
-UA_Guid UA_Guid_random(UA_UInt32 *seed) {
+UA_Guid UA_Guid_random(void) {
     UA_Guid result;
     result.data1 = (UA_UInt32)pcg32_random_r(&UA_rng);
     UA_UInt32 r = (UA_UInt32)pcg32_random_r(&UA_rng);
@@ -232,6 +236,22 @@ UA_Boolean UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) {
     return UA_FALSE;
 }
 
+/* ExpandedNodeId */
+static void ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p, const UA_DataType *_) {
+    NodeId_deleteMembers(&p->nodeId, _);
+    UA_String_deleteMembers(&p->namespaceUri);
+}
+
+static UA_StatusCode
+ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNodeId *dst, const UA_DataType *_) {
+    UA_StatusCode retval = NodeId_copy(&src->nodeId, &dst->nodeId, NULL);
+    retval |= UA_String_copy(&src->namespaceUri, &dst->namespaceUri);
+    dst->serverIndex = src->serverIndex;
+    if(retval != UA_STATUSCODE_GOOD)
+        ExpandedNodeId_deleteMembers(dst, NULL);
+    return retval;
+}
+
 /* ExtensionObject */
 static void ExtensionObject_deleteMembers(UA_ExtensionObject *p, const UA_DataType *_) {
     switch(p->encoding) {
@@ -536,6 +556,19 @@ UA_Variant_setArrayCopy(UA_Variant *v, const void *array,
     return UA_STATUSCODE_GOOD;
 }
 
+/* LocalizedText */
+static void LocalizedText_deleteMembers(UA_LocalizedText *p, const UA_DataType *_) {
+    UA_String_deleteMembers(&p->locale);
+    UA_String_deleteMembers(&p->text);
+}
+
+static UA_StatusCode
+LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst, const UA_DataType *_) {
+    UA_StatusCode retval = UA_String_copy(&src->locale, &dst->locale);
+    retval |= UA_String_copy(&src->text, &dst->text);
+    return retval;
+}
+
 /* DataValue */
 static void DataValue_deleteMembers(UA_DataValue *p, const UA_DataType *_) {
     Variant_deletemembers(&p->value, NULL);
@@ -593,44 +626,64 @@ void * UA_new(const UA_DataType *type) {
     return p;
 }
 
-static UA_StatusCode UA_copyFixedSize(const void *src, void *dst, const UA_DataType *type) {
+static UA_StatusCode copyByte(const void *src, void *dst, const UA_DataType *_) {
+    memcpy(dst, src, sizeof(UA_Byte));
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode copy2Byte(const void *src, void *dst, const UA_DataType *_) {
+    memcpy(dst, src, sizeof(UA_UInt16));
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode copy4Byte(const void *src, void *dst, const UA_DataType *_) {
+    memcpy(dst, src, sizeof(UA_UInt32));
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode copy8Byte(const void *src, void *dst, const UA_DataType *_) {
+    memcpy(dst, src, sizeof(UA_UInt64));
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode copyFixedSize(const void *src, void *dst, const UA_DataType *type) {
     memcpy(dst, src, type->memSize);
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode UA_copyNoInit(const void *src, void *dst, const UA_DataType *type);
+static UA_StatusCode copyNoInit(const void *src, void *dst, const UA_DataType *type);
 
 typedef UA_StatusCode (*UA_copySignature)(const void *src, void *dst, const UA_DataType *type);
 static const UA_copySignature copyJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
-    (UA_copySignature)UA_copyFixedSize, // Boolean
-    (UA_copySignature)UA_copyFixedSize, // SByte
-    (UA_copySignature)UA_copyFixedSize, // Byte
-    (UA_copySignature)UA_copyFixedSize, // Int16
-    (UA_copySignature)UA_copyFixedSize, // UInt16 
-    (UA_copySignature)UA_copyFixedSize, // Int32 
-    (UA_copySignature)UA_copyFixedSize, // UInt32 
-    (UA_copySignature)UA_copyFixedSize, // Int64
-    (UA_copySignature)UA_copyFixedSize, // UInt64 
-    (UA_copySignature)UA_copyFixedSize, // Float 
-    (UA_copySignature)UA_copyFixedSize, // Double 
-    (UA_copySignature)UA_copyNoInit, // String
-    (UA_copySignature)UA_copyFixedSize, // DateTime
-    (UA_copySignature)UA_copyFixedSize, // Guid 
-    (UA_copySignature)UA_copyNoInit, // ByteString
-    (UA_copySignature)UA_copyNoInit, // XmlElement
+    (UA_copySignature)copyByte, // Boolean
+    (UA_copySignature)copyByte, // SByte
+    (UA_copySignature)copyByte, // Byte
+    (UA_copySignature)copy2Byte, // Int16
+    (UA_copySignature)copy2Byte, // UInt16 
+    (UA_copySignature)copy4Byte, // Int32 
+    (UA_copySignature)copy4Byte, // UInt32 
+    (UA_copySignature)copy8Byte, // Int64
+    (UA_copySignature)copy8Byte, // UInt64 
+    (UA_copySignature)copy4Byte, // Float 
+    (UA_copySignature)copy8Byte, // Double 
+    (UA_copySignature)copyNoInit, // String
+    (UA_copySignature)copy8Byte, // DateTime
+    (UA_copySignature)copyFixedSize, // Guid 
+    (UA_copySignature)copyNoInit, // ByteString
+    (UA_copySignature)copyNoInit, // XmlElement
     (UA_copySignature)NodeId_copy,
-    (UA_copySignature)UA_copyNoInit, // ExpandedNodeId
-    (UA_copySignature)UA_copyFixedSize, // StatusCode
-    (UA_copySignature)UA_copyNoInit, // QualifiedName
-    (UA_copySignature)UA_copyNoInit, // LocalizedText
+    (UA_copySignature)ExpandedNodeId_copy,
+    (UA_copySignature)copy4Byte, // StatusCode
+    (UA_copySignature)copyNoInit, // QualifiedName
+    (UA_copySignature)LocalizedText_copy, // LocalizedText
     (UA_copySignature)ExtensionObject_copy,
     (UA_copySignature)DataValue_copy,
     (UA_copySignature)Variant_copy,
     (UA_copySignature)DiagnosticInfo_copy,
-    (UA_copySignature)UA_copyNoInit,
+    (UA_copySignature)copyNoInit // all others
 };
 
-static UA_StatusCode UA_copyNoInit(const void *src, void *dst, const UA_DataType *type) {
+static UA_StatusCode copyNoInit(const void *src, void *dst, const UA_DataType *type) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     uintptr_t ptrs = (uintptr_t)src;
     uintptr_t ptrd = (uintptr_t)dst;
@@ -668,7 +721,7 @@ static UA_StatusCode UA_copyNoInit(const void *src, void *dst, const UA_DataType
 
 UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *type) {
     memset(dst, 0, type->memSize);
-    return UA_copyNoInit(src, dst, type);
+    return copyNoInit(src, dst, type);
 }
 
 typedef void (*UA_deleteMembersSignature)(void *p, const UA_DataType *type);
@@ -692,10 +745,10 @@ static const UA_deleteMembersSignature deleteMembersJumpTable[UA_BUILTIN_TYPES_C
     (UA_deleteMembersSignature)UA_deleteMembers, // ByteString
     (UA_deleteMembersSignature)UA_deleteMembers, // XmlElement
     (UA_deleteMembersSignature)NodeId_deleteMembers,
-    (UA_deleteMembersSignature)UA_deleteMembers, // ExpandedNodeId
+    (UA_deleteMembersSignature)ExpandedNodeId_deleteMembers, // ExpandedNodeId
     (UA_deleteMembersSignature)nopDeleteMembers, // StatusCode
     (UA_deleteMembersSignature)UA_deleteMembers, // QualifiedName
-    (UA_deleteMembersSignature)UA_deleteMembers, // LocalizedText
+    (UA_deleteMembersSignature)LocalizedText_deleteMembers, // LocalizedText
     (UA_deleteMembersSignature)ExtensionObject_deleteMembers,
     (UA_deleteMembersSignature)DataValue_deleteMembers,
     (UA_deleteMembersSignature)Variant_deletemembers,

+ 11 - 75
src/ua_types_encoding_binary.c

@@ -66,18 +66,10 @@ UInt16_encodeBinary(UA_UInt16 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt16) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
-#if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     UA_UInt16 le_uint16 = htole16(*src);
     src = &le_uint16;
-#endif
-
-#ifdef UA_ALIGNED_MEMORY_ACCESS
-    dst->data[(*offset)++] = (*src & 0x00FF) >> 0;
-    dst->data[(*offset)++] = (*src & 0xFF00) >> 8;
-#else
-    *(UA_UInt16*)&dst->data[*offset] = *src;
+    memcpy(&dst->data[*offset], src, sizeof(UA_UInt16));
     *offset += 2;
-#endif
     return UA_STATUSCODE_GOOD;
 }
 
@@ -91,17 +83,9 @@ UInt16_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_UInt16 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt16) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-#ifdef UA_ALIGNED_MEMORY_ACCESS
-    *dst = (UA_UInt16) src->data[(*offset)++] << 0;
-    *dst |= (UA_UInt16) src->data[(*offset)++] << 8;
-#else
-    *dst = *((UA_UInt16*) &src->data[*offset]);
+    memcpy(dst, &src->data[*offset], sizeof(UA_UInt16));
     *offset += 2;
-#endif
-
-#if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     *dst = le16toh(*dst);
-#endif
     return UA_STATUSCODE_GOOD;
 }
 
@@ -116,20 +100,10 @@ UInt32_encodeBinary(UA_UInt32 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt32) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
-#if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     UA_UInt32 le_uint32 = htole32(*src);
     src = &le_uint32;
-#endif
-
-#ifdef UA_ALIGNED_MEMORY_ACCESS
-    dst->data[(*offset)++] = (*src & 0x000000FF) >> 0;
-    dst->data[(*offset)++] = (*src & 0x0000FF00) >> 8;
-    dst->data[(*offset)++] = (*src & 0x00FF0000) >> 16;
-    dst->data[(*offset)++] = (*src & 0xFF000000) >> 24;
-#else
-    *(UA_UInt32*) &dst->data[*offset] = *src;
+    memcpy(&dst->data[*offset], src, sizeof(UA_UInt32));
     *offset += 4;
-#endif
     return UA_STATUSCODE_GOOD;
 }
 
@@ -149,19 +123,9 @@ UInt32_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_UInt32 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt32) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-#ifdef UA_ALIGNED_MEMORY_ACCESS
-    *dst = (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF));
-    *dst |= (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 8);
-    *dst |= (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 16);
-    *dst |= (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 24);
-#else
-    *dst = *((UA_UInt32*) &src->data[*offset]);
+    memcpy(dst, &src->data[*offset], sizeof(UA_UInt32));
     *offset += 4;
-#endif
-
-#if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     *dst = le32toh(*dst);
-#endif
     return UA_STATUSCODE_GOOD;
 }
 
@@ -182,24 +146,10 @@ UInt64_encodeBinary(UA_UInt64 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt64) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
-#if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     UA_UInt64 le_uint64 = htole64(*src);
     src = &le_uint64;
-#endif
-
-#ifdef UA_ALIGNED_MEMORY_ACCESS
-    dst->data[(*offset)++] = (*src & 0x00000000000000FF) >> 0;
-    dst->data[(*offset)++] = (*src & 0x000000000000FF00) >> 8;
-    dst->data[(*offset)++] = (*src & 0x0000000000FF0000) >> 16;
-    dst->data[(*offset)++] = (*src & 0x00000000FF000000) >> 24;
-    dst->data[(*offset)++] = (*src & 0x000000FF00000000) >> 32;
-    dst->data[(*offset)++] = (*src & 0x0000FF0000000000) >> 40;
-    dst->data[(*offset)++] = (*src & 0x00FF000000000000) >> 48;
-    dst->data[(*offset)++] = (*src & 0xFF00000000000000) >> 56;
-#else
-    *(UA_UInt64*) &dst->data[*offset] = *src;
+    memcpy(&dst->data[*offset], src, sizeof(UA_UInt64));
     *offset += 8;
-#endif
     return UA_STATUSCODE_GOOD;
 }
 
@@ -219,23 +169,9 @@ UInt64_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_UInt64 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt64) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-#ifdef UA_ALIGNED_MEMORY_ACCESS
-    *dst  = (UA_UInt64) src->data[(*offset)++];
-    *dst |= (UA_UInt64) src->data[(*offset)++] << 8;
-    *dst |= (UA_UInt64) src->data[(*offset)++] << 16;
-    *dst |= (UA_UInt64) src->data[(*offset)++] << 24;
-    *dst |= (UA_UInt64) src->data[(*offset)++] << 32;
-    *dst |= (UA_UInt64) src->data[(*offset)++] << 40;
-    *dst |= (UA_UInt64) src->data[(*offset)++] << 48;
-    *dst |= (UA_UInt64) src->data[(*offset)++] << 56;
-#else
-    *dst = *((UA_UInt64*) &src->data[*offset]);
+    memcpy(dst, &src->data[*offset], sizeof(UA_UInt64));
     *offset += 8;
-#endif
-
-#if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     *dst = le64toh(*dst);
-#endif
     return UA_STATUSCODE_GOOD;
 }
 
@@ -348,7 +284,7 @@ Array_encodeBinary(const void *src, size_t length, const UA_DataType *type,
     else if(src == UA_EMPTY_ARRAY_SENTINEL)
         signed_length = 0;
     UA_StatusCode retval = Int32_encodeBinary(&signed_length, NULL, dst, offset);
-    if(retval != UA_STATUSCODE_GOOD)
+    if(retval != UA_STATUSCODE_GOOD || length == 0)
         return retval;
 
 #ifndef UA_NON_LITTLEENDIAN_ARCHITECTURE
@@ -964,11 +900,11 @@ DataValue_encodeBinary(UA_DataValue const *src, const UA_DataType *_,
     if(src->hasSourceTimestamp)
         retval |= DateTime_encodeBinary(&src->sourceTimestamp, NULL, dst, offset);
     if(src->hasSourcePicoseconds)
-        retval |= Int16_encodeBinary(&src->sourcePicoseconds, NULL, dst, offset);
+        retval |= UInt16_encodeBinary(&src->sourcePicoseconds, NULL, dst, offset);
     if(src->hasServerTimestamp)
         retval |= DateTime_encodeBinary(&src->serverTimestamp, NULL, dst, offset);
     if(src->hasServerPicoseconds)
-        retval |= Int16_encodeBinary(&src->serverPicoseconds, NULL, dst, offset);
+        retval |= UInt16_encodeBinary(&src->serverPicoseconds, NULL, dst, offset);
     return retval;
 }
 
@@ -986,14 +922,14 @@ DataValue_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
     if(dst->hasSourceTimestamp)
         retval |= DateTime_decodeBinary(src, offset, &dst->sourceTimestamp, NULL);
     if(dst->hasSourcePicoseconds) {
-        retval |= Int16_decodeBinary(src, offset, &dst->sourcePicoseconds, NULL);
+        retval |= UInt16_decodeBinary(src, offset, &dst->sourcePicoseconds, NULL);
         if(dst->sourcePicoseconds > MAX_PICO_SECONDS)
             dst->sourcePicoseconds = MAX_PICO_SECONDS;
     }
     if(dst->hasServerTimestamp)
         retval |= DateTime_decodeBinary(src, offset, &dst->serverTimestamp, NULL);
     if(dst->hasServerPicoseconds) {
-        retval |= Int16_decodeBinary(src, offset, &dst->serverPicoseconds, NULL);
+        retval |= UInt16_decodeBinary(src, offset, &dst->serverPicoseconds, NULL);
         if(dst->serverPicoseconds > MAX_PICO_SECONDS)
             dst->serverPicoseconds = MAX_PICO_SECONDS;
     }

+ 12 - 3
src/ua_util.h

@@ -48,7 +48,7 @@
 /* Thread Local Storage */
 /************************/
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 # ifdef __GNUC__
 #  define UA_THREAD_LOCAL __thread
 # elif defined(_MSC_VER)
@@ -64,22 +64,31 @@
 /* System Libraries */
 /********************/
 
-#include <time.h>
 #ifdef _WIN32
 # include <winsock2.h> //needed for amalgation
 # include <windows.h>
 # undef SLIST_ENTRY
+#endif
+
+#include <time.h>
+#ifdef _WIN32
+int gettimeofday(struct timeval *tp, struct timezone *tzp);
 #else
 # include <sys/time.h>
 #endif
 
+#if defined(__APPLE__) || defined(__MACH__)
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
 /*************************/
 /* External Dependencies */
 /*************************/
 
 #include "queue.h"
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 # define _LGPL_SOURCE
 # include <urcu.h>
 # include <urcu/wfcqueue.h>

examples/logger_stdout.c → src_extra/logger_stdout.c


examples/logger_stdout.h → src_extra/logger_stdout.h


+ 72 - 60
examples/networklayer_tcp.c

@@ -32,7 +32,7 @@
 # define CLOSESOCKET(S) close(S)
 #endif
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 # include <urcu/uatomic.h>
 #endif
 
@@ -117,10 +117,11 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
         UA_ByteString_deleteMembers(response);
 #ifdef _WIN32
         const int last_error = WSAGetLastError();
-        if(last_error == WSAEINTR || last_error == WSAEWOULDBLOCK)
+        #define TEST_RETRY (last_error == WSAEINTR || last_error == WSAEWOULDBLOCK)
 #else
-		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
+        #define TEST_RETRY (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
 #endif
+        if (TEST_RETRY)
             return UA_STATUSCODE_GOOD; /* retry */
         else {
             socket_close(connection);
@@ -186,16 +187,12 @@ static void FreeConnectionCallback(UA_Server *server, void *ptr) {
 #define MAXBACKLOG 100
 
 typedef struct {
-    UA_ServerNetworkLayer layer;
-    
-    /* config */
+    UA_ConnectionConfig conf;
     UA_UInt32 port;
-    UA_ConnectionConfig conf; /* todo: rename to localconf. */
-
+    UA_Logger logger; // Set during start
+    
     /* open sockets and connections */
-    fd_set fdset;
     UA_Int32 serversockfd;
-    UA_Int32 highestfd;
     size_t mappingsSize;
     struct ConnectionMapping {
         UA_Connection *connection;
@@ -221,20 +218,23 @@ ServerNetworkLayerReleaseRecvBuffer(UA_Connection *connection, UA_ByteString *bu
 }
 
 /* after every select, we need to reset the sockets we want to listen on */
-static void setFDSet(ServerNetworkLayerTCP *layer) {
-    FD_ZERO(&layer->fdset);
-    FD_SET((UA_UInt32)layer->serversockfd, &layer->fdset);
-    layer->highestfd = layer->serversockfd;
+static UA_Int32
+setFDSet(ServerNetworkLayerTCP *layer, fd_set *fdset) {
+    FD_ZERO(fdset);
+    FD_SET((UA_UInt32)layer->serversockfd, fdset);
+    UA_Int32 highestfd = layer->serversockfd;
     for(size_t i = 0; i < layer->mappingsSize; i++) {
-        FD_SET((UA_UInt32)layer->mappings[i].sockfd, &layer->fdset);
-        if(layer->mappings[i].sockfd > layer->highestfd)
-            layer->highestfd = layer->mappings[i].sockfd;
+        FD_SET((UA_UInt32)layer->mappings[i].sockfd, fdset);
+        if(layer->mappings[i].sockfd > highestfd)
+            highestfd = layer->mappings[i].sockfd;
     }
+    return highestfd;
 }
 
 /* callback triggered from the server */
-static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
-#ifdef UA_MULTITHREADING
+static void
+ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
+#ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_xchg(&connection->state, UA_CONNECTION_CLOSED) == UA_CONNECTION_CLOSED)
         return;
 #else
@@ -243,7 +243,7 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
     connection->state = UA_CONNECTION_CLOSED;
 #endif
     ServerNetworkLayerTCP *layer = connection->handle;
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Closing the Connection %i",
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "Closing the Connection %i",
                 connection->sockfd);
     /* only "shutdown" here. this triggers the select, where the socket is
        "closed" in the mainloop */
@@ -251,7 +251,8 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
 }
 
 /* call only from the single networking thread */
-static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
+static UA_StatusCode
+ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
     UA_Connection *c = malloc(sizeof(UA_Connection));
     if(!c)
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -259,7 +260,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     struct sockaddr_in addr;
     socklen_t addrlen = sizeof(struct sockaddr_in);
     getsockname(newsockfd, (struct sockaddr*)&addr, &addrlen);
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "New Connection %i over TCP from %s:%d",
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "New Connection %i over TCP from %s:%d",
                 newsockfd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
     UA_Connection_init(c);
     c->sockfd = newsockfd;
@@ -274,7 +275,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     struct ConnectionMapping *nm;
     nm = realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
     if(!nm) {
-        UA_LOG_ERROR(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "No memory for a new Connection");
+        UA_LOG_ERROR(layer->logger, UA_LOGCATEGORY_NETWORK, "No memory for a new Connection");
         free(c);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
@@ -284,17 +285,18 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger logger) {
-    layer->layer.logger = logger;
+static UA_StatusCode
+ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl) {
+    ServerNetworkLayerTCP *layer = nl->handle;
 #ifdef _WIN32
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error opening socket, code: %d",
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket, code: %d",
                        WSAGetLastError());
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 #else
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 #endif
@@ -304,37 +306,39 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, U
     int optval = 1;
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
                        "Error during setting of socket options");
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error during socket binding");
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error during socket binding");
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     socket_set_nonblocking(layer->serversockfd);
     listen(layer->serversockfd, MAXBACKLOG);
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "TCP network layer listening on %.*s",
-                layer->layer.discoveryUrl.length, layer->layer.discoveryUrl.data);
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "TCP network layer listening on %.*s",
+                nl->discoveryUrl.length, nl->discoveryUrl.data);
     return UA_STATUSCODE_GOOD;
 }
 
 static size_t
-ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UInt16 timeout) {
-    setFDSet(layer);
+ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout) {
+    ServerNetworkLayerTCP *layer = nl->handle;
+    fd_set fdset;
+    UA_Int32 highestfd = setFDSet(layer, &fdset);
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize;
-    resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
+    resultsize = select(highestfd+1, &fdset, NULL, NULL, &tmptv);
     if(resultsize < 0) {
         *jobs = NULL;
         return 0;
     }
 
     /* accept new connections (can only be a single one) */
-    if(FD_ISSET(layer->serversockfd, &layer->fdset)) {
+    if(FD_ISSET(layer->serversockfd, &fdset)) {
         resultsize--;
         struct sockaddr_in cli_addr;
         socklen_t cli_len = sizeof(cli_addr);
@@ -358,7 +362,7 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
     size_t j = 0;
     UA_ByteString buf = UA_BYTESTRING_NULL;
     for(size_t i = 0; i < layer->mappingsSize && j < (size_t)resultsize; i++) {
-        if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
+        if(!(FD_ISSET(layer->mappings[i].sockfd, &fdset)))
             continue;
         UA_StatusCode retval = socket_recv(layer->mappings[i].connection, &buf, 0);
         if(retval == UA_STATUSCODE_GOOD) {
@@ -398,8 +402,9 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
 }
 
 static size_t
-ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
+ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Job **jobs) {
+    ServerNetworkLayerTCP *layer = nl->handle;
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
                 "Shutting down the TCP network layer with %d open connection(s)", layer->mappingsSize);
     shutdown(layer->serversockfd,2);
     CLOSESOCKET(layer->serversockfd);
@@ -422,43 +427,54 @@ ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
 }
 
 /* run only when the server is stopped */
-static void ServerNetworkLayerTCP_deleteMembers(ServerNetworkLayerTCP *layer) {
+static void ServerNetworkLayerTCP_deleteMembers(UA_ServerNetworkLayer *nl) {
+    ServerNetworkLayerTCP *layer = nl->handle;
     free(layer->mappings);
+    free(layer);
+    UA_String_deleteMembers(&nl->discoveryUrl);
 }
 
-UA_ServerNetworkLayer * ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
+UA_ServerNetworkLayer
+UA_ServerNetworkLayerTCP(UA_ConnectionConfig conf, UA_UInt32 port, UA_Logger logger) {
 #ifdef _WIN32
     WORD wVersionRequested;
     WSADATA wsaData;
     wVersionRequested = MAKEWORD(2, 2);
     WSAStartup(wVersionRequested, &wsaData);
 #endif
+
+    UA_ServerNetworkLayer nl;
+    memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
     ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
     if(!layer)
-        return NULL;
-    memset(layer, 0, sizeof(ServerNetworkLayerTCP));
+        return nl;
+    
     layer->conf = conf;
+    layer->port = port;
+    layer->logger = logger;
     layer->mappingsSize = 0;
     layer->mappings = NULL;
-    layer->port = port;
+
+    /* get the discovery url from the hostname */
+    UA_String du = UA_STRING_NULL;
     char hostname[256];
     if(gethostname(hostname, 255) == 0) {
         char discoveryUrl[256];
-        UA_String str;
 #ifndef _MSC_VER
-        str.length = snprintf(discoveryUrl, 255, "opc.tcp://%s:%d", hostname, port);
+        du.length = snprintf(discoveryUrl, 255, "opc.tcp://%s:%d", hostname, port);
 #else
-        str.length = _snprintf_s(discoveryUrl, 255, _TRUNCATE, "opc.tcp://%s:%d", hostname, port);
+        du.length = _snprintf_s(discoveryUrl, 255, _TRUNCATE, "opc.tcp://%s:%d", hostname, port);
 #endif
-        str.data = (UA_Byte*)discoveryUrl;
-        UA_String_copy(&str, &layer->layer.discoveryUrl);
+        du.data = (UA_Byte*)discoveryUrl;
     }
 
-    layer->layer.start = (UA_StatusCode(*)(UA_ServerNetworkLayer*,UA_Logger))ServerNetworkLayerTCP_start;
-    layer->layer.getJobs = (size_t(*)(UA_ServerNetworkLayer*,UA_Job**,UA_UInt16))ServerNetworkLayerTCP_getJobs;
-    layer->layer.stop = (size_t(*)(UA_ServerNetworkLayer*, UA_Job**))ServerNetworkLayerTCP_stop;
-    layer->layer.deleteMembers = (void(*)(UA_ServerNetworkLayer*))ServerNetworkLayerTCP_deleteMembers;
-    return &layer->layer;
+    nl.handle = layer;
+    UA_String_copy(&du, &nl.discoveryUrl);
+    nl.start = ServerNetworkLayerTCP_start;
+    nl.getJobs = ServerNetworkLayerTCP_getJobs;
+    nl.stop = ServerNetworkLayerTCP_stop;
+    nl.deleteMembers = ServerNetworkLayerTCP_deleteMembers;
+    return nl;
 }
 
 /***************************/
@@ -481,7 +497,7 @@ ClientNetworkLayerReleaseBuffer(UA_Connection *connection, UA_ByteString *buf) {
 
 static void
 ClientNetworkLayerClose(UA_Connection *connection) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_xchg(&connection->state, UA_CONNECTION_CLOSED) == UA_CONNECTION_CLOSED)
         return;
 #else
@@ -494,7 +510,7 @@ ClientNetworkLayerClose(UA_Connection *connection) {
 
 /* we have no networklayer. instead, attach the reusable buffer to the handle */
 UA_Connection
-ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) {
+UA_ClientConnectionTCP(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) {
     UA_Connection connection;
     UA_Connection_init(&connection);
     connection.localConf = localConf;
@@ -523,12 +539,8 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpoin
         if(endpointUrl[portpos] == ':') {
             char *endPtr = NULL;
             unsigned long int tempulong = strtoul(&endpointUrl[portpos+1], &endPtr, 10);
-            if (ERANGE != errno &&
-                tempulong < UINT16_MAX &&
-                endPtr != &endpointUrl[portpos+1])
-            {
+            if (ERANGE != errno && tempulong < UINT16_MAX && endPtr != &endpointUrl[portpos+1])
                 port = (UA_UInt16)tempulong;
-            }
             break;
         }
     }

+ 3 - 2
examples/networklayer_tcp.h

@@ -14,10 +14,11 @@ extern "C" {
 #include "ua_client.h"
 
 /** @brief Create the TCP networklayer and listen to the specified port */
-UA_ServerNetworkLayer UA_EXPORT * ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port);
+UA_ServerNetworkLayer UA_EXPORT
+UA_ServerNetworkLayerTCP(UA_ConnectionConfig conf, UA_UInt32 port, UA_Logger logger);
 
 UA_Connection UA_EXPORT
-ClientNetworkLayerTCP_connect(UA_ConnectionConfig conf, const char *endpointUrl, UA_Logger logger);
+UA_ClientConnectionTCP(UA_ConnectionConfig conf, const char *endpointUrl, UA_Logger logger);
 
 #ifdef __cplusplus
 } // extern "C"

+ 1 - 1
examples/networklayer_udp.c

@@ -9,7 +9,7 @@
 #include <stdio.h>
 #include <string.h> // memset
 #include "networklayer_udp.h"
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 # include <urcu/uatomic.h>
 #endif
 

examples/networklayer_udp.h → src_extra/networklayer_udp.h


+ 4 - 4
tests/CMakeLists.txt

@@ -6,7 +6,7 @@ include_directories(${PROJECT_BINARY_DIR}/src_generated)
 find_package(Check REQUIRED)
 find_package(Threads REQUIRED)
 
-set(LIBS ${CHECK_LIBRARIES})
+set(LIBS ${CHECK_LIBRARIES} ${open62541_LIBRARIES})
 if(NOT WIN32)
   list(APPEND LIBS pthread m)
   if (NOT APPLE)
@@ -15,9 +15,9 @@ if(NOT WIN32)
 else()
     list(APPEND LIBS ws2_32)
 endif()
-if(ENABLE_MULTITHREADING)
+if(UA_ENABLE_MULTITHREADING)
     list(APPEND LIBS urcu-cds urcu urcu-common)
-endif(ENABLE_MULTITHREADING)
+endif()
 
 # the unit test are built directly on the open62541 object files. so they can
 # access symbols that are hidden/not exported to the shared library
@@ -68,7 +68,7 @@ add_test(session ${CMAKE_CURRENT_BINARY_DIR}/check_session)
 #                           ${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)
+#if(NOT UA_ENABLE_AMALGAMATION)
 #    list(APPEND check_fileinput_source ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
 #endif()
 #add_executable(check_server_interaction_fileinput ${check_fileinput_source})

+ 23 - 0
tests/check_builtin.c

@@ -873,6 +873,28 @@ START_TEST(UA_String_encodeShallWorkOnExample) {
 }
 END_TEST
 
+START_TEST(UA_ExpandedNodeId_encodeShallWorkOnExample) {
+    // given
+    UA_ExpandedNodeId src = UA_EXPANDEDNODEID_NUMERIC(0, 15);
+    src.namespaceUri = UA_STRING("testUri");
+
+    UA_Byte data[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                       0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                       0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                       0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
+    UA_ByteString dst = { 32, data };
+    UA_Int32  retval = 0;
+    size_t pos = 0;
+
+    // when
+    retval = UA_ExpandedNodeId_encodeBinary(&src, &dst, &pos);
+    // then
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+    ck_assert_int_eq(pos, 13);
+    ck_assert_int_eq(dst.data[0], 0x80); // namespaceuri flag
+}
+END_TEST
+
 START_TEST(UA_DataValue_encodeShallWorkOnExampleWithoutVariant) {
     // given
     UA_DataValue src;
@@ -1470,6 +1492,7 @@ static Suite *testSuite_builtin(void) {
     tcase_add_test(tc_encode, UA_Float_encodeShallWorkOnExample);
     tcase_add_test(tc_encode, UA_Double_encodeShallWorkOnExample);
     tcase_add_test(tc_encode, UA_String_encodeShallWorkOnExample);
+    tcase_add_test(tc_encode, UA_ExpandedNodeId_encodeShallWorkOnExample);
     tcase_add_test(tc_encode, UA_DataValue_encodeShallWorkOnExampleWithoutVariant);
     tcase_add_test(tc_encode, UA_DataValue_encodeShallWorkOnExampleWithVariant);
     tcase_add_test(tc_encode, UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject);

+ 19 - 19
tests/check_nodestore.c

@@ -7,7 +7,7 @@
 #include "ua_util.h"
 #include "check.h"
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 #include <pthread.h>
 #include <urcu.h>
 #endif
@@ -61,7 +61,7 @@ START_TEST(replaceNonExistingNode) {
 END_TEST
 
 START_TEST(findNodeInUA_NodeStoreWithSingleEntry) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 	// given
@@ -74,14 +74,14 @@ START_TEST(findNodeInUA_NodeStoreWithSingleEntry) {
 	ck_assert_int_eq((uintptr_t)inserted, (uintptr_t)nr);
 	// finally
 	UA_NodeStore_delete(ns);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }
 END_TEST
 
 START_TEST(failToFindNodeInOtherUA_NodeStore) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 	// given
@@ -98,14 +98,14 @@ START_TEST(failToFindNodeInOtherUA_NodeStore) {
 	// finally
 	UA_VariableNode_delete((UA_VariableNode*)n);
 	UA_NodeStore_delete(ns);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }
 END_TEST
 
 START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 	// given
@@ -130,14 +130,14 @@ START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
 	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)inserted);
 	// finally
 	UA_NodeStore_delete(ns);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }
 END_TEST
 
 START_TEST(iterateOverUA_NodeStoreShallNotVisitEmptyNodes) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 	// given
@@ -164,14 +164,14 @@ START_TEST(iterateOverUA_NodeStoreShallNotVisitEmptyNodes) {
 	ck_assert_int_eq(visitCnt, 6);
 	// finally
 	UA_NodeStore_delete(ns);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }
 END_TEST
 
 START_TEST(findNodeInExpandedNamespace) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 	// given
@@ -190,14 +190,14 @@ START_TEST(findNodeInExpandedNamespace) {
 	// finally
 	UA_free((void*)n2);
 	UA_NodeStore_delete(ns);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }
 END_TEST
 
 START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 	// given
@@ -217,14 +217,14 @@ START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
 	ck_assert_int_eq(visitCnt, 200);
 	// finally
 	UA_NodeStore_delete(ns);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }
 END_TEST
 
 START_TEST(failToFindNonExistantNodeInUA_NodeStoreWithSeveralEntries) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 	// given
@@ -248,7 +248,7 @@ START_TEST(failToFindNonExistantNodeInUA_NodeStoreWithSeveralEntries) {
 	// finally
 	UA_free((void *)n6);
 	UA_NodeStore_delete(ns);
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }
@@ -258,7 +258,7 @@ END_TEST
 /* Performance Profiling Test Cases */
 /************************************/
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 struct UA_NodeStoreProfileTest {
 	UA_NodeStore *ns;
 	UA_Int32 min_val;
@@ -286,7 +286,7 @@ static void *profileGetThread(void *arg) {
 #endif
 
 START_TEST(profileGetDelete) {
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
    	rcu_register_thread();
 #endif
 
@@ -299,7 +299,7 @@ START_TEST(profileGetDelete) {
 	}
 	clock_t begin, end;
 	begin = clock();
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 #define THREADS 4
     pthread_t t[THREADS];
 	struct UA_NodeStoreProfileTest p[THREADS];
@@ -326,7 +326,7 @@ START_TEST(profileGetDelete) {
 
 	UA_NodeStore_delete(ns);
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 #endif
 }

+ 90 - 8
tests/check_services_attributes.c

@@ -12,7 +12,7 @@
 #include "ua_util.h"
 #include "server/ua_server_internal.h"
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 #include <pthread.h>
 #include <urcu.h>
 #endif
@@ -34,7 +34,20 @@ static UA_Server* makeTestSequence(void) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
+	
+    /* DataSource VariableNode */
+    UA_VariableAttributes_init(&vattr);
+    UA_DataSource temperatureDataSource = (UA_DataSource) {
+                                           .handle = NULL, .read = NULL, .write = NULL};
+    vattr.description = UA_LOCALIZEDTEXT("en_US","temperature");
+    vattr.displayName = UA_LOCALIZEDTEXT("en_US","temperature");
+    UA_Server_addDataSourceVariableNode(server, UA_NODEID_STRING(1, "cpu.temperature"),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+					UA_QUALIFIEDNAME(1, "cpu temperature"),
+                                        UA_NODEID_NULL, vattr, temperatureDataSource, NULL);
+
     
     /* VariableNode with array */
     UA_VariableAttributes_init(&vattr);
@@ -50,7 +63,7 @@ static UA_Server* makeTestSequence(void) {
     parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
 
     /* ObjectNode */
     UA_ObjectAttributes obj_attr;
@@ -62,7 +75,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Demo"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
-                            obj_attr, NULL);
+                            obj_attr, NULL, NULL);
 
     /* ViewNode */
     UA_ViewAttributes view_attr;
@@ -72,9 +85,9 @@ static UA_Server* makeTestSequence(void) {
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL);
+                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL, NULL);
 
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
 	/* MethodNode */
     UA_MethodAttributes ma;
     UA_MethodAttributes_init(&ma);
@@ -538,7 +551,7 @@ START_TEST(ReadSingleAttributeHistorizingWithoutTimestamp) {
 } END_TEST
 
 START_TEST(ReadSingleAttributeExecutableWithoutTimestamp) {
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     UA_Server *server = makeTestSequence();
     UA_DataValue resp;
     UA_DataValue_init(&resp);
@@ -559,7 +572,7 @@ START_TEST(ReadSingleAttributeExecutableWithoutTimestamp) {
 } END_TEST
 
 START_TEST(ReadSingleAttributeUserExecutableWithoutTimestamp) {
-#ifdef ENABLE_METHODCALLS
+#ifdef UA_ENABLE_METHODCALLS
     UA_Server *server = makeTestSequence();
     UA_DataValue resp;
     UA_DataValue_init(&resp);
@@ -579,6 +592,57 @@ START_TEST(ReadSingleAttributeUserExecutableWithoutTimestamp) {
 #endif
 } END_TEST
 
+START_TEST(ReadSingleDataSourceAttributeValueWithoutTimestamp) {
+    UA_Server *server = makeTestSequence();
+    UA_DataValue resp;
+    UA_DataValue_init(&resp);
+    UA_ReadRequest rReq;
+    UA_ReadRequest_init(&rReq);
+    rReq.nodesToRead = UA_ReadValueId_new();
+    rReq.nodesToReadSize = 1;
+    rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "cpu.temperature");
+    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    ck_assert_int_eq(UA_STATUSCODE_BADINTERNALERROR, resp.status);
+    UA_Server_delete(server);
+    UA_ReadRequest_deleteMembers(&rReq);
+    UA_DataValue_deleteMembers(&resp);
+} END_TEST
+
+START_TEST(ReadSingleDataSourceAttributeDataTypeWithoutTimestamp) {
+    UA_Server *server = makeTestSequence();
+    UA_DataValue resp;
+    UA_DataValue_init(&resp);
+    UA_ReadRequest rReq;
+    UA_ReadRequest_init(&rReq);
+    rReq.nodesToRead = UA_ReadValueId_new();
+    rReq.nodesToReadSize = 1;
+    rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "cpu.temperature");
+    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_DATATYPE;
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    ck_assert_int_eq(UA_STATUSCODE_BADINTERNALERROR, resp.status);
+    UA_Server_delete(server);
+    UA_ReadRequest_deleteMembers(&rReq);
+    UA_DataValue_deleteMembers(&resp);
+} END_TEST
+
+START_TEST (ReadSingleDataSourceAttributeArrayDimensionsWithoutTimestamp) {
+    UA_Server *server = makeTestSequence();
+    UA_DataValue resp;
+    UA_DataValue_init(&resp);
+    UA_ReadRequest rReq;
+    UA_ReadRequest_init(&rReq);
+    rReq.nodesToRead = UA_ReadValueId_new();
+    rReq.nodesToReadSize = 1;
+    rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "cpu.temperature");
+    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    ck_assert_int_eq(UA_STATUSCODE_BADINTERNALERROR, resp.status);
+    UA_Server_delete(server);
+    UA_ReadRequest_deleteMembers(&rReq);
+    UA_DataValue_deleteMembers(&resp);
+} END_TEST
+
 /* Tests for writeValue method */
 
 START_TEST(WriteSingleAttributeNodeId) {
@@ -908,6 +972,20 @@ START_TEST(WriteSingleAttributeUserExecutable) {
     UA_Server_delete(server);
 } END_TEST
 
+START_TEST(WriteSingleDataSourceAttributeValue) {
+    UA_Server *server = makeTestSequence();
+    UA_WriteValue wValue;
+    UA_WriteValue_init(&wValue);
+    UA_Int32 testValue = 0;
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_INT32]);
+    wValue.nodeId = UA_NODEID_STRING(1, "cpu.temperature");
+    wValue.attributeId = UA_ATTRIBUTEID_VALUE;
+    wValue.value.hasValue = UA_TRUE;
+    UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
+    ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
+    UA_Server_delete(server);
+} END_TEST
+
 START_TEST(numericRange) {
     UA_NumericRange range;
     const UA_String str = (UA_String){9, (UA_Byte*)"1:2,0:3,5"};
@@ -950,6 +1028,9 @@ static Suite * testSuite_services_attributes(void) {
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeHistorizingWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeExecutableWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeUserExecutableWithoutTimestamp);
+	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeValueWithoutTimestamp);
+	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestamp);
+	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeArrayDimensionsWithoutTimestamp);
 
 	suite_add_tcase(s, tc_readSingleAttributes);
 
@@ -976,6 +1057,7 @@ static Suite * testSuite_services_attributes(void) {
 	tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeHistorizing);
 	tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeExecutable);
 	tcase_add_test(tc_writeSingleAttributes, WriteSingleAttributeUserExecutable);
+	tcase_add_test(tc_writeSingleAttributes, WriteSingleDataSourceAttributeValue);
 
 	suite_add_tcase(s, tc_writeSingleAttributes);
 

+ 33 - 4
tests/check_services_nodemanagement.c

@@ -12,11 +12,16 @@
 #include "ua_util.h"
 #include "server/ua_server_internal.h"
 
-#ifdef UA_MULTITHREADING
+#ifdef UA_ENABLE_MULTITHREADING
 #include <pthread.h>
 #include <urcu.h>
 #endif
 
+static UA_StatusCode
+instantiationMethod(UA_NodeId newNodeId, UA_NodeId templateId, void *handle ) {
+  *((UA_Int32 *) handle) += 1;
+  return UA_STATUSCODE_GOOD;
+}
 START_TEST(AddVariableNode) {
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
 
@@ -32,11 +37,34 @@ START_TEST(AddVariableNode) {
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                                  myIntegerName, UA_NODEID_NULL, attr, NULL);
+                                                  myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
     UA_Server_delete(server);
 } END_TEST
 
+START_TEST(AddComplexTypeWithInheritance) {
+  UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+  
+  /* add a variable node to the address space */
+  UA_ObjectAttributes attr;
+  UA_ObjectAttributes_init(&attr);
+  attr.description = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
+  attr.displayName = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
+  
+  UA_NodeId myObjectNodeId = UA_NODEID_STRING(1, "the.fake.Server.Struct");
+  UA_QualifiedName myObjectName = UA_QUALIFIEDNAME(1, "the.fake.Server.Struct");
+  UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+  UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+  UA_Int32 handleCalled;
+  UA_InstantiationCallback iCallback = {.method=instantiationMethod, .handle = (void *) &handleCalled};
+    
+  UA_StatusCode res = UA_Server_addObjectNode(server, myObjectNodeId, parentNodeId, parentReferenceNodeId,
+                                                myObjectName, UA_NODEID_NUMERIC(0, 2004), attr, &iCallback, NULL);
+  ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
+  ck_assert_int_gt(handleCalled, 0); // Should be 58, but may depend on NS0 XML detail
+  UA_Server_delete(server);
+} END_TEST
+
 START_TEST(AddNodeTwiceGivesError) {
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
 
@@ -52,10 +80,10 @@ START_TEST(AddNodeTwiceGivesError) {
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                                  myIntegerName, UA_NODEID_NULL, attr, NULL);
+                                                  myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
     res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                    myIntegerName, UA_NODEID_NULL, attr, NULL);
+                                    myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_BADNODEIDEXISTS);
     UA_Server_delete(server);
 } END_TEST
@@ -65,6 +93,7 @@ static Suite * testSuite_services_nodemanagement(void) {
 
 	TCase *tc_addnodes = tcase_create("addnodes");
 	tcase_add_test(tc_addnodes, AddVariableNode);
+        tcase_add_test(tc_addnodes, AddComplexTypeWithInheritance);
 	tcase_add_test(tc_addnodes, AddNodeTwiceGivesError);
 
 	suite_add_tcase(s, tc_addnodes);

+ 0 - 20
tools/.checkPorts.sh

@@ -1,20 +0,0 @@
-#!/bin/bash
-
-#
-# This script checks whether all patches from /ports dir are applicable
-#
-
-PATCHES=ports/*
-
-for p in $PATCHES
-do
-	git apply --check $p
-	if [[ "$?" == 0 ]] 
-	then
-		echo $p is applicable
-	else
-		echo failed to apply $p
-		exit 1
-	fi
-	
-done

+ 0 - 20
tools/.deployGH_doc.sh

@@ -1,20 +0,0 @@
-#!/bin/bash
-
-#
-# This script is run by travis-ci and pushes generated
-# Doxygen docs and single-source distributions to open62541-www
-#
-
-git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/acplt/open62541-www
-cd open62541-www
-#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 "updated generated documentation on webpage by travis-ci [ci skip]"
-git push https://$GITAUTH@github.com/acplt/open62541-www
-cd ..
-rm -rf open62541-www

+ 0 - 54
tools/.deployGH_release.sh

@@ -1,54 +0,0 @@
-#!/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 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 ..
-
-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 "added release files and updated releases webpage by travis-ci [ci skip]"
-git push https://$GITAUTH@github.com/acplt/open62541-www
-cd ..
-rm -rf open62541-www

+ 9 - 38
tools/generate_datatypes.py

@@ -144,32 +144,16 @@ class BuiltinType(Type):
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(" + self.name + "), " + \
                 ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
-                ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
+                ".membersSize = 1,\n\t.members = (UA_DataTypeMember[]){{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
                 (".memberName = \"\", " if typeintrospection else "") + \
                 ".padding = 0, .isArray = UA_TRUE }}, " + \
                 ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
 
-        if self.name == "UA_ExpandedNodeId":
-            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-                ".memSize = sizeof(UA_ExpandedNodeId), " + \
-                ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
-                ".membersSize = 3, .members = {" + \
-                "\n\t{.memberTypeIndex = UA_TYPES_NODEID, .namespaceZero = UA_TRUE, " + \
-                (".memberName = \"nodeId\", " if typeintrospection else "") + \
-                ".padding = 0, .isArray = UA_FALSE }," + \
-                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
-                (".memberName = \"namespaceUri\", " if typeintrospection else "") + \
-                ".padding = offsetof(UA_ExpandedNodeId, namespaceUri) - sizeof(UA_NodeId), .isArray = UA_FALSE }," + \
-                "\n\t{.memberTypeIndex = UA_TYPES_UINT32, .namespaceZero = UA_TRUE, " + \
-                (".memberName = \"serverIndex\", " if typeintrospection else "") + \
-                ".padding = offsetof(UA_ExpandedNodeId, serverIndex) - offsetof(UA_ExpandedNodeId, namespaceUri) - sizeof(UA_String), .isArray = UA_FALSE }},\n" + \
-                ".typeIndex = UA_TYPES_EXPANDEDNODEID }"
-
         if self.name == "UA_QualifiedName":
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(UA_QualifiedName), " + \
                 ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
-                ".membersSize = 2, .members = {" + \
+                ".membersSize = 2, .members = (UA_DataTypeMember[]){" + \
                 "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
                 (".memberName = \"namespaceIndex\", " if typeintrospection else "") + \
                 ".padding = 0, .isArray = UA_FALSE }," + \
@@ -178,24 +162,11 @@ class BuiltinType(Type):
                 ".padding = offsetof(UA_QualifiedName, name)-sizeof(UA_UInt16), .isArray = UA_FALSE }},\n" + \
                 ".typeIndex = UA_TYPES_QUALIFIEDNAME }"
 
-        if self.name == "UA_LocalizedText":
-            return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-                ".memSize = sizeof(UA_LocalizedText), " + \
-                ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
-                ".membersSize = 2, .members = {" + \
-                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
-                (".memberName = \"locale\", " if typeintrospection else "") + \
-                ".padding = 0, .isArray = UA_FALSE }," + \
-                "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
-                (".memberName = \"text\", " if typeintrospection else "") + \
-                ".padding = offsetof(UA_LocalizedText, text)-sizeof(UA_String), .isArray = UA_FALSE }},\n" + \
-                ".typeIndex = UA_TYPES_LOCALIZEDTEXT }"
-
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), " + \
             ".builtin = UA_TRUE, .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
             ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
-            ", .membersSize = 1, .members = {" + \
+            ", .membersSize = 1, .members = (UA_DataTypeMember[]){" + \
             "\n\t{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + " , .namespaceZero = UA_TRUE, " + \
             (".memberName = \"\", " if typeintrospection else "") + \
             ".padding = 0, .isArray = UA_FALSE }},\n" + \
@@ -236,7 +207,7 @@ class EnumerationType(Type):
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), .builtin = UA_TRUE, " + \
             ".fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
-            ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32, " + \
+            ".membersSize = 1,\n\t.members = (UA_DataTypeMember[]){{.memberTypeIndex = UA_TYPES_INT32, " + \
             (".memberName = \"\", " if typeintrospection else "") + \
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
 
@@ -257,7 +228,7 @@ class OpaqueType(Type):
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
-            ".builtin = UA_FALSE, .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE," + \
+            ".builtin = UA_FALSE, .membersSize = 1,\n\t.members = (UA_DataTypeMember[]){{.memberTypeIndex = UA_TYPES_BYTE," + \
             (".memberName = \"\", " if typeintrospection else "") + \
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_TRUE }}, .typeIndex = %s}" % (outname.upper() + "_" + self.name[3:].upper())
 
@@ -324,10 +295,10 @@ class StructType(Type):
                  ", .typeIndex = " + outname.upper() + "_" + self.name[3:].upper() + \
                  ", .membersSize = " + str(len(self.members)) + ","
         if len(self.members) > 0:
-            layout += "\n\t.members={"
+            layout += "\n\t.members=(UA_DataTypeMember[]){"
             for index, member in enumerate(self.members.values()):
                 layout += "\n\t{" + \
-                          ((".memberName = \"" + member.name[0].upper() + member.name[1:] + "\", ") if typeintrospection else "") + \
+                          ((".memberName = \"" + member.name + "\", ") if typeintrospection else "") + \
                           ".memberTypeIndex = " + ("UA_TYPES_" + member.memberType.name[3:].upper() if args.namespace_id == 0 or member.memberType.name in existing_types else \
                                                    outname.upper() + "_" + member.memberType.name[3:].upper()) + ", " + \
                           ".namespaceZero = "+ \
@@ -540,7 +511,7 @@ extern "C" {
 */
 ''')
 printh("#define " + outname.upper() + "_COUNT %s\n" % (str(len(types))))
-printh("extern UA_EXPORT const UA_DataType *" + outname.upper() + ";\n")
+printh("extern UA_EXPORT const UA_DataType " + outname.upper() + "[];\n")
 
 i = 0
 if sys.version_info[0] < 3:
@@ -587,7 +558,7 @@ printc('''/**
 #include "stddef.h"
 #include "ua_types.h"
 #include "''' + outname + '''_generated.h"\n
-const UA_DataType *''' + outname.upper() + ''' = (UA_DataType[]){''')
+const UA_DataType ''' + outname.upper() + '''[] = {''')
 if sys.version_info[0] < 3:
     values = types.itervalues()
 else:

+ 10 - 3
tools/pyUANamespace/open62541_MacroHelper.py

@@ -115,6 +115,9 @@ class open62541_MacroHelper():
     code.append("attr.displayName = UA_LOCALIZEDTEXT(\"\", \"" + str(node.displayName()) + "\");")
     code.append("attr.description = UA_LOCALIZEDTEXT(\"\", \"" + str(node.description()) + "\");")
     
+    if nodetype in ["Variable", "VariableType"]:
+      code = code + node.printOpen62541CCode_SubtypeEarly(bootstrapping = False)
+    
     code.append("UA_NodeId nodeId = " + str(self.getCreateNodeIDMacro(node)) + ";")
     if nodetype in ["Object", "Variable"]:
       code.append("UA_NodeId typeDefinition = UA_NODEID_NULL;") # todo instantiation of object and variable types
@@ -125,16 +128,20 @@ class open62541_MacroHelper():
       code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(" +  str(extrNs[0]) + ", \"" + extrNs[1] + "\");")
     else:
       code.append("UA_QualifiedName nodeName = UA_QUALIFIEDNAME(0, \"" + str(node.browseName()) + "\");")
-
+    
+    # In case of a MethodNode: Add in|outArg struct generation here. Mandates that namespace reordering was done using 
+    # Djikstra (check that arguments have not been printed). (@ichrispa)
     code.append("UA_Server_add%sNode(server, nodeId, parentNodeId, parentReferenceNodeId, nodeName" % nodetype)
       
     if nodetype in ["Object", "Variable"]:
       code.append("       , typeDefinition")
     
     if nodetype != "Method":
-      code.append("       , attr, NULL);")
+      code.append("       , attr, NULL, NULL);")
     else:
-      code.append("       , attr, (UA_MethodCallback) NULL, NULL, 0, NULL, 0, NULL, NULL);")
+      # FIXME:  Semantic of inputArgumentSize = -1 is used to signal the suppression of argument creation.
+      #         This should be replaced with a properly generated struct for the arguments.
+      code.append("       , attr, (UA_MethodCallback) NULL, NULL, -1, NULL, -1, NULL, NULL);")
     return code
     
   def getCreateNodeBootstrap(self, node):

+ 15 - 17
tools/pyUANamespace/ua_builtin_types.py

@@ -353,8 +353,7 @@ class opcua_value_t():
           for v in self.value:
             log(self, "Building extObj array index " + str(self.value.index(v)))
             code = code + v.printOpen62541CCode_SubType_build(arrayIndex=self.value.index(v))
-        code.append("UA_Variant *" + self.parent.getCodePrintableID() + "_variant = UA_Variant_new();")
-        code.append(self.parent.getCodePrintableID() + "_variant->type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
+        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
         code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + "[" + str(len(self.value)) + "];")
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           for v in self.value:
@@ -364,7 +363,7 @@ class opcua_value_t():
         else:
           for v in self.value:
             code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType() + ";")
-        code.append("UA_Variant_setArrayCopy(" + self.parent.getCodePrintableID() + "_variant, &" + valueName +
+        code.append("UA_Variant_setArrayCopy( &attr.value, &" + valueName +
                     ", (UA_Int32) " + str(len(self.value)) + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
     else:
       # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
@@ -380,16 +379,15 @@ class opcua_value_t():
         # The following strategy applies to all other types, in particular strings and numerics.
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           code = code + self.value[0].printOpen62541CCode_SubType_build()
-        code.append("UA_Variant *" + self.parent.getCodePrintableID() + "_variant = UA_Variant_new();")
-        code.append(self.parent.getCodePrintableID() + "_variant->type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
+        #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy(" + self.parent.getCodePrintableID() + "_variant, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
+          code.append("UA_Variant_setScalarCopy( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
           #FIXME: There is no membership definition for extensionObjects generated in this function.
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
         else:
           code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy(" + self.parent.getCodePrintableID() + "_variant, &" + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
+          code.append("UA_Variant_setScalarCopy( &attr.value, &" + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(&" + valueName + ");")
     return code
 
@@ -477,9 +475,9 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
 
     # Allocate some memory
     code.append("UA_ExtensionObject *" + self.getCodeInstanceName() + " =  UA_ExtensionObject_new();")
-    code.append(self.getCodeInstanceName() + "->encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;")
-    code.append(self.getCodeInstanceName() + "->typeId = UA_NODEID_NUMERIC(" + str(self.parent.dataType().target().id().ns) + ", " + str(self.parent.dataType().target().id().i) + "+ UA_ENCODINGOFFSET_BINARY);")
-    code.append("UA_ByteString_newMembers(&" + self.getCodeInstanceName() + "->body, 65000);" )
+    code.append(self.getCodeInstanceName() + "->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;")
+    code.append(self.getCodeInstanceName() + "->content.encoded.typeId = UA_NODEID_NUMERIC(" + str(self.parent.dataType().target().id().ns) + ", " + str(self.parent.dataType().target().id().i) + "+ UA_ENCODINGOFFSET_BINARY);")
+    code.append("if(UA_ByteString_allocBuffer(&" + self.getCodeInstanceName() + "->content.encoded.body, 65000) != UA_STATUSCODE_GOOD) {}" )
 
     # Encode each value as a bytestring seperately.
     code.append("size_t " + self.getCodeInstanceName() + "_encOffset = 0;" )
@@ -488,20 +486,20 @@ class opcua_BuiltinType_extensionObject_t(opcua_value_t):
       encField = self.getEncodingRule()[encFieldIdx]
       encFieldIdx = encFieldIdx + 1;
       if encField[2] == 0:
-        code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + ", &" + self.getCodeInstanceName() + "->body, &" + self.getCodeInstanceName() + "_encOffset);" )
+        code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + ", &" + self.getCodeInstanceName() + "->content.encoded.body, &" + self.getCodeInstanceName() + "_encOffset);" )
       else:
         if isinstance(subv, list):
           for subvidx in range(0,len(subv)):
-            code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + "], &" + self.getCodeInstanceName() + "->body, &" + self.getCodeInstanceName() + "_encOffset);" )
+            code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[" + str(subvidx) + "], &" + self.getCodeInstanceName() + "->content.encoded.body, &" + self.getCodeInstanceName() + "_encOffset);" )
         else:
-          code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[0], &" + self.getCodeInstanceName() + "->body, &" + self.getCodeInstanceName() + "_encOffset);" )
+          code.append("UA_" + subv.stringRepresentation + "_encodeBinary(&" + self.getCodeInstanceName()+"_struct."+subv.alias() + "[0], &" + self.getCodeInstanceName() + "->content.encoded.body, &" + self.getCodeInstanceName() + "_encOffset);" )
 
     # Reallocate the memory by swapping the 65k Bytestring for a new one
-    code.append(self.getCodeInstanceName() + "->body.length = " + self.getCodeInstanceName() + "_encOffset;");
+    code.append(self.getCodeInstanceName() + "->content.encoded.body.length = " + self.getCodeInstanceName() + "_encOffset;");
     code.append("UA_Byte *" + self.getCodeInstanceName() + "_newBody = (UA_Byte *) UA_malloc(" + self.getCodeInstanceName() + "_encOffset );" )
-    code.append("memcpy(" + self.getCodeInstanceName() + "_newBody, " + self.getCodeInstanceName() + "->body.data, " + self.getCodeInstanceName() + "_encOffset);" )
-    code.append("UA_Byte *" + self.getCodeInstanceName() + "_oldBody = " + self.getCodeInstanceName() + "->body.data;");
-    code.append(self.getCodeInstanceName() + "->body.data = " +self.getCodeInstanceName() + "_newBody;")
+    code.append("memcpy(" + self.getCodeInstanceName() + "_newBody, " + self.getCodeInstanceName() + "->content.encoded.body.data, " + self.getCodeInstanceName() + "_encOffset);" )
+    code.append("UA_Byte *" + self.getCodeInstanceName() + "_oldBody = " + self.getCodeInstanceName() + "->content.encoded.body.data;");
+    code.append(self.getCodeInstanceName() + "->content.encoded.body.data = " +self.getCodeInstanceName() + "_newBody;")
     code.append("UA_free(" + self.getCodeInstanceName() + "_oldBody);")
     code.append("")
     return code

+ 3 - 0
tools/pyUANamespace/ua_namespace.py

@@ -640,6 +640,9 @@ class opcua_namespace():
     header.append('#include "server/ua_nodes.h"')
     header.append('#include "ua_util.h"')
     header.append('#include "ua_types.h"')
+    header.append('#include "ua_types_encoding_binary.h"')
+    header.append('#include "ua_types_generated_encoding_binary.h"')
+    header.append('#include "ua_transport_generated_encoding_binary.h"')
     header.append('#else')
     header.append('#include "open62541.h"')
     header.append('#define NULL ((void *)0)')

+ 4 - 2
tools/pyUANamespace/ua_node_types.py

@@ -1069,7 +1069,8 @@ class opcua_node_variable_t(opcua_node_t):
         if self.value() != None:
           code = code + self.value().printOpen62541CCode(bootstrapping)
           return code
-    code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
+    if(bootstrapping):
+      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
     return code
   
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
@@ -1323,7 +1324,8 @@ class opcua_node_variableType_t(opcua_node_t):
         if self.value() != None:
           code = code + self.value().printOpen62541CCode(bootstrapping)
           return code
-    code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
+    if(bootstrapping):
+      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
     return code
   
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):

+ 1 - 2
tools/travis_linux_before_install.sh

@@ -4,7 +4,7 @@ sudo apt-get update
 sudo apt-get install binutils-mingw-w64-i686 gcc-mingw-w64-i686 mingw-w64
 sudo add-apt-repository ppa:kalakris/cmake -y
 sudo apt-get update -qq
-sudo apt-get install -qq --no-install-recommends build-essential cmake python-lxml gcc-multilib graphviz doxygen wget zip
+sudo apt-get install -qq --no-install-recommends build-essential cmake python-lxml gcc-multilib wget zip
 sudo apt-get install libsubunit-dev #for check_0.10.0
 wget http://ftp.de.debian.org/debian/pool/main/c/check/check_0.10.0-3_amd64.deb
 sudo dpkg -i check_0.10.0-3_amd64.deb
@@ -14,5 +14,4 @@ sudo dpkg -i liburcu2_0.8.5-1ubuntu1_amd64.deb
 sudo dpkg -i liburcu-dev_0.8.5-1ubuntu1_amd64.deb
 sudo pip install cpp-coveralls
 sudo pip install sphinx
-sudo pip install breathe
 sudo pip install sphinx_rtd_theme

+ 44 - 40
tools/travis_linux_script.sh

@@ -1,72 +1,76 @@
 #!/bin/bash
 set -ev
-echo "Checking the applicability of patches"
-# ./tools/.checkPorts.sh
+
 echo "Documentation and certificate build"
 mkdir -p build
 cd build
-cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_DOCUMENTATION=ON -DGENERATE_SELFSIGNED=ON ..
+cmake -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_EXAMPLES=ON -DUA_BUILD_DOCUMENTATION=ON -DUA_BUILD_SELFSIGNED_CERTIFICATE=ON ..
 make doc
 make selfsigned
-cp -r doc ..
-cp server_cert.der ..
-echo "Testing builds"
-cd .. && rm build -rf && mkdir -p build && cd build
+cp -r doc ../../
+cp server_cert.der ../../
+cd .. && rm build -rf 
+
 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 ..
+mkdir -p build && cd build
+cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw32.cmake -DUA_ENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_EXAMPLES=ON ..
 make
-cp ../README.md .
-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
+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 ..
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
+
 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 ..
+mkdir -p build && cd build
+cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-mingw64.cmake -DUA_ENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_EXAMPLES=ON ..
 make
-cp ../README.md .
-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
+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 ..
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
+
 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 ..
+mkdir -p build && cd build
+cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-gcc-m32.cmake -DUA_ENABLE_AMALGAMATION=ON -DCMAKE_BUILD_TYPE=Release -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON ..
 make
-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
+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 ..
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
+
 echo "Compile release build for 64-bit linux"
-cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_AMALGAMATION=ON -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
+mkdir -p build && cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DUA_ENABLE_AMALGAMATION=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON ..
 make
-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
+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.h .. #copy single file-release
-cp open62541.c .. #copy single file-release
+cp open62541.h ../../ #copy single file-release
+cp open62541.c ../../ #copy single file-release
+cd .. && rm build -rf 
+
 echo "Upgrade to gcc 4.8"
 sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
 sudo apt-get update -qq
 sudo apt-get install -qq gcc-4.8 g++-4.8 valgrind
 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20
 sudo update-alternatives --config gcc
+
 echo "Building the C++ example"
+mkdir -p build && cd build
+cp ../../open62541.* .
 gcc -std=c99 -c open62541.c
-g++-4.8 ../examples/server.cpp -I./ open62541.o -o cpp-server
-cd .. && rm build -rf && mkdir -p build && cd build
+g++-4.8 ../examples/server.cpp -I./ open62541.o -lrt -o cpp-server
+cd .. && rm build -rf 
+
 echo "Compile multithreaded version"
-cmake -DENABLE_MULTITHREADING=ON -DBUILD_EXAMPLESERVER=ON ..
+mkdir -p build && cd build
+cmake -DUA_ENABLE_MULTITHREADING=ON -DUA_BUILD_EXAMPLESERVER=ON ..
 make
-cd .. && rm build -rf && mkdir -p build && cd build
+cd .. && rm build -rf 
+
+#this run inclides full examples and methodcalls
 echo "Debug build and unit tests (64 bit)"
-cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEMO_NODESET=ON -DBUILD_UNIT_TESTS=ON -DBUILD_EXAMPLESERVER=ON -DENABLE_COVERAGE=ON ..
+mkdir -p build && cd build
+cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_METHODCALLS=ON -DUA_BUILD_DEMO_NODESET=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_ENABLE_COVERAGE=ON ..
 make && make test ARGS="-V"
 echo "Run valgrind to see if the server leaks memory (just starting up and closing..)"
-if [[ ! ( ${TRAVIS_OS_NAME} == "linux" && ${CC} == "clang") ]]; then
-  (valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
-  (coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../ ; exit 0);
-fi
-cd ..
+(valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
+coveralls --gcov /usr/bin/gcov-4.8 -E '.*\.h' -E '.*CMakeCXXCompilerId\.cpp' -E '.*CMakeCCompilerId\.c' -r ../
+cd .. && rm build -rf

+ 1 - 3
tools/travis_osx_before_install.sh

@@ -4,11 +4,9 @@ brew install cmake
 brew install check
 brew install libxml2
 brew install userspace-rcu
-brew install graphviz
-brew install doxygen
-brew install swig
 brew install --HEAD valgrind
 
 sudo pip install lxml
 sudo pip install sphinx
 sudo pip install breathe
+sudo pip install sphinx_rtd_theme

+ 12 - 16
tools/travis_osx_script.sh

@@ -1,30 +1,26 @@
 #!/bin/bash
 set -ev
-echo "Documentation and certificate build"
-mkdir -p build
-cd build
-cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_DOCUMENTATION=ON -DGENERATE_SELFSIGNED=ON ..
-make doc
-make selfsigned
-cp -r doc ..
-cp server_cert.der ..
-echo "Testing builds"
-cd .. && rm -rf build && mkdir -p build && cd build
+
 echo "Compile release build for OS X"
-cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_AMALGAMATION=ON -DBUILD_EXAMPLESERVER=ON -DBUILD_EXAMPLECLIENT=ON ..
+mkdir -p build && cd build
+cmake -DCMAKE_BUILD_TYPE=Release -DUA_ENABLE_AMALGAMATION=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_BUILD_EXAMPLECLIENT=ON -DUA_BUILD_DOCUMENTATION=ON -DUA_GENERATE_SELFSIGNED=ON ..
 make
 tar -pczf open62541-osx.tar.gz ../doc ../server_cert.der ../LICENSE ../AUTHORS ../README.md server_static server client_static client libopen62541.dylib open62541.h open62541.c
 cp open62541-osx.tar.gz ..
 cp open62541.h .. #copy single file-release
 cp open62541.c .. #copy single file-release
-cd .. && rm -rf build && mkdir -p build && cd build
+cd .. && rm -rf build
+
 echo "Compile multithreaded version"
-cmake -DENABLE_MULTITHREADING=ON -DBUILD_EXAMPLESERVER=ON ..
+mkdir -p build && cd build
+cmake -DUA_ENABLE_MULTITHREADING=ON -DUA_BUILD_EXAMPLESERVER=ON ..
 make
-cd .. && rm -rf build && mkdir -p build && cd build
+cd .. && rm -rf build
+
 echo "Debug build and unit tests (64 bit)"
-cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_DEMO_NODESET=ON -DBUILD_UNIT_TESTS=ON -DBUILD_EXAMPLESERVER=ON -DENABLE_COVERAGE=ON ..
+mkdir -p build && cd build
+cmake -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_DEMO_NODESET=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_BUILD_EXAMPLESERVER=ON -DUA_ENABLE_COVERAGE=ON ..
 make && make test
 echo "Run valgrind to see if the server leaks memory (just starting up and closing..)"
 (valgrind --error-exitcode=3 ./server & export pid=$!; sleep 2; kill -INT $pid; wait $pid);
-cd ..
+cd .. && rm -rf build

+ 0 - 0
tools/.coverity.sh


+ 14 - 0
tools/travis_push_doc.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+git clone --depth=5 -b gh-pages https://$GITAUTH@github.com/open62541/open62541-www
+cd open62541-www
+
+git rm -r -f ./doc/current/*
+cp -r ../../doc/* ./doc/current/
+git add -A ./doc/current
+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 "updated generated documentation on webpage by travis-ci [ci skip]"
+git push https://$GITAUTH@github.com/open62541/open62541-www
+cd .. && rm -rf open62541-www

+ 49 - 0
tools/travis_push_release.sh

@@ -0,0 +1,49 @@
+#!/bin/bash
+
+TAGSTOSAVE=50
+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 clone --depth=5 -b gh-pages https://$GITAUTH@github.com/open62541/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 ..
+
+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 "added release files and updated releases webpage by travis-ci [ci skip]"
+git push https://$GITAUTH@github.com/open62541/open62541-www
+cd ..
+rm -rf open62541-www