Browse Source

Merge branch 'master' into add-code-of-conduct-1

Stefan Profanter 7 years ago
parent
commit
4ea40d346f
100 changed files with 8591 additions and 3250 deletions
  1. 2 0
      .gitignore
  2. 6 0
      .gitmodules
  3. 24 0
      .travis-apt-pin.preferences
  4. 72 45
      .travis.yml
  5. 2 0
      AUTHORS
  6. 102 10
      CHANGELOG
  7. 338 124
      CMakeLists.txt
  8. 3 2
      Dockerfile
  9. 0 1
      LICENSE
  10. 13 15
      README.md
  11. 1 1
      TinyDockerfile
  12. 90 20
      appveyor.yml
  13. 0 34
      deps/libc_string.c
  14. 4 6
      deps/libc_time.c
  15. 15 3
      deps/libc_time.h
  16. 1 0
      deps/mdnsd
  17. 2 0
      deps/ms_stdint.h
  18. 10 9
      deps/pcg_basic.h
  19. 1 0
      deps/ua-nodeset
  20. 13 12
      doc/CMakeLists.txt
  21. 60 21
      doc/building.rst
  22. 15 10
      doc/index.rst
  23. 3 3
      doc/internal.rst
  24. 4 5
      doc/namespace_compiler.rst
  25. 1 1
      doc/toc.rst
  26. 63 65
      examples/CMakeLists.txt
  27. 67 0
      examples/access_control/client_access_control.c
  28. 65 0
      examples/access_control/server_access_control.c
  29. 21 35
      examples/client.c
  30. 95 0
      examples/client_connect_loop.c
  31. 41 0
      examples/custom_datatype/client_types_custom.c
  32. 51 0
      examples/custom_datatype/custom_datatype.h
  33. 86 0
      examples/custom_datatype/server_types_custom.c
  34. 186 0
      examples/discovery/client_find_servers.c
  35. 46 0
      examples/discovery/server_lds.c
  36. 187 0
      examples/discovery/server_multicast.c
  37. 131 0
      examples/discovery/server_register.c
  38. 124 0
      examples/nodeset/CMakeLists.txt
  39. 37 0
      examples/nodeset/server_nodeset.c
  40. 26 11
      examples/server_nodeset.xml
  41. 52 0
      examples/nodeset/server_nodeset_plcopen.c
  42. 77 90
      examples/server.c
  43. 7 18
      examples/server.cpp
  44. 9 23
      examples/server_certificate.c
  45. 71 75
      examples/server_inheritance.c
  46. 27 39
      examples/server_instantiation.c
  47. 13 22
      examples/server_mainloop.c
  48. 0 53
      examples/server_nodeset.c
  49. 7 21
      examples/server_repeated_job.c
  50. 3 15
      examples/server_udp.c
  51. 131 0
      examples/tutorial_client_events.c
  52. 1 2
      examples/tutorial_client_firststeps.c
  53. 2 2
      examples/tutorial_datatypes.c
  54. 28 26
      examples/tutorial_server_datasource.c
  55. 4 9
      examples/tutorial_server_firststeps.c
  56. 29 28
      examples/tutorial_server_method.c
  57. 44 60
      examples/tutorial_server_object.c
  58. 11 12
      examples/tutorial_server_variable.c
  59. 14 19
      examples/tutorial_server_variabletype.c
  60. 15 0
      include/open62541.pc.in
  61. 129 50
      include/ua_client.h
  62. 39 7
      include/ua_client_highlevel.h
  63. 87 82
      include/ua_config.h.in
  64. 0 137
      include/ua_connection.h
  65. 1339 33
      include/ua_constants.h
  66. 0 47
      include/ua_job.h
  67. 0 136
      include/ua_log.h
  68. 74 0
      include/ua_plugin_access_control.h
  69. 121 0
      include/ua_plugin_log.h
  70. 223 0
      include/ua_plugin_network.h
  71. 142 22
      src/server/ua_nodes.h
  72. 309 0
      include/ua_plugin_securitypolicy.h
  73. 428 274
      include/ua_server.h
  74. 104 0
      include/ua_server_config.h
  75. 57 33
      include/ua_types.h
  76. 13 4
      open62541.spec
  77. 141 0
      plugins/ua_accesscontrol_default.c
  78. 58 0
      plugins/ua_accesscontrol_default.h
  79. 24 2
      plugins/ua_clock.c
  80. 311 0
      plugins/ua_config_default.c
  81. 59 0
      plugins/ua_config_default.h
  82. 0 130
      plugins/ua_config_standard.c
  83. 0 22
      plugins/ua_config_standard.h
  84. 36 0
      plugins/ua_debug_dump_pkgs.c
  85. 6 13
      plugins/ua_log_stdout.c
  86. 2 3
      plugins/ua_log_stdout.h
  87. 517 438
      plugins/ua_network_tcp.c
  88. 1 1
      plugins/ua_network_tcp.h
  89. 20 15
      plugins/ua_network_udp.c
  90. 468 0
      plugins/ua_nodestore_default.c
  91. 21 0
      plugins/ua_nodestore_default.h
  92. 163 0
      plugins/ua_securitypolicy_none.c
  93. 22 0
      plugins/ua_securitypolicy_none.h
  94. 230 716
      src/client/ua_client.c
  95. 499 0
      src/client/ua_client_connect.c
  96. 133 0
      src/client/ua_client_discovery.c
  97. 74 75
      src/client/ua_client_highlevel.c
  98. 153 56
      src/client/ua_client_highlevel_subscriptions.c
  99. 35 7
      src/client/ua_client_internal.h
  100. 0 0
      src/server/ua_mdns.c

+ 2 - 0
.gitignore

@@ -77,3 +77,5 @@ Makefile
 /exampleClient_legacy
 /exampleClient_legacy
 /src_generated/
 /src_generated/
 /build
 /build
+/.idea
+/cmake-build*

+ 6 - 0
.gitmodules

@@ -0,0 +1,6 @@
+[submodule "deps/mdnsd"]
+	path = deps/mdnsd
+	url = https://github.com/Pro/mdnsd.git
+[submodule "deps/ua-nodeset"]
+	path = deps/ua-nodeset
+	url = https://github.com/OPCFoundation/UA-Nodeset.git

+ 24 - 0
.travis-apt-pin.preferences

@@ -0,0 +1,24 @@
+Package: clang-3.9
+Pin: release o=Ubuntu
+Pin-Priority: -1
+
+Package: libclang-common-3.9-dev
+Pin: release o=Ubuntu
+Pin-Priority: -1
+
+Package: libclang1-3.9
+Pin: release o=Ubuntu
+Pin-Priority: -1
+
+Package: libllvm3.9v4
+Pin: release o=Ubuntu
+Pin-Priority: -1
+
+Package: clang-tidy-3.9
+Pin: release o=Ubuntu
+Pin-Priority: -1
+
+Package: libfuzzer-3.9-dev
+Pin: release o=Ubuntu
+Pin-Priority: -1
+

+ 72 - 45
.travis.yml

@@ -1,15 +1,6 @@
 language: c
 language: c
 
 
-compiler:
-- gcc
-- clang
-
-os:
-- linux
-- osx
-
 # use new build environment (docker)
 # use new build environment (docker)
-dist: trusty
 sudo: required
 sudo: required
 
 
 env:
 env:
@@ -18,28 +9,49 @@ env:
     - secure: nSunY54Wp5HkQCHHbKwlwpbaKyqRVIu/0EnhaoJSwhM1wqerQV/E5d/2JelO9/tZgbungAO7wk/fjutRMVc7d378RTIPwS8vHpvZfEoGhCFsLoTOlqESzsZFBup2H5t1lpQ23jRHDOxlLdJy2lz5U+zd1YnYgDXqdDFjegsIYdo=
     - secure: nSunY54Wp5HkQCHHbKwlwpbaKyqRVIu/0EnhaoJSwhM1wqerQV/E5d/2JelO9/tZgbungAO7wk/fjutRMVc7d378RTIPwS8vHpvZfEoGhCFsLoTOlqESzsZFBup2H5t1lpQ23jRHDOxlLdJy2lz5U+zd1YnYgDXqdDFjegsIYdo=
     # COVERITY_SCAN_TOKEN:
     # COVERITY_SCAN_TOKEN:
     - secure: C7LLWmOCdRYJGiXjFYDHWwBB6XGjs9Hio4kkvDehLRredRgp1UJ73g6Av9L7xrTUide6GiPrSd+RJw7py/twx5qaeIjOWPy+XvtmabDEQBquLjEkvS+LP2EycaMe92kHMo1ItFfRomgj1FyNYPVnUFgdyedGWv+p553ziDbrMas=
     - secure: C7LLWmOCdRYJGiXjFYDHWwBB6XGjs9Hio4kkvDehLRredRgp1UJ73g6Av9L7xrTUide6GiPrSd+RJw7py/twx5qaeIjOWPy+XvtmabDEQBquLjEkvS+LP2EycaMe92kHMo1ItFfRomgj1FyNYPVnUFgdyedGWv+p553ziDbrMas=
-  matrix:
-    # Do both, compile with static code analysis and without
-    - ANALYZE=false
-    - ANALYZE=true
-    - DOCKER=true
+
+
+dist: trusty
 
 
 matrix:
 matrix:
-  exclude:
-  # This excludes OSX GCC builds.
-    - os: osx
+  fast_finish: true
+  include:
+    - os: linux
+      compiler: gcc
+      env:
+        - ANALYZE=false
+        - PYTHON=python2
+    - os: linux
       compiler: gcc
       compiler: gcc
-    - os: osx
       env: ANALYZE=true
       env: ANALYZE=true
-    - os: osx
+    - os: linux
+      compiler: gcc
       env: DOCKER=true
       env: DOCKER=true
+      services:
+        - docker
     - os: linux
     - os: linux
       compiler: clang
       compiler: clang
-      env: DOCKER=true
-
-# Required for docker build test
-services:
-  - docker
+      env:
+        - ANALYZE=false
+        - PYTHON=python2
+    - os: linux
+      compiler: clang
+      env:
+        - ANALYZE=false
+        - PYTHON=python3
+    - os: linux
+      compiler: clang
+      env: ANALYZE=true
+    - os: linux
+      compiler: clang
+      env: FUZZER=true
+    - os: osx
+      compiler: clang
+      # disable homebrew auto update which takes a lot of time
+      env: HOMEBREW_NO_AUTO_UPDATE=1
+      cache:
+        directories:
+          - $HOME/Library/Caches/Homebrew
 
 
 addons:
 addons:
   apt:
   apt:
@@ -48,25 +60,26 @@ addons:
     packages:
     packages:
       - binutils-mingw-w64-i686
       - binutils-mingw-w64-i686
       - build-essential
       - build-essential
-      - cmake
-      - gcc-multilib
-      - g++-multilib
-      - valgrind
       - check
       - check
+      - cmake
       - cppcheck
       - cppcheck
-      - mingw-w64
-      - g++-mingw-w64-x86-64
+      - gcc-multilib
       - g++-mingw-w64-i686
       - g++-mingw-w64-i686
-      - libc6-dbg # for valgrind compilation
+      - g++-mingw-w64-x86-64
+      - g++-multilib
+      - graphviz
       - libsubunit-dev
       - libsubunit-dev
       - libx11-dev
       - libx11-dev
+      - mingw-w64
+      - python-six
+      - python3-six
+      - texlive-fonts-recommended
+      - texlive-latex-extra
+      - texlive-latex-recommended
+      - valgrind
       - wget
       - wget
       - xutils-dev
       - xutils-dev
       - zip
       - zip
-      - graphviz
-      - texlive-latex-recommended
-      - texlive-latex-extra
-      - texlive-fonts-recommended
   coverity_scan:
   coverity_scan:
     project:
     project:
       name: "open62541/open62541"
       name: "open62541/open62541"
@@ -81,18 +94,32 @@ cache:
   apt: true
   apt: true
   directories:
   directories:
     - $HOME/install
     - $HOME/install
+    - $HOME/.cache/pip
+
+# combine all the commands into one single command. See https://github.com/travis-ci/travis-ci/issues/1066
+before_install: |
+ set -e
+ # Exit travis if on coverity_scan branch and not first build
+ test $TRAVIS_BRANCH != coverity_scan -o ${TRAVIS_JOB_NUMBER##*.} = 1 || exit 0
+ if [ ${TRAVIS_OS_NAME} == "linux" ]; then echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-; fi
+ if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis/travis_linux_before_install.sh; fi
+ if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis/travis_osx_before_install.sh; fi
 
 
-before_install:
-- if [ ${TRAVIS_OS_NAME} == "linux" ] && [ "${COVERITY_SCAN_BRANCH}" = 1 ]; then echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-; fi
-- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis/travis_linux_before_install.sh; fi
-- if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis/travis_osx_before_install.sh; fi
+script: |
+ set -e
+ if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis/travis_linux_script.sh; fi
+ if [ ${TRAVIS_OS_NAME} == "osx" ]; then sh ./tools/travis/travis_osx_script.sh; fi
 
 
-script:
-- if [ ${TRAVIS_OS_NAME} == "linux" ] && [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then sh ./tools/travis/travis_linux_script.sh; fi
-- if [ ${TRAVIS_OS_NAME} == "osx" ] && [ "${COVERITY_SCAN_BRANCH}" != 1 ]; then sh ./tools/travis/travis_osx_script.sh; fi
+after_success: |
+ if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis/travis_linux_after_success.sh; fi
+ # Sleep to flush travis output
+ echo == Build success ==
+ sleep 5
 
 
-after_success:
-- if [ ${TRAVIS_OS_NAME} == "linux" ]; then sh ./tools/travis/travis_linux_after_success.sh; fi
+after_failure: |
+ # Sleep to flush travis output
+ echo == Build failed ==
+ sleep 5
 
 
 deploy:
 deploy:
   provider: releases
   provider: releases
@@ -110,4 +137,4 @@ deploy:
   on:
   on:
     repo: open62541/open62541
     repo: open62541/open62541
     tags: true
     tags: true
-    condition: $CC = gcc && $ANALYZE = false
+    condition: $CC = gcc && $ANALYZE = false

+ 2 - 0
AUTHORS

@@ -1,10 +1,12 @@
 The authors of open62541 are (in alphabetical order)
 The authors of open62541 are (in alphabetical order)
 
 
 Bauer, Maximilian
 Bauer, Maximilian
+Ebrahimi, Reza <reza.ebrahimi.dev (at) gmail.com>
 Graube, Markus <markus.graube (at) tu-dresden.de>
 Graube, Markus <markus.graube (at) tu-dresden.de>
 Gruener, Sten <s.gruener (at) plt.rwth-aachen.de>
 Gruener, Sten <s.gruener (at) plt.rwth-aachen.de>
 Iatrou, Chris Paul <chris_paul.iatrou (at) tu-dresden.de>
 Iatrou, Chris Paul <chris_paul.iatrou (at) tu-dresden.de>
 Jeromin, Holger
 Jeromin, Holger
 Palm, Florian <f.palm (at) plt.rwth-aachen.de>
 Palm, Florian <f.palm (at) plt.rwth-aachen.de>
 Pfrommer, Julius <julius.pfrommer (at) kit.edu>
 Pfrommer, Julius <julius.pfrommer (at) kit.edu>
+Profanter, Stefan <profanter (at) fortiss.org>
 Urbas, Leon <leon.urbas (at) tu-dresden.de>
 Urbas, Leon <leon.urbas (at) tu-dresden.de>

+ 102 - 10
CHANGELOG

@@ -1,21 +1,113 @@
-The changelog tracks changes to the public API.
-Internal refactorings and bug fixes are not reported here.
+This changelog reports changes to the public API. Internal refactorings and bug
+fixes are not reported here.
+
+2017-09-07 jpfr <julius.pfrommer at web.de>
+
+ * Make Client Highlevel Interface consistent
+
+   Two methods in the client highlevel interface were not conformant with the
+   API convention that array sizes are given before the array pointer. This
+   changes the signature of UA_Client_writeArrayDimensionsAttribute and
+   UA_Client_readArrayDimensionsAttribute.
+
+   The API changes are detected by the type-matching in the compiler. So there
+   is little risk for bugs due to unaligned implementations.
+
+2017-08-16 jpfr <julius.pfrommer at web.de>
+
+ * Default Attribute Values for Node Attributes
+
+   The AddNodes service takes a structure with the attributes of the new node as
+   input. We began checking the consistency of the attributes more closely. You
+   can now use constant global definitions with default values as a starting
+   point. For example UA_VariableAttributes_default for adding a variable node.
+
+ * All nodes have a context pointer
+
+   All nodes now carry a context pointer. The context pointer is initially set
+   to a user-defined memory location. The context pointer is passed to all
+   user-visible callbacks involving the node.
+
+ * Global and node-type constructor/destructor
+
+   The constructors are fine-grained mechanisms to control the instantiation and
+   deletion of nodes. Constructors receive the node context pointer and can also
+   replace it.
+
+2017-08-13 Infinity95 <mark.giraud at student.kit.edu>
+
+ * New/Delete methods for the server configuration
+
+   The default server configuration is no longer a constant global variable.
+   Instead, it is now handled with a pair of new/delete methods. This enables
+   the use of malloced members of the server configuration. With this change,
+   the endpoint descriptions are no longer generated in the server but are
+   created as part of the server configuration. See the example server
+   implementations on how to use the configuration generation. The change is a
+   precursor to the encryption implementation that ties into the generation of
+   endpoint descriptions in the server config.
+
+   The generation of the default server configuration is implemented as a
+   "plugin". So it comes with CC0 licensing and can be freely adjusted by users.
+
+   The TCP port in the default configuration is 4840. This is the recommended
+   port for OPC UA and now used throughout all examples.
 
 
 2017-07-04 jpfr <julius.pfrommer at web.de>
 2017-07-04 jpfr <julius.pfrommer at web.de>
 
 
-    * Return partially overlapping ranges
+ * Return partially overlapping ranges
+
+   Test the integrity of the range and compute the max index used for every
+   dimension. The standard says in Part 4, Section 7.22:
+
+   When reading a value, the indexes may not speify a range that is within
+   the bounds of the array. The Server shall return a partial result if some
+   elements exist within the range.
+
+2017-07-03 jpfr <julius.pfrommer at web.de>
+
+ * Implement asynchronous service calls for the client
+
+   All OPC UA services are asynchronous in nature. So several service calls can
+   be made without waiting for a response first. Responess may come in a
+   different ordering. The client takes a method pointer and a data pointer to
+   perform an asynchronous callback on the request response.
+
+   Synchronous service calls are still supported in the client. Asynchronous
+   responses are processed in the background until the synchronous response (the
+   client is waiting for) returns the control flow back to the user.
+
+2017-06-26 janitza-thbe
 
 
-      Test the integrity of the range and compute the max index used for every
-      dimension. The standard says in Part 4, Section 7.22:
+ * Enable IPv6 in the networklayer plugin
 
 
-      When reading a value, the indexes may not speify a range that is within
-      the bounds of the array. The Server shall return a partial result if some
-      elements exist within the range.
+   The server networklayer listens on several sockets for available networks and
+   IP versions. IPv4 connections are still supported.
+
+   The OPC Foundation ANSI C Stack before 2016 does not fully support IPv6. On
+   Windows, the 'localhost' target is resolved to IPv6 by default. Old
+   applications (e.g. the Conformance Testing Tools) need to connect to
+   127.0.0.1 instead of 'localhost' to force IPv4.
+
+2017-06-16 jpfr <julius.pfrommer at web.de>
+
+ * Require the AccessLevel bit UA_ACCESSLEVELMASK_READ for reading
+
+   Set the bit by default when adding nodes for a smooth transition to the new
+   API. This will change at a later point with an additional node settings
+   argument for the AddNodes methods.
 
 
 2017-05-03 pro <profanter at fortiss.org>
 2017-05-03 pro <profanter at fortiss.org>
 
 
-    * Array dimensions are UInt32 also for the highlevel client read service
+ * Array dimensions are UInt32 also for the highlevel client read service
+
+2017-04-16 jpfr <julius.pfrommer at web.de>
+
+ * Refactor UA_parseEndpointUrl to work with UA_String
+
+   The output hostname and path now point into the original endpointUrl with an
+   appropriate length.
 
 
 2017-04-14 jpfr <julius.pfrommer at web.de>
 2017-04-14 jpfr <julius.pfrommer at web.de>
 
 
-    * Auto-instantiate only child nodes marked as mandatory (fixes #1004)
+ * Auto-instantiate only child nodes marked as mandatory (fixes #1004)

+ 338 - 124
CMakeLists.txt

@@ -1,17 +1,28 @@
-cmake_minimum_required(VERSION 2.8.11)
+cmake_minimum_required(VERSION 3.0)
 project(open62541)
 project(open62541)
 # set(CMAKE_VERBOSE_MAKEFILE ON)
 # set(CMAKE_VERBOSE_MAKEFILE ON)
 
 
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/tools/cmake")
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/tools/cmake")
 find_package(PythonInterp REQUIRED)
 find_package(PythonInterp REQUIRED)
 find_package(Git)
 find_package(Git)
+include(AssignSourceGroup)
+
+#############################
+# Compiled binaries folders #
+#############################
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+set(LIB_INSTALL_DIR /usr/lib CACHE PATH "Installation path of libraries")
 
 
 ###########
 ###########
 # Version #
 # Version #
 ###########
 ###########
 
 
 set(OPEN62541_VER_MAJOR 0)
 set(OPEN62541_VER_MAJOR 0)
-set(OPEN62541_VER_MINOR 2)
+set(OPEN62541_VER_MINOR 3)
 set(OPEN62541_VER_PATCH 0)
 set(OPEN62541_VER_PATCH 0)
 set(OPEN62541_VER_LABEL "dev") # Appended to the X.Y.Z version format. For example "-rc1" or an empty string
 set(OPEN62541_VER_LABEL "dev") # Appended to the X.Y.Z version format. For example "-rc1" or an empty string
 
 
@@ -44,10 +55,17 @@ set(UA_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported")
 option(UA_ENABLE_METHODCALLS "Enable the Method service set" ON)
 option(UA_ENABLE_METHODCALLS "Enable the Method service set" ON)
 option(UA_ENABLE_NODEMANAGEMENT "Enable dynamic addition and removal of nodes at runtime" ON)
 option(UA_ENABLE_NODEMANAGEMENT "Enable dynamic addition and removal of nodes at runtime" ON)
 option(UA_ENABLE_SUBSCRIPTIONS "Enable subscriptions support." ON)
 option(UA_ENABLE_SUBSCRIPTIONS "Enable subscriptions support." ON)
+option(UA_ENABLE_DISCOVERY "Enable Discovery Service (LDS)" ON)
+option(UA_ENABLE_DISCOVERY_MULTICAST "Enable Discovery Service with multicast support (LDS-ME)" OFF)
+# Semaphores/file system may not be available on embedded devices. It can be disabled with the following option
+option(UA_ENABLE_DISCOVERY_SEMAPHORE "Enable Discovery Semaphore support" ON)
+mark_as_advanced(UA_ENABLE_DISCOVERY_SEMAPHORE)
 option(UA_ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
 option(UA_ENABLE_AMALGAMATION "Concatenate the library to a single file open62541.h/.c" OFF)
 option(UA_ENABLE_COVERAGE "Enable gcov coverage" OFF)
 option(UA_ENABLE_COVERAGE "Enable gcov coverage" OFF)
 option(BUILD_SHARED_LIBS "Enable building of shared libraries (dll/so)" OFF)
 option(BUILD_SHARED_LIBS "Enable building of shared libraries (dll/so)" OFF)
 
 
+set(UA_VXWORKS_WRS_KERNEL OFF CACHE BOOL "Enable if you want to compile for VxWorks as kernel Module")
+
 if(UA_ENABLE_COVERAGE)
 if(UA_ENABLE_COVERAGE)
   set(CMAKE_BUILD_TYPE DEBUG)
   set(CMAKE_BUILD_TYPE DEBUG)
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
@@ -55,6 +73,11 @@ if(UA_ENABLE_COVERAGE)
   set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
   set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
 endif()
 endif()
 
 
+if(UA_ENABLE_DISCOVERY_MULTICAST AND NOT UA_ENABLE_DISCOVERY)
+    MESSAGE(WARNING "UA_ENABLE_DISCOVERY_MULTICAST is enabled, but not UA_ENABLE_DISCOVERY. UA_ENABLE_DISCOVERY_MULTICAST will be set to OFF")
+    SET(UA_ENABLE_DISCOVERY_MULTICAST OFF CACHE BOOL "Enable Discovery Service with multicast support (LDS-ME)" FORCE)
+endif()
+
 # Advanced options
 # Advanced options
 option(UA_ENABLE_MULTITHREADING "Enable multithreading (experimental)" OFF)
 option(UA_ENABLE_MULTITHREADING "Enable multithreading (experimental)" OFF)
 mark_as_advanced(UA_ENABLE_MULTITHREADING)
 mark_as_advanced(UA_ENABLE_MULTITHREADING)
@@ -65,31 +88,43 @@ mark_as_advanced(UA_ENABLE_STATUSCODE_DESCRIPTIONS)
 option(UA_ENABLE_TYPENAMES "Add the type and member names to the UA_DataType structure" ON)
 option(UA_ENABLE_TYPENAMES "Add the type and member names to the UA_DataType structure" ON)
 mark_as_advanced(UA_ENABLE_TYPENAMES)
 mark_as_advanced(UA_ENABLE_TYPENAMES)
 
 
-option(UA_ENABLE_EMBEDDED_LIBC "Use a custom implementation of some libc functions that might be missing on embedded targets (e.g. string handling)." OFF)
-mark_as_advanced(UA_ENABLE_EMBEDDED_LIBC)
-
 option(UA_ENABLE_DETERMINISTIC_RNG "Do not seed the random number generator (e.g. for unit tests)." OFF)
 option(UA_ENABLE_DETERMINISTIC_RNG "Do not seed the random number generator (e.g. for unit tests)." OFF)
 mark_as_advanced(UA_ENABLE_DETERMINISTIC_RNG)
 mark_as_advanced(UA_ENABLE_DETERMINISTIC_RNG)
 
 
-option(UA_ENABLE_GENERATE_NAMESPACE0 "Generate and load UA XML Namespace 0 definition (experimental)" OFF)
-mark_as_advanced(UA_ENABLE_GENERATE_NAMESPACE0)
+option(UA_ENABLE_FULL_NS0 "Use the full NS0 instead of a minimal Namespace 0 nodeset" OFF)
 
 
 option(UA_ENABLE_VALGRIND_UNIT_TESTS "Use Valgrind to detect memory leaks when running the unit tests" OFF)
 option(UA_ENABLE_VALGRIND_UNIT_TESTS "Use Valgrind to detect memory leaks when running the unit tests" OFF)
 mark_as_advanced(UA_ENABLE_VALGRIND_UNIT_TESTS)
 mark_as_advanced(UA_ENABLE_VALGRIND_UNIT_TESTS)
 
 
-option(UA_ENABLE_NONSTANDARD_STATELESS "Enable stateless extension (non-standard)" OFF)
-mark_as_advanced(UA_ENABLE_NONSTANDARD_STATELESS)
-
 option(UA_ENABLE_NONSTANDARD_UDP "Enable udp extension (non-standard)" OFF)
 option(UA_ENABLE_NONSTANDARD_UDP "Enable udp extension (non-standard)" OFF)
 mark_as_advanced(UA_ENABLE_NONSTANDARD_UDP)
 mark_as_advanced(UA_ENABLE_NONSTANDARD_UDP)
-if(UA_ENABLE_NONSTANDARD_UDP)
-  set(UA_ENABLE_NONSTANDARD_STATELESS ON)
+
+option(UA_ENABLE_UNIT_TEST_FAILURE_HOOKS
+       "Add hooks to force failure modes for additional unit tests. Not for production use!" OFF)
+mark_as_advanced(UA_ENABLE_UNIT_TEST_FAILURE_HOOKS)
+
+# Build options for debugging
+option(UA_DEBUG "Enable assertions and additional functionality that should not be included in release builds" OFF)
+mark_as_advanced(UA_DEBUG)
+if(CMAKE_BUILD_TYPE STREQUAL "Debug")
+    set(UA_DEBUG ON)
 endif()
 endif()
 
 
+option(UA_DEBUG_DUMP_PKGS "Dump every package received by the server as hexdump format" OFF)
+mark_as_advanced(UA_DEBUG_DUMP_PKGS)
+
 # Build Targets
 # Build Targets
 option(UA_BUILD_EXAMPLES "Build example servers and clients" OFF)
 option(UA_BUILD_EXAMPLES "Build example servers and clients" OFF)
 option(UA_BUILD_UNIT_TESTS "Build the unit tests" OFF)
 option(UA_BUILD_UNIT_TESTS "Build the unit tests" OFF)
-option(UA_BUILD_EXAMPLES_NODESET_COMPILER "Generate an OPC UA information model from a nodeset XML (experimental)" OFF)
+option(UA_BUILD_FUZZING "Build the fuzzing executables" OFF)
+mark_as_advanced(UA_BUILD_FUZZING)
+if(UA_BUILD_FUZZING)
+    # oss-fuzz already defines this by default
+    add_definitions(-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
+endif()
+
+option(UA_BUILD_OSS_FUZZ "Special build switch used in oss-fuzz" OFF)
+mark_as_advanced(UA_BUILD_OSS_FUZZ)
 
 
 # Advanced Build Targets
 # Advanced Build Targets
 option(UA_BUILD_SELFSIGNED_CERTIFICATE "Generate self-signed certificate" OFF)
 option(UA_BUILD_SELFSIGNED_CERTIFICATE "Generate self-signed certificate" OFF)
@@ -99,11 +134,18 @@ mark_as_advanced(UA_BUILD_SELFSIGNED_CERTIFICATE)
 set(UA_DYNAMIC_LINKING OFF)
 set(UA_DYNAMIC_LINKING OFF)
 if(BUILD_SHARED_LIBS)
 if(BUILD_SHARED_LIBS)
   set(UA_DYNAMIC_LINKING ON)
   set(UA_DYNAMIC_LINKING ON)
+  if (UA_ENABLE_DISCOVERY_MULTICAST)
+      set(MDNSD_DYNAMIC_LINKING ON)
+  endif()
 endif()
 endif()
 
 
 # Force compilation with as C++
 # Force compilation with as C++
 option(UA_COMPILE_AS_CXX "Force compilation with a C++ compiler" OFF)
 option(UA_COMPILE_AS_CXX "Force compilation with a C++ compiler" OFF)
 mark_as_advanced(UA_COMPILE_AS_CXX)
 mark_as_advanced(UA_COMPILE_AS_CXX)
+if (UA_COMPILE_AS_CXX)
+    # We need the UINT32_C define
+    add_definitions(-D__STDC_CONSTANT_MACROS)
+endif()
 
 
 #####################
 #####################
 # Compiler Settings #
 # Compiler Settings #
@@ -112,27 +154,57 @@ mark_as_advanced(UA_COMPILE_AS_CXX)
 # Collect libraries
 # Collect libraries
 list(APPEND open62541_LIBRARIES "")
 list(APPEND open62541_LIBRARIES "")
 if(NOT WIN32)
 if(NOT WIN32)
-  list(APPEND open62541_LIBRARIES pthread)
-  if(NOT APPLE AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
-    list(APPEND open62541_LIBRARIES rt)
+  if(QNXNTO)
+    list(APPEND open62541_LIBRARIES socket)
+    list(APPEND open62541_LIBRARIES c)
+    list(APPEND open62541_LIBRARIES stdc++)
+  else()
+    list(APPEND open62541_LIBRARIES pthread m)
+    if(NOT APPLE AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
+      list(APPEND open62541_LIBRARIES rt)
+    endif()
   endif()
   endif()
 else()
 else()
   list(APPEND open62541_LIBRARIES ws2_32)
   list(APPEND open62541_LIBRARIES ws2_32)
+    if(UA_ENABLE_DISCOVERY_MULTICAST)
+        list(APPEND open62541_LIBRARIES iphlpapi)
+    endif()
 endif()
 endif()
 if(UA_ENABLE_MULTITHREADING)
 if(UA_ENABLE_MULTITHREADING)
-  list(APPEND open62541_LIBRARIES urcu-cds urcu urcu-common)
+  list(APPEND open62541_LIBRARIES urcu-cds urcu-bp urcu-common)
 endif(UA_ENABLE_MULTITHREADING)
 endif(UA_ENABLE_MULTITHREADING)
 
 
-if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
+if(NOT UA_COMPILE_AS_CXX AND (CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang"))
     # Compiler
     # Compiler
-    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 -Wstrict-overflow -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes
-                    -Winit-self -Wformat-security -Wformat-nonliteral)
-    if(NOT WIN32 AND NOT CYGWIN AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
+    add_definitions(-std=c99 -pipe
+                    -Wall -Wextra -Werror -Wpedantic
+                    -Wno-static-in-inline # clang doesn't like the use of static inline methods inside static inline methods
+                    -Wno-overlength-strings # may happen in the nodeset compiler when complex values are directly encoded
+                    -Wno-unused-parameter # some methods may require unused arguments to cast to a method pointer
+                    -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls
+                    -Wformat -Wformat-security -Wformat-nonliteral
+                    -Wuninitialized -Winit-self
+                    -Wcast-qual
+                    -Wstrict-overflow
+                    -Wnested-externs
+                    -Wmultichar
+                    -Wundef
+                    -Wc++-compat)
+
+    if(NOT WIN32 AND NOT CYGWIN AND NOT QNXNTO AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD"))
         add_definitions(-Wshadow -Wconversion -fvisibility=hidden -fPIC)
         add_definitions(-Wshadow -Wconversion -fvisibility=hidden -fPIC)
     endif()
     endif()
 
 
+    if(UA_ENABLE_AMALGAMATION)
+        add_definitions(-Wno-unused-function)
+    endif()
+
+    if(UA_VXWORKS_WRS_KERNEL)
+        # Disable flags for VXWORKS
+        remove_definitions(-Werror -Wpedantic -Wno-static-in-inline -fPIC)
+        add_definitions(-D_WRS_KERNEL)
+    endif()
+
     # Linker
     # Linker
     set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
     set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
 
 
@@ -171,8 +243,14 @@ endif()
 
 
 if(MSVC)
 if(MSVC)
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3 /WX") # Compiler warnings, error on warning
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3 /WX") # Compiler warnings, error on warning
-  set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
-  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd")
+
+  if(NOT BUILD_SHARED_LIB)
+    set(CompilerFlags CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_C_FLAGS
+        CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE)
+    foreach(CompilerFlag ${CompilerFlags})
+      string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}")
+    endforeach()
+  endif()
 endif()
 endif()
 
 
 #########################
 #########################
@@ -181,27 +259,35 @@ endif()
 
 
 file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
 file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
 configure_file("include/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
 configure_file("include/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
-include_directories(${PROJECT_BINARY_DIR}/src_generated
-                    ${PROJECT_SOURCE_DIR}/include
-                    ${PROJECT_SOURCE_DIR}/deps)
+configure_file("include/open62541.pc.in" "${PROJECT_BINARY_DIR}/src_generated/open62541.pc" @ONLY)
+
+if(UA_ENABLE_DISCOVERY_MULTICAST)
+    set(MDNSD_LOGLEVEL 300 CACHE STRING "Level at which logs shall be reported" FORCE)
+    configure_file("deps/mdnsd/libmdnsd/mdnsd_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/mdnsd_config.h")
+endif()
+
+include_directories(${PROJECT_SOURCE_DIR}/include
+                    ${PROJECT_SOURCE_DIR}/plugins # TODO: discovery depends on the default config
+                    ${PROJECT_SOURCE_DIR}/deps
+                    ${PROJECT_BINARY_DIR}
+                    ${PROJECT_BINARY_DIR}/src_generated)
 
 
 set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
 set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/deps/ms_stdint.h
                      ${PROJECT_SOURCE_DIR}/deps/ms_stdint.h
                      ${PROJECT_SOURCE_DIR}/include/ua_constants.h
                      ${PROJECT_SOURCE_DIR}/include/ua_constants.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
-                     ${PROJECT_BINARY_DIR}/src_generated/ua_nodeids.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_handling.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_handling.h
-                     ${PROJECT_SOURCE_DIR}/include/ua_connection.h
-                     ${PROJECT_SOURCE_DIR}/include/ua_job.h
-                     ${PROJECT_SOURCE_DIR}/include/ua_log.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_plugin_network.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_plugin_log.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_plugin_access_control.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_plugin_securitypolicy.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_plugin_nodestore.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_server_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
-                     ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.h
-                     ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.h
-                     ${PROJECT_SOURCE_DIR}/plugins/ua_config_standard.h)
-
+)
 set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
 set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
                      ${PROJECT_SOURCE_DIR}/deps/libc_time.h
                      ${PROJECT_SOURCE_DIR}/deps/libc_time.h
@@ -213,14 +299,14 @@ set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                      ${PROJECT_SOURCE_DIR}/src/ua_connection_internal.h
                      ${PROJECT_SOURCE_DIR}/src/ua_connection_internal.h
                      ${PROJECT_SOURCE_DIR}/src/ua_securechannel.h
                      ${PROJECT_SOURCE_DIR}/src/ua_securechannel.h
-                     ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.h
                      ${PROJECT_SOURCE_DIR}/src/ua_session.h
                      ${PROJECT_SOURCE_DIR}/src/ua_session.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_timer.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.h
-                     ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_session_manager.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_session_manager.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_securechannel_manager.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_securechannel_manager.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_server_internal.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_server_internal.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_services.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_services.h
+                     ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.h
                      ${PROJECT_SOURCE_DIR}/src/client/ua_client_internal.h)
                      ${PROJECT_SOURCE_DIR}/src/client/ua_client_internal.h)
 
 
 # TODO: make client optional
 # TODO: make client optional
@@ -228,83 +314,131 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.c
                 ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
                 ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
+                ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c
+                ${PROJECT_SOURCE_DIR}/src/ua_util.c
+                ${PROJECT_SOURCE_DIR}/src/ua_timer.c
+                ${PROJECT_SOURCE_DIR}/src/ua_session.c
                 ${PROJECT_SOURCE_DIR}/src/ua_connection.c
                 ${PROJECT_SOURCE_DIR}/src/ua_connection.c
                 ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
                 ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
-                ${PROJECT_SOURCE_DIR}/src/ua_session.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_server_ns0.c
+                ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_binary.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_binary.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_utils.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_utils.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_worker.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_worker.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_server_discovery.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_securechannel_manager.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_securechannel_manager.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_session_manager.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_session_manager.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.c
-                # nodestores
-                ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_nodestore_concurrent.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_datachange.c
                 # services
                 # services
-                ${PROJECT_SOURCE_DIR}/src/server/ua_services_discovery.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_services_securechannel.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_services_session.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_services_attribute.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_services_nodemanagement.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
-                # method call
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_call.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_call.c
-                # subscriptions
-                ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_session.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_attribute.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_discovery.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_securechannel.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_nodemanagement.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_discovery_multicast.c
                 # client
                 # client
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
+                ${PROJECT_SOURCE_DIR}/src/client/ua_client_connect.c
+                ${PROJECT_SOURCE_DIR}/src/client/ua_client_discovery.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel_subscriptions.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel_subscriptions.c
+
                 # dependencies
                 # dependencies
                 ${PROJECT_SOURCE_DIR}/deps/libc_time.c
                 ${PROJECT_SOURCE_DIR}/deps/libc_time.c
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
 
 
+set(default_plugin_headers ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.h
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.h
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.h
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_nodestore_default.h
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.h
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.h)
+
 set(default_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
 set(default_plugin_sources ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_clock.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_clock.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.c
                            ${PROJECT_SOURCE_DIR}/plugins/ua_log_stdout.c
-                           ${PROJECT_SOURCE_DIR}/plugins/ua_config_standard.c)
-
-if(UA_ENABLE_EMBEDDED_LIBC)
-  list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/deps/libc_string.c)
-endif()
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.c
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_nodestore_default.c
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_config_default.c
+                           ${PROJECT_SOURCE_DIR}/plugins/ua_securitypolicy_none.c)
 
 
-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)
+if(UA_DEBUG_DUMP_PKGS)
+    list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/plugins/ua_debug_dump_pkgs.c)
 endif()
 endif()
 
 
 if(UA_ENABLE_NONSTANDARD_UDP)
 if(UA_ENABLE_NONSTANDARD_UDP)
     list(APPEND exported_headers ${PROJECT_SOURCE_DIR}/plugins/ua_network_udp.h)
     list(APPEND exported_headers ${PROJECT_SOURCE_DIR}/plugins/ua_network_udp.h)
 endif()
 endif()
 
 
+if(UA_ENABLE_DISCOVERY_MULTICAST)
+    # prepend in list, otherwise it complains that winsock2.h has to be included before windows.h
+    set(internal_headers ${PROJECT_BINARY_DIR}/src_generated/mdnsd_config.h
+                         ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/1035.h
+                         ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/xht.h
+                         ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/sdtxt.h
+                         ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/mdnsd.h
+                         ${internal_headers} )
+    list(APPEND internal_headers ${PROJECT_SOURCE_DIR}/src/server/ua_mdns_internal.h)
+    set(lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_mdns.c
+                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/1035.c
+                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/xht.c
+                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/sdtxt.c
+                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/mdnsd.c
+                    ${lib_sources})
+endif()
+
 #########################
 #########################
 # Generate source files #
 # Generate source files #
 #########################
 #########################
 
 
-# standard data types
+if (UA_ENABLE_FULL_NS0)
+    set(UA_FILE_NS0 ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml)
+    set(UA_FILE_DATATYPES "")
+    set(UA_FILE_NODEIDS ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/NodeIds.csv)
+    set(UA_FILE_TYPES_BSD ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.Types.bsd)
+    if(NOT EXISTS "${UA_FILE_NS0}")
+        MESSAGE(FATAL_ERROR "File ${UA_FILE_NS0} not found. You probably need to initialize the git submodule for deps/ua-nodeset.")
+    endif()
+else()
+    set(UA_FILE_NS0 ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.NodeSet2.Minimal.xml)
+    set(UA_FILE_DATATYPES "${PROJECT_SOURCE_DIR}/tools/schema/datatypes_minimal.txt")
+    set(UA_FILE_NODEIDS ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv)
+    set(UA_FILE_TYPES_BSD ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd)
+endif()
+
+if (UA_FILE_DATATYPES STREQUAL "")
+    set(SELECTED_TYPES_TMP "")
+else()
+  set(SELECTED_TYPES_TMP "--selected-types=${UA_FILE_DATATYPES}")
+endif()
+
+# standard-defined data types
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
 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.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_handling.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_handling.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                    PRE_BUILD
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
-                           --typedescriptions ${PROJECT_SOURCE_DIR}/tools/schema/NodeIds.csv
-                           --selected_types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_minimal.txt
-                           ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd ${PROJECT_BINARY_DIR}/src_generated/ua_types
+                           --type-csv=${UA_FILE_NODEIDS}
+                           ${SELECTED_TYPES_TMP}
+                           --type-bsd=${UA_FILE_TYPES_BSD}
+                           ${PROJECT_BINARY_DIR}/src_generated/ua_types
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
-                           ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_minimal.txt
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
+                           ${UA_FILE_NODEIDS}
+                           ${UA_FILE_TYPES_BSD}
+                           ${UA_FILE_DATATYPES})
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 add_custom_target(open62541-generator-types DEPENDS
 add_custom_target(open62541-generator-types DEPENDS
-        ${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_handling.h
-        ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h)
+                  ${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_handling.h
+                  ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h)
 
 
 # transport data types
 # transport data types
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
@@ -313,13 +447,17 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_transport_gener
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                           ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h
                    PRE_BUILD
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
                    COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
-                           --namespace=1 --selected_types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
-                           ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.Types.bsd
-                           ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd
+                           --namespace=1
+                           --selected-types=${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
+                           --type-bsd=${UA_FILE_TYPES_BSD}
+                           --type-bsd=${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd
+                           --no-builtin
                            ${PROJECT_BINARY_DIR}/src_generated/ua_transport
                            ${PROJECT_BINARY_DIR}/src_generated/ua_transport
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
                            ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_transport.txt
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd)
+                           ${UA_FILE_TYPES_BSD}
+                           ${PROJECT_SOURCE_DIR}/tools/schema/Custom.Opc.Ua.Transport.bsd)
+
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 add_custom_target(open62541-generator-transport DEPENDS
 add_custom_target(open62541-generator-transport DEPENDS
         ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
         ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.c
@@ -327,14 +465,6 @@ add_custom_target(open62541-generator-transport DEPENDS
         ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_handling.h
         ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_handling.h
         ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h)
         ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated_encoding_binary.h)
 
 
-# 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
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_nodeids.py
-                           ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/NodeIds.csv)
-
 # statuscode explanation
 # statuscode explanation
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c
         PRE_BUILD
         PRE_BUILD
@@ -342,57 +472,82 @@ add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_desc
         ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions
         ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions
         DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_statuscode_descriptions.py
         DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_statuscode_descriptions.py
         ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv)
         ${CMAKE_CURRENT_SOURCE_DIR}/tools/schema/Opc.Ua.StatusCodes.csv)
-list(APPEND lib_sources ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c)
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 # we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
 add_custom_target(open62541-generator-statuscode DEPENDS
 add_custom_target(open62541-generator-statuscode DEPENDS
-                  ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c)
-
-
-# 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
-                   DEPENDS ${PROJECT_SOURCE_DIR}/tools/schema/namespace0/${GENERATE_NAMESPACE0_FILE}
-                           ${PROJECT_SOURCE_DIR}/tools/pyUANamespace/generate_open62541CCode.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_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c)
 
 
 # single-file release
 # single-file release
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h
                    PRE_BUILD
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
                    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
-                           ${OPEN62541_VER_COMMIT} ${CMAKE_CURRENT_BINARY_DIR}/open62541.h ${exported_headers}
+                           ${OPEN62541_VER_COMMIT} ${CMAKE_CURRENT_BINARY_DIR}/open62541.h
+                           ${exported_headers} ${default_plugin_headers}
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
-                           ${exported_headers} ${internal_headers})
+                           ${exported_headers} ${default_plugin_headers})
 
 
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.c
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.c
                    PRE_BUILD
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
                    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
                            ${OPEN62541_VER_COMMIT} ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
                            ${OPEN62541_VER_COMMIT} ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
                            ${internal_headers} ${lib_sources} ${default_plugin_sources}
                            ${internal_headers} ${lib_sources} ${default_plugin_sources}
-                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${internal_headers} ${lib_sources})
+                   DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py ${internal_headers}
+                           ${lib_sources})
 
 
 add_custom_target(open62541-amalgamation-source DEPENDS ${PROJECT_BINARY_DIR}/open62541.c)
 add_custom_target(open62541-amalgamation-source DEPENDS ${PROJECT_BINARY_DIR}/open62541.c)
 add_custom_target(open62541-amalgamation-header DEPENDS ${PROJECT_BINARY_DIR}/open62541.h)
 add_custom_target(open62541-amalgamation-header DEPENDS ${PROJECT_BINARY_DIR}/open62541.h)
 
 
-add_dependencies(open62541-amalgamation-source open62541-generator-types open62541-generator-transport open62541-generator-statuscode)
 add_dependencies(open62541-amalgamation-header open62541-generator-types)
 add_dependencies(open62541-amalgamation-header open62541-generator-types)
+add_dependencies(open62541-amalgamation-source open62541-generator-types
+                 open62541-generator-transport open62541-generator-statuscode)
+
+
+set(NODESET_MAX_STR_LEN 0)
+if(MSVC)
+    # Visual Studio has a maximum string length of 65535 bytes
+    set(NODESET_MAX_STR_LEN 65535)
+endif()
+
+# generated namespace 0
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.c
+                          ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.h
+                   PRE_BUILD
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                           --generate-ns0
+                           --internal-headers
+                           --max-string-length=${NODESET_MAX_STR_LEN}
+                           --ignore ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/NodeID_NS0_Base.txt
+                           --xml ${UA_FILE_NS0}
+                           ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0
+                   DEPENDS ${UA_FILE_NS0}
+                           ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                           ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodes.py
+                           ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset.py
+                           ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/datatypes.py
+                           ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541.py
+                           ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_nodes.py
+                           ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_datatypes.py)
+
+# stack protector needs to be disabled for the huge ns0 file, otherwise it may take many minutes to compile the file.
+set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.c PROPERTIES COMPILE_FLAGS -fno-stack-protector)
+
+# we need a custom target to avoid that the generator is called concurrently and thus overwriting files while the other thread is compiling
+add_custom_target(open62541-generator-namespace DEPENDS
+        ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.c
+        ${PROJECT_BINARY_DIR}/src_generated/ua_namespace0.h)
 
 
 #####################
 #####################
 # Build the Library #
 # Build the Library #
 #####################
 #####################
 
 
+assign_source_group(${lib_sources})
+assign_source_group(${internal_headers})
+assign_source_group(${exported_headers})
+assign_source_group(${default_plugin_sources})
+
 if(UA_ENABLE_AMALGAMATION)
 if(UA_ENABLE_AMALGAMATION)
-    include_directories(${PROJECT_BINARY_DIR}) # contains open62541.h
     add_library(open62541-object OBJECT ${PROJECT_BINARY_DIR}/open62541.c ${PROJECT_BINARY_DIR}/open62541.h)
     add_library(open62541-object OBJECT ${PROJECT_BINARY_DIR}/open62541.c ${PROJECT_BINARY_DIR}/open62541.h)
+    target_include_directories(open62541-object PRIVATE ${PROJECT_BINARY_DIR})
+
     # make sure the open62541_amalgamation target builds before so that amalgamation is finished and it is not executed again for open62541-object
     # make sure the open62541_amalgamation target builds before so that amalgamation is finished and it is not executed again for open62541-object
     # and thus may overwrite the amalgamation result during multiprocessor compilation
     # and thus may overwrite the amalgamation result during multiprocessor compilation
     # the header is already a dependency of open62541 target itself
     # the header is already a dependency of open62541 target itself
@@ -401,9 +556,7 @@ if(UA_ENABLE_AMALGAMATION)
                      open62541-generator-types
                      open62541-generator-types
                      open62541-generator-transport
                      open62541-generator-transport
                      open62541-generator-statuscode
                      open62541-generator-statuscode
-                     open62541-amalgamation-source
-                     )
-
+                     open62541-amalgamation-source)
 
 
     add_library(open62541 $<TARGET_OBJECTS:open62541-object>)
     add_library(open62541 $<TARGET_OBJECTS:open62541-object>)
 
 
@@ -425,6 +578,7 @@ else()
     target_include_directories(open62541-plugins PRIVATE ${PROJECT_SOURCE_DIR}/plugins)
     target_include_directories(open62541-plugins PRIVATE ${PROJECT_SOURCE_DIR}/plugins)
     target_include_directories(open62541-plugins PRIVATE ${PROJECT_BINARY_DIR}/src_generated)
     target_include_directories(open62541-plugins PRIVATE ${PROJECT_BINARY_DIR}/src_generated)
     target_compile_definitions(open62541-plugins PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)
     target_compile_definitions(open62541-plugins PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)
+    set_target_properties(open62541-plugins PROPERTIES FOLDER "open62541/lib")
 
 
     add_library(open62541 $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
     add_library(open62541 $<TARGET_OBJECTS:open62541-object> $<TARGET_OBJECTS:open62541-plugins>)
 
 
@@ -434,24 +588,23 @@ else()
     endif()
     endif()
 endif()
 endif()
 
 
-if(UA_ENABLE_GENERATE_NAMESPACE0)
-    add_dependencies(open62541-amalgamation-source open62541-generator-namespace)
-    add_dependencies(open62541-amalgamation-header open62541-generator-namespace)
-    if(NOT UA_ENABLE_AMALGAMATION)
-        add_dependencies(open62541-object open62541-generator-namespace)
-    endif()
+add_dependencies(open62541-amalgamation-source open62541-generator-namespace)
+add_dependencies(open62541-amalgamation-header open62541-generator-namespace)
+if(NOT UA_ENABLE_AMALGAMATION)
+    add_dependencies(open62541-object open62541-generator-namespace)
 endif()
 endif()
 
 
 # Export Symbols
 # Export Symbols
 target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)
 target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)
 target_compile_definitions(open62541 PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)
 target_compile_definitions(open62541 PRIVATE -DUA_DYNAMIC_LINKING_EXPORT)
+if (UA_ENABLE_DISCOVERY_MULTICAST)
+    target_compile_definitions(open62541-object PRIVATE -DMDNSD_DYNAMIC_LINKING_EXPORT)
+    target_compile_definitions(open62541 PRIVATE -DMDNSD_DYNAMIC_LINKING_EXPORT)
+endif()
 
 
 # DLL requires linking to dependencies
 # DLL requires linking to dependencies
 target_link_libraries(open62541 ${open62541_LIBRARIES})
 target_link_libraries(open62541 ${open62541_LIBRARIES})
 
 
-# Always generate the amalgamated header
-add_dependencies(open62541 open62541-amalgamation-header)
-
 # Generate properly versioned shared library links on Linux
 # Generate properly versioned shared library links on Linux
 SET_TARGET_PROPERTIES(open62541 PROPERTIES SOVERSION 0 VERSION "${OPEN62541_VER_MAJOR}.${OPEN62541_VER_MINOR}.${OPEN62541_VER_PATCH}")
 SET_TARGET_PROPERTIES(open62541 PROPERTIES SOVERSION 0 VERSION "${OPEN62541_VER_MAJOR}.${OPEN62541_VER_MINOR}.${OPEN62541_VER_PATCH}")
 
 
@@ -475,6 +628,13 @@ if(UA_BUILD_UNIT_TESTS)
     add_subdirectory(tests)
     add_subdirectory(tests)
 endif()
 endif()
 
 
+if(UA_BUILD_FUZZING OR UA_BUILD_OSS_FUZZ)
+    # Force enable discovery, to also fuzzy-test this code
+    set(UA_ENABLE_DISCOVERY ON CACHE STRING "" FORCE)
+    set(UA_ENABLE_DISCOVERY_MULTICAST ON CACHE STRING "" FORCE)
+    add_subdirectory(tests/fuzz)
+endif()
+
 ############################
 ############################
 # Linting run (clang-tidy) #
 # Linting run (clang-tidy) #
 ############################
 ############################
@@ -493,6 +653,7 @@ add_custom_target(lint ${CLANG_TIDY_PROGRAM}
                   -I${PROJECT_SOURCE_DIR}/src/server
                   -I${PROJECT_SOURCE_DIR}/src/server
                   -I${PROJECT_SOURCE_DIR}/src/client
                   -I${PROJECT_SOURCE_DIR}/src/client
                   -I${PROJECT_BINARY_DIR}/src_generated
                   -I${PROJECT_BINARY_DIR}/src_generated
+                  -DUA_NO_AMALGAMATION
                   DEPENDS ${lib_sources}
                   DEPENDS ${lib_sources}
                   COMMENT "Run clang-tidy on the library")
                   COMMENT "Run clang-tidy on the library")
 add_dependencies(lint open62541)
 add_dependencies(lint open62541)
@@ -504,12 +665,52 @@ add_dependencies(lint open62541)
 # specify install location with `-DCMAKE_INSTALL_PREFIX=xyz`
 # specify install location with `-DCMAKE_INSTALL_PREFIX=xyz`
 # Enable shared library with `-DBUILD_SHARED_LIBS=ON`
 # Enable shared library with `-DBUILD_SHARED_LIBS=ON`
 
 
+set(cmake_configfile_install ${LIB_INSTALL_DIR}/cmake3)
+set(target_install_dest_name "${cmake_configfile_install}/open62541Targets.cmake")
+set(open62541_tools_dir share/open62541/tools)
+set(open62541_deps_dir include/open62541/deps)
+
 # export library (either static or shared depending on BUILD_SHARED_LIBS)
 # export library (either static or shared depending on BUILD_SHARED_LIBS)
 install(TARGETS open62541
 install(TARGETS open62541
-        LIBRARY DESTINATION ${LIB_INSTALL_DIR} 
-        ARCHIVE DESTINATION ${LIB_INSTALL_DIR}) 
+        EXPORT open62541Targets
+        LIBRARY DESTINATION ${LIB_INSTALL_DIR}
+        ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}
+        INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}/open62541 ${open62541_deps_dir})
+
+include(CMakePackageConfigHelpers)
+configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/open62541-config.cmake.in"
+                              "${CMAKE_CURRENT_BINARY_DIR}/cmake/open62541-config.cmake"
+                              INSTALL_DESTINATION "${cmake_configfile_install}"
+                              PATH_VARS target_install_dest_name open62541_tools_dir)
+
+set(open62541_VERSION)
+get_target_property(open62541_VERSION open62541 VERSION)
+
+write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/open62541ConfigVersion.cmake"
+                                 VERSION ${open62541_VERSION}
+                                 COMPATIBILITY AnyNewerVersion)
+
+install(EXPORT open62541Targets
+        FILE open62541Targets.cmake
+        DESTINATION "${cmake_configfile_install}")
+
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/open62541-config.cmake"
+              "${CMAKE_CURRENT_BINARY_DIR}/open62541ConfigVersion.cmake"
+        DESTINATION "${cmake_configfile_install}")
+
+
+if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
+    install(FILES "${PROJECT_BINARY_DIR}/src_generated/open62541.pc"
+            DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+endif()
+
 # export amalgamated header open62541.h which is generated due to build of open62541-object
 # export amalgamated header open62541.h which is generated due to build of open62541-object
-install(FILES ${PROJECT_BINARY_DIR}/open62541.h DESTINATION include)
+if(UA_ENABLE_AMALGAMATION)
+    install(FILES ${PROJECT_BINARY_DIR}/open62541.h DESTINATION include/open62541)
+endif()
+install(DIRECTORY deps/ DESTINATION ${open62541_deps_dir})
+install(DIRECTORY tools/ DESTINATION ${open62541_tools_dir} USE_SOURCE_PERMISSIONS)
 
 
 ##########################
 ##########################
 # Packaging (DEB/RPM)    #
 # Packaging (DEB/RPM)    #
@@ -528,3 +729,16 @@ set(CPACK_PACKAGE_VERSION_PATCH "0")
 set(CPACK_DEBIAN_PACKAGE_MAINTAINER "open62541 team") #required
 set(CPACK_DEBIAN_PACKAGE_MAINTAINER "open62541 team") #required
 
 
 include(CPack)
 include(CPack)
+
+##################################
+# Visual studio solution folders #
+##################################
+
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "_CmakePredifinedTargets")
+
+set_target_properties(open62541 PROPERTIES FOLDER "open62541/lib")
+set_target_properties(open62541-object PROPERTIES FOLDER "open62541/lib")
+set_target_properties(lint PROPERTIES FOLDER "CodeAnalysis")
+set_target_properties(open62541-amalgamation-header PROPERTIES FOLDER "open62541/lib")
+set_target_properties(open62541-amalgamation-source PROPERTIES FOLDER "open62541/lib")

+ 3 - 2
Dockerfile

@@ -1,10 +1,11 @@
 FROM alpine:3.5
 FROM alpine:3.5
-RUN apk add --no-cache cmake gcc g++ musl-dev python make && rm -rf /var/cache/apk/*
+RUN apk add --no-cache cmake gcc g++ musl-dev python py-pip py-six make && rm -rf /var/cache/apk/*
 ADD . /tmp/open62541
 ADD . /tmp/open62541
 WORKDIR /tmp/open62541/build
 WORKDIR /tmp/open62541/build
+RUN pip install six
 RUN cmake -DUA_ENABLE_AMALGAMATION=true  \
 RUN cmake -DUA_ENABLE_AMALGAMATION=true  \
           -DBUILD_SHARED_LIBS=true \
           -DBUILD_SHARED_LIBS=true \
           /tmp/open62541 
           /tmp/open62541 
 RUN make -j
 RUN make -j
 RUN cp *.h /usr/include/ && \
 RUN cp *.h /usr/include/ && \
-    cp *.so /usr/lib
+    cp bin/*.so /usr/lib

+ 0 - 1
LICENSE

@@ -371,4 +371,3 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice
 
 
   This Source Code Form is "Incompatible With Secondary Licenses", as
   This Source Code Form is "Incompatible With Secondary Licenses", as
   defined by the Mozilla Public License, v. 2.0.
   defined by the Mozilla Public License, v. 2.0.
-

File diff suppressed because it is too large
+ 13 - 15
README.md


+ 1 - 1
TinyDockerfile

@@ -6,6 +6,6 @@ RUN apk add --no-cache cmake gcc g++ musl-dev python make && rm -rf /var/cache/a
           -DBUILD_SHARED_LIBS=true /tmp/open62541 && \
           -DBUILD_SHARED_LIBS=true /tmp/open62541 && \
     make && \
     make && \
     cp *.h /usr/include/ && \
     cp *.h /usr/include/ && \
-    cp *.so /usr/lib && \
+    cp bin/*.so /usr/lib && \
     make clean && \
     make clean && \
     apk del cmake gcc g++ musl-dev python make
     apk del cmake gcc g++ musl-dev python make

+ 90 - 20
appveyor.yml

@@ -5,81 +5,151 @@ clone_depth: 20
 
 
 environment:
 environment:
     global:
     global:
+        APPVEYOR_CACHE_ENTRY_ZIP_ARGS: -t7z -m0=lzma -mx=9
         CYG_ARCH: x86
         CYG_ARCH: x86
         CYG_ROOT: C:/cygwin
         CYG_ROOT: C:/cygwin
         CYG_SETUP_URL: http://cygwin.com/setup-x86.exe
         CYG_SETUP_URL: http://cygwin.com/setup-x86.exe
-        CYG_MIRROR: http://cygwin.mirror.constant.com
+        CYG_MIRROR: http://mirrors.kernel.org/sourceware/cygwin/
         CYG_CACHE: C:\cygwin\var\cache\setup
         CYG_CACHE: C:\cygwin\var\cache\setup
         CYG_BASH: C:/cygwin/bin/bash
         CYG_BASH: C:/cygwin/bin/bash
-
       
       
     matrix:
     matrix:
         - CC_NAME: MinGW Makefiles
         - CC_NAME: MinGW Makefiles
           CC_SHORTNAME: mingw
           CC_SHORTNAME: mingw
-          MAKE: mingw32-make
+          MAKE: mingw32-make -j
           FORCE_CXX: OFF
           FORCE_CXX: OFF
-        # - CC_NAME: Visual Studio 9 2008
-        #   CC_SHORTNAME: vs2008
-        # # Do not use multicore switch (/m), it causes appveyor to randomly fail
-        #   MAKE: msbuild open62541.sln
-        #   FORCE_CXX: ON
+          OUT_DIR_LIB: bin
+          OUT_DIR_EXAMPLES: bin\examples
+        - CC_NAME: Visual Studio 9 2008
+          CC_SHORTNAME: vs2008
+          # Do not build in parallel, project dependencies are not solved correctly and thus appveyor may randomly fail
+          MAKE: msbuild /m:1 /p:BuildInParallel=false /p:ContinueOnError=false /p:StopOnFirstFailure=true open62541.sln
+          FORCE_CXX: ON
+          OUT_DIR_LIB: bin\Debug
+          OUT_DIR_EXAMPLES: bin\examples\Debug
         - CC_NAME: Visual Studio 12 2013
         - CC_NAME: Visual Studio 12 2013
           CC_SHORTNAME: vs2013
           CC_SHORTNAME: vs2013
-          # Do not use multicore switch (/m), it causes appveyor to randomly fail
-          MAKE: msbuild open62541.sln
+          # Do not build in parallel, project dependencies are not solved correctly and thus appveyor may randomly fail
+          MAKE: msbuild /m:1 /p:BuildInParallel=false /p:ContinueOnError=false /p:StopOnFirstFailure=true open62541.sln
           FORCE_CXX: OFF
           FORCE_CXX: OFF
+          OUT_DIR_LIB: bin\Debug
+          OUT_DIR_EXAMPLES: bin\examples\Debug
         - CC_NAME: Visual Studio 12 2013 Win64
         - CC_NAME: Visual Studio 12 2013 Win64
           CC_SHORTNAME: vs2013-x64
           CC_SHORTNAME: vs2013-x64
-          # Do not use multicore switch (/m), it causes appveyor to randomly fail
-          MAKE: msbuild open62541.sln
+          # Do not build in parallel, project dependencies are not solved correctly and thus appveyor may randomly fail
+          MAKE: msbuild /m:1 /p:BuildInParallel=false /p:ContinueOnError=false /p:StopOnFirstFailure=true open62541.sln
           FORCE_CXX: OFF
           FORCE_CXX: OFF
+          OUT_DIR_LIB: bin\Debug
+          OUT_DIR_EXAMPLES: bin\examples\Debug
 
 
 cache:
 cache:
   - '%CYG_CACHE%'
   - '%CYG_CACHE%'
+  - 'c:\miktex'
+  #- 'c:\python27'
 
 
 init:
 init:
   - git config --global core.autocrlf input # Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
   - git config --global core.autocrlf input # Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail
 
 
 # Install needed build dependencies
 # Install needed build dependencies
 install:
 install:
+  - git submodule update --init --recursive
   - if not exist "%CYG_ROOT%" mkdir "%CYG_ROOT%"
   - if not exist "%CYG_ROOT%" mkdir "%CYG_ROOT%"
   - ps: echo "Installing Cygwin from $env:CYG_SETUP_URL to $env:CYG_ROOT/setup-x86.exe"
   - ps: echo "Installing Cygwin from $env:CYG_SETUP_URL to $env:CYG_ROOT/setup-x86.exe"
   - appveyor DownloadFile %CYG_SETUP_URL% -FileName %CYG_ROOT%/setup-x86.exe
   - appveyor DownloadFile %CYG_SETUP_URL% -FileName %CYG_ROOT%/setup-x86.exe
   - ps: echo "Downloaded. Now ready to install."
   - ps: echo "Downloaded. Now ready to install."
   - cmd: '"%CYG_ROOT%/setup-x86.exe" --quiet-mode --no-shortcuts --only-site -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" --packages cmake,python'
   - cmd: '"%CYG_ROOT%/setup-x86.exe" --quiet-mode --no-shortcuts --only-site -R "%CYG_ROOT%" -s "%CYG_MIRROR%" -l "%CYG_CACHE%" --packages cmake,python'
   - cmd: '%CYG_BASH% -lc "cygcheck -dc cygwin"'
   - cmd: '%CYG_BASH% -lc "cygcheck -dc cygwin"'
+  # Install miktex to get pdflatex, if we don't get it from the cache
+  - if not exist c:\miktex\texmfs\install\miktex\bin\pdflatex.exe appveyor DownloadFile http://mirrors.ctan.org/systems/win32/miktex/setup/miktex-portable.exe
+  - if not exist c:\miktex\texmfs\install\miktex\bin\pdflatex.exe 7z x miktex-portable.exe -oc:\miktex >NUL
+  # Remove some big files to reduce size to be cached
+  - if exist c:\miktex\texmfs\install\doc rd /s /q c:\miktex\texmfs\install\doc
+  - if exist c:\miktex\texmfs\install\internal rd /s /q c:\miktex\texmfs\install\internal
+  - if exist c:\miktex\texmfs\install\miktex\bin\biber.exe rd /s /q c:\miktex\texmfs\install\miktex\bin\biber.exe
+  - if exist c:\miktex\texmfs\install\miktex\bin\icudt58.dll rd /s /q c:\miktex\texmfs\install\miktex\bin\icudt58.dll
+  - if exist c:\miktex\texmfs\install\miktex\bin\a5toa4.exe rd /s /q c:\miktex\texmfs\install\miktex\bin\a5toa4.exe
+  - pip install --user sphinx sphinx_rtd_theme
+  - cinst graphviz.portable
 
 
 before_build:
 before_build:
+  # use MinGW64
+  - set PATH=C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin;%PATH%
   # Workaround for CMake not wanting sh.exe on PATH for MinGW
   # Workaround for CMake not wanting sh.exe on PATH for MinGW
   - set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
   - set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
-  - set PATH=C:\MinGW\bin;%PATH%
+  # Miktex
+  - set "PATH=%PATH%;c:\miktex\texmfs\install\miktex\bin;%APPDATA%\Python\Scripts"
+  # autoinstall latex packages (0=no, 1=autoinstall, 2=ask)
+  # this adds this to the registry!
+  - initexmf --set-config-value [MPM]AutoInstall=1
+  - initexmf --update-fndb
 
 
 build_script:
 build_script:
+  # log is loaded from cache, so we strip it here
+  - rd /s /q c:\miktex\texmfs\data\miktex\log
+
   - cd c:\projects\open62541
   - cd c:\projects\open62541
+  # Collect files for .zip packing
+  - md pack
+  - copy "%APPVEYOR_BUILD_FOLDER%\LICENSE" pack\
+  - copy "%APPVEYOR_BUILD_FOLDER%\AUTHORS" pack\
+  - copy "%APPVEYOR_BUILD_FOLDER%\README.md" pack\
+  # now start build
+  - md build
+  - cd build
+  - echo. && echo "##### Building Documentation on %CC_NAME% #####" && echo.
+  - cmake -DMIKTEX_BINARY_PATH=c:\miktex\texmfs\install\miktex\bin -DCMAKE_BUILD_TYPE=Release -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -DUA_BUILD_EXAMPLES:BOOL=OFF -G"%CC_NAME%" ..
+  - cmake --build . --target doc_latex & cmake --build . --target doc_pdf
+  - move "%APPVEYOR_BUILD_FOLDER%\build\doc_latex\open62541.pdf" %APPVEYOR_BUILD_FOLDER%\pack\
+  - cd ..
+  - rd /s /q build
   - md build
   - md build
   - cd build
   - cd build
-  - echo "Testing %CC_NAME%"
+  - echo. && echo "##### Testing %CC_NAME% #####" && echo.
   - cmake -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -G"%CC_NAME%" ..
   - cmake -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -G"%CC_NAME%" ..
   - '%MAKE%'
   - '%MAKE%'
   - cd ..
   - cd ..
   - rd /s /q build
   - rd /s /q build
   - md build
   - md build
   - cd build
   - cd build
-  - echo "Testing %CC_NAME% with amalgamation"
+  - echo. && echo "##### Testing %CC_NAME% with full NS0 #####" && echo.
+  - cmake -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_FULL_NS0:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -G"%CC_NAME%" ..
+  - '%MAKE%'
+  - cd ..
+  - rd /s /q build
+  - md build
+  - cd build
+  - echo. && echo "##### Testing %CC_NAME% with amalgamation #####" && echo.
   - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_AMALGAMATION:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -DBUILD_SHARED_LIBS:BOOL=OFF -G"%CC_NAME%" ..
   - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_AMALGAMATION:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -DBUILD_SHARED_LIBS:BOOL=OFF -G"%CC_NAME%" ..
   - '%MAKE%'
   - '%MAKE%'
-  - 7z a -tzip open62541-%CC_SHORTNAME%-static.zip %APPVEYOR_BUILD_FOLDER%\build\*
-  - move open62541-%CC_SHORTNAME%-static.zip %APPVEYOR_BUILD_FOLDER%
+  - md %APPVEYOR_BUILD_FOLDER%\pack_tmp
+  - move "%APPVEYOR_BUILD_FOLDER%\build\open62541.c" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - move "%APPVEYOR_BUILD_FOLDER%\build\open62541.h" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_EXAMPLES%\server.exe" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_EXAMPLES%\client.exe" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - if "%CC_SHORTNAME%" == "mingw" move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_LIB%\libopen62541.a" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - if not "%CC_SHORTNAME%" == "mingw" move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_LIB%\open62541.lib" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
   - cd ..
   - cd ..
+  - 7z a -tzip open62541-%CC_SHORTNAME%-static.zip "%APPVEYOR_BUILD_FOLDER%\pack\*" "%APPVEYOR_BUILD_FOLDER%\pack_tmp\*"
+  - rd /s /q pack_tmp
   - rd /s /q build
   - rd /s /q build
   - md build
   - md build
   - cd build
   - cd build
-  - echo "Testing %CC_NAME% with amalgamation and .dll"
+  - echo. && echo "##### Testing %CC_NAME% with amalgamation and .dll #####" && echo.
   - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_AMALGAMATION:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -DBUILD_SHARED_LIBS:BOOL=ON -G"%CC_NAME%" ..
   - cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_AMALGAMATION:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=%FORCE_CXX% -DBUILD_SHARED_LIBS:BOOL=ON -G"%CC_NAME%" ..
   - '%MAKE%'
   - '%MAKE%'
-  - 7z a -tzip open62541-%CC_SHORTNAME%-dynamic.zip %APPVEYOR_BUILD_FOLDER%\build\*
-  - move open62541-%CC_SHORTNAME%-dynamic.zip %APPVEYOR_BUILD_FOLDER%
+  - md %APPVEYOR_BUILD_FOLDER%\pack_tmp
+  - move "%APPVEYOR_BUILD_FOLDER%\build\open62541.c" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - move "%APPVEYOR_BUILD_FOLDER%\build\open62541.h" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_EXAMPLES%\server.exe" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_EXAMPLES%\client.exe" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - if "%CC_SHORTNAME%" == "mingw" move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_LIB%\libopen62541.dll" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - if "%CC_SHORTNAME%" == "mingw" move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_LIB%\libopen62541.dll.a" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - if not "%CC_SHORTNAME%" == "mingw" move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_LIB%\open62541.dll" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
+  - if not "%CC_SHORTNAME%" == "mingw" move "%APPVEYOR_BUILD_FOLDER%\build\%OUT_DIR_LIB%\open62541.pdb" %APPVEYOR_BUILD_FOLDER%\pack_tmp\
   - cd ..
   - cd ..
+  - 7z a -tzip open62541-%CC_SHORTNAME%-dynamic.zip "%APPVEYOR_BUILD_FOLDER%\pack\*" "%APPVEYOR_BUILD_FOLDER%\pack_tmp\*"
+  # do not cache log
+  - rd /s /q c:\miktex\texmfs\data\miktex\log
 
 
 after_build:
 after_build:
   - appveyor PushArtifact %APPVEYOR_BUILD_FOLDER%\open62541-%CC_SHORTNAME%-static.zip
   - appveyor PushArtifact %APPVEYOR_BUILD_FOLDER%\open62541-%CC_SHORTNAME%-static.zip

+ 0 - 34
deps/libc_string.c

@@ -1,34 +0,0 @@
-/*
- * This work is licensed under a Creative Commons CCZero 1.0 Universal License.
- * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
- */
-
-#include "ua_config.h"
-
-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--)
-        *d++ = *s++;
-    return dest;
-}
-
-void *memset(void *dest, int c, size_t n) {
-    unsigned char c8 = (unsigned char)c;
-    unsigned char *target = dest;
-    while(n--)
-        *target++ = c8;
-    return dest;
-}
-
-size_t strlen(const char *str) {
-    size_t len = 0;
-    for(const char *s = str; *s; s++, len++);
-    return len;
-}
-
-int memcmp(const void *vl, const void *vr, size_t n) {
-    const unsigned char *l = vl, *r = vr;
-    for(; n && *l == *r; n--, l++, r++);
-    return n ? *l-*r : 0;
-}

+ 4 - 6
deps/libc_time.c

@@ -1,8 +1,7 @@
-/*
- * Originally released by the musl project (http://www.musl-libc.org/) under the
- * MIT license. Taken from the file /src/time/__secs_to_tm.c
- */
+/* Originally released by the musl project (http://www.musl-libc.org/) under the
+ * MIT license. Taken from the file /src/time/__secs_to_tm.c */
 
 
+#include <limits.h>
 #include "libc_time.h"
 #include "libc_time.h"
 
 
 /* 2000-03-01 (mod 400 year, immediately after feb29 */
 /* 2000-03-01 (mod 400 year, immediately after feb29 */
@@ -12,8 +11,7 @@
 #define DAYS_PER_100Y (365*100 + 24)
 #define DAYS_PER_100Y (365*100 + 24)
 #define DAYS_PER_4Y   (365*4   + 1)
 #define DAYS_PER_4Y   (365*4   + 1)
 
 
-int __secs_to_tm(long long t, struct tm *tm)
-{
+int __secs_to_tm(long long t, struct mytm *tm) {
     long long days, secs, years;
     long long days, secs, years;
     int remdays, remsecs, remyears;
     int remdays, remsecs, remyears;
     int qc_cycles, c_cycles, q_cycles;
     int qc_cycles, c_cycles, q_cycles;

+ 15 - 3
deps/libc_time.h

@@ -1,8 +1,20 @@
 #ifndef LIBC_TIME_H_
 #ifndef LIBC_TIME_H_
 #define LIBC_TIME_H_
 #define LIBC_TIME_H_
 
 
-#include <limits.h>
-#include <time.h>
-int __secs_to_tm(long long t, struct tm *tm);
+struct mytm {
+    int tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+    /* long __tm_gmtoff; */
+    /* const char *__tm_zone; */
+};
+
+int __secs_to_tm(long long t, struct mytm *tm);
 
 
 #endif /* LIBC_TIME_H_ */
 #endif /* LIBC_TIME_H_ */

+ 1 - 0
deps/mdnsd

@@ -0,0 +1 @@
+Subproject commit 4cea3adf05cdea4d1149514c55c0eb2f1d857032

+ 2 - 0
deps/ms_stdint.h

@@ -47,6 +47,7 @@
 // compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
 // compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
 // or compiler give many errors like this:
 // or compiler give many errors like this:
 //   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
 //   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifndef UNDER_CE
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
@@ -54,6 +55,7 @@ extern "C" {
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif
+#endif
 
 
 // Define _W64 macros to mark types changing their size, like intptr_t.
 // Define _W64 macros to mark types changing their size, like intptr_t.
 #ifndef _W64
 #ifndef _W64

+ 10 - 9
deps/pcg_basic.h

@@ -21,18 +21,19 @@
  *     http://www.pcg-random.org
  *     http://www.pcg-random.org
  */
  */
 
 
-#ifndef PCG_BASIC_H_INCLUDED
-#define PCG_BASIC_H_INCLUDED 1
+#ifndef PCG_BASIC_H_
+#define PCG_BASIC_H_
 
 
-#include "ms_stdint.h"
-
-#if __cplusplus
+#ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+#include "ua_config.h"
+
 typedef struct pcg_state_setseq_64 {
 typedef struct pcg_state_setseq_64 {
-    uint64_t state;             // RNG state.  All values are possible.
-    uint64_t inc;               // Controls which RNG sequence (stream) is selected. Must *always* be odd.
+    uint64_t state;  /* RNG state.  All values are possible. */
+    uint64_t inc;    /* Controls which RNG sequence (stream) is selected. Must
+                      * *always* be odd. */
 } pcg32_random_t;
 } pcg32_random_t;
 
 
 #define PCG32_INITIALIZER { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
 #define PCG32_INITIALIZER { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
@@ -40,8 +41,8 @@ typedef struct pcg_state_setseq_64 {
 void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq);
 void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq);
 uint32_t pcg32_random_r(pcg32_random_t* rng);
 uint32_t pcg32_random_r(pcg32_random_t* rng);
 
 
-#if __cplusplus
+#ifdef __cplusplus
 }
 }
 #endif
 #endif
 
 
-#endif // PCG_BASIC_H_INCLUDED
+#endif /* PCG_BASIC_H_ */

+ 1 - 0
deps/ua-nodeset

@@ -0,0 +1 @@
+Subproject commit ddce8bb6a1792916b161a9e3ba3b6b80675e8c1e

+ 13 - 12
doc/CMakeLists.txt

@@ -23,11 +23,11 @@ generate_rst(${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h ${DOC_SRC_
 generate_rst(${PROJECT_SOURCE_DIR}/include/ua_server.h ${DOC_SRC_DIR}/server.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/include/ua_server.h ${DOC_SRC_DIR}/server.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/include/ua_client.h ${DOC_SRC_DIR}/client.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/include/ua_client.h ${DOC_SRC_DIR}/client.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h ${DOC_SRC_DIR}/client_highlevel.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h ${DOC_SRC_DIR}/client_highlevel.rst)
-generate_rst(${PROJECT_SOURCE_DIR}/include/ua_log.h ${DOC_SRC_DIR}/log.rst)
-generate_rst(${PROJECT_SOURCE_DIR}/include/ua_connection.h ${DOC_SRC_DIR}/connection.rst)
+generate_rst(${PROJECT_SOURCE_DIR}/include/ua_plugin_log.h ${DOC_SRC_DIR}/plugin_log.rst)
+generate_rst(${PROJECT_SOURCE_DIR}/include/ua_plugin_network.h ${DOC_SRC_DIR}/plugin_network.rst)
+generate_rst(${PROJECT_SOURCE_DIR}/include/ua_plugin_access_control.h ${DOC_SRC_DIR}/plugin_access_control.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/src/server/ua_services.h ${DOC_SRC_DIR}/services.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/src/server/ua_services.h ${DOC_SRC_DIR}/services.rst)
-generate_rst(${PROJECT_SOURCE_DIR}/src/server/ua_nodestore.h ${DOC_SRC_DIR}/nodestore.rst)
-generate_rst(${PROJECT_SOURCE_DIR}/src/server/ua_nodes.h ${DOC_SRC_DIR}/information_modelling.rst)
+generate_rst(${PROJECT_SOURCE_DIR}/include/ua_plugin_nodestore.h ${DOC_SRC_DIR}/nodestore.rst)
 
 
 # Doc from tutorial code
 # Doc from tutorial code
 generate_rst(${PROJECT_SOURCE_DIR}/examples/tutorial_datatypes.c ${DOC_SRC_DIR}/tutorial_datatypes.rst)
 generate_rst(${PROJECT_SOURCE_DIR}/examples/tutorial_datatypes.c ${DOC_SRC_DIR}/tutorial_datatypes.rst)
@@ -43,9 +43,9 @@ add_custom_target(doc_latex ${SPHINX_EXECUTABLE}
   -b latex "${DOC_SRC_DIR}" "${DOC_LATEX_DIR}"
   -b latex "${DOC_SRC_DIR}" "${DOC_LATEX_DIR}"
   DEPENDS ${DOC_SRC_DIR}/types.rst ${DOC_SRC_DIR}/constants.rst ${DOC_SRC_DIR}/types_generated.rst
   DEPENDS ${DOC_SRC_DIR}/types.rst ${DOC_SRC_DIR}/constants.rst ${DOC_SRC_DIR}/types_generated.rst
           ${DOC_SRC_DIR}/server.rst ${DOC_SRC_DIR}/client.rst ${DOC_SRC_DIR}/client_highlevel.rst
           ${DOC_SRC_DIR}/server.rst ${DOC_SRC_DIR}/client.rst ${DOC_SRC_DIR}/client_highlevel.rst
-          ${DOC_SRC_DIR}/log.rst ${DOC_SRC_DIR}/connection.rst ${DOC_SRC_DIR}/services.rst
-          ${DOC_SRC_DIR}/nodestore.rst ${DOC_SRC_DIR}/information_modelling.rst
-          ${DOC_SRC_DIR}/protocol.rst
+          ${DOC_SRC_DIR}/plugin_log.rst ${DOC_SRC_DIR}/plugin_network.rst
+          ${DOC_SRC_DIR}/services.rst ${DOC_SRC_DIR}/plugin_access_control.rst
+          ${DOC_SRC_DIR}/nodestore.rst
           ${DOC_SRC_DIR}/tutorial_datatypes.rst
           ${DOC_SRC_DIR}/tutorial_datatypes.rst
           ${DOC_SRC_DIR}/tutorial_client_firststeps.rst
           ${DOC_SRC_DIR}/tutorial_client_firststeps.rst
           ${DOC_SRC_DIR}/tutorial_server_firststeps.rst
           ${DOC_SRC_DIR}/tutorial_server_firststeps.rst
@@ -57,10 +57,10 @@ add_custom_target(doc_latex ${SPHINX_EXECUTABLE}
   COMMENT "Building LaTeX sources for documentation with Sphinx")
   COMMENT "Building LaTeX sources for documentation with Sphinx")
 add_dependencies(doc_latex open62541)
 add_dependencies(doc_latex open62541)
 
 
-add_custom_target(doc_pdf ${PDFLATEX_COMPILER} -q "open62541.tex"
+add_custom_target(doc_pdf ${PDFLATEX_COMPILER} --quiet "open62541.tex"
   WORKING_DIRECTORY ${DOC_LATEX_DIR}
   WORKING_DIRECTORY ${DOC_LATEX_DIR}
   # compile it twice so that the contents pages are correct
   # compile it twice so that the contents pages are correct
-  COMMAND ${PDFLATEX_COMPILER} -q "open62541.tex"
+  COMMAND ${PDFLATEX_COMPILER} --quiet "open62541.tex"
   DEPENDS ${PDFLATEX_COMPILER}
   DEPENDS ${PDFLATEX_COMPILER}
   COMMENT "Generating PDF documentation from LaTeX sources")
   COMMENT "Generating PDF documentation from LaTeX sources")
 add_dependencies(doc_pdf doc_latex)
 add_dependencies(doc_pdf doc_latex)
@@ -69,9 +69,9 @@ add_custom_target(doc ${SPHINX_EXECUTABLE}
   -b html "${DOC_SRC_DIR}" "${DOC_HTML_DIR}"
   -b html "${DOC_SRC_DIR}" "${DOC_HTML_DIR}"
   DEPENDS ${DOC_SRC_DIR}/types.rst ${DOC_SRC_DIR}/constants.rst ${DOC_SRC_DIR}/types_generated.rst
   DEPENDS ${DOC_SRC_DIR}/types.rst ${DOC_SRC_DIR}/constants.rst ${DOC_SRC_DIR}/types_generated.rst
           ${DOC_SRC_DIR}/server.rst ${DOC_SRC_DIR}/client.rst ${DOC_SRC_DIR}/client_highlevel.rst
           ${DOC_SRC_DIR}/server.rst ${DOC_SRC_DIR}/client.rst ${DOC_SRC_DIR}/client_highlevel.rst
-          ${DOC_SRC_DIR}/log.rst ${DOC_SRC_DIR}/connection.rst ${DOC_SRC_DIR}/services.rst
-          ${DOC_SRC_DIR}/nodestore.rst ${DOC_SRC_DIR}/information_modelling.rst
-          ${DOC_SRC_DIR}/protocol.rst
+          ${DOC_SRC_DIR}/plugin_log.rst ${DOC_SRC_DIR}/plugin_network.rst
+          ${DOC_SRC_DIR}/services.rst ${DOC_SRC_DIR}/plugin_access_control.rst
+          ${DOC_SRC_DIR}/nodestore.rst
           ${DOC_SRC_DIR}/tutorial_datatypes.rst
           ${DOC_SRC_DIR}/tutorial_datatypes.rst
           ${DOC_SRC_DIR}/tutorial_client_firststeps.rst
           ${DOC_SRC_DIR}/tutorial_client_firststeps.rst
           ${DOC_SRC_DIR}/tutorial_server_firststeps.rst
           ${DOC_SRC_DIR}/tutorial_server_firststeps.rst
@@ -84,3 +84,4 @@ add_custom_target(doc ${SPHINX_EXECUTABLE}
 add_dependencies(doc open62541)
 add_dependencies(doc open62541)
 
 
 set_target_properties(doc doc_latex doc_pdf PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE)
 set_target_properties(doc doc_latex doc_pdf PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE)
+set_target_properties(doc doc_latex doc_pdf PROPERTIES FOLDER "open62541/doc")

+ 60 - 21
doc/building.rst

@@ -22,7 +22,7 @@ Building with CMake on Ubuntu or Debian
 
 
 .. code-block:: bash
 .. code-block:: bash
 
 
-   sudo apt-get install git build-essential gcc pkg-config cmake python
+   sudo apt-get install git build-essential gcc pkg-config cmake python python-six
 
 
    # enable additional features
    # enable additional features
    sudo apt-get install liburcu-dev # for multithreading
    sudo apt-get install liburcu-dev # for multithreading
@@ -52,9 +52,10 @@ with MinGW, just replace the compiler selection in the call to CMake.
 
 
 - Download and install
 - Download and install
 
 
-  - Python 2.7.x (Python 3.x should work, too): https://python.org/downloads
+  - Python 2.7.x (Python 3.x works as well): https://python.org/downloads
+  - Install python-six with the pip package manager (``pip install six``)
   - CMake: http://www.cmake.org/cmake/resources/software.html
   - CMake: http://www.cmake.org/cmake/resources/software.html
-  - Microsoft Visual Studio 2015 Community Edition: https://www.visualstudio.com/products/visual-studio-community-vs
+  - Microsoft Visual Studio: https://www.visualstudio.com/products/visual-studio-community-vs
 
 
 - Download the open62541 sources (using git or as a zipfile from github)
 - Download the open62541 sources (using git or as a zipfile from github)
 - Open a command shell (cmd) and run
 - Open a command shell (cmd) and run
@@ -83,6 +84,7 @@ Building on OS X
 .. code-block:: bash
 .. code-block:: bash
 
 
    brew install cmake
    brew install cmake
+   pip install six # python 2/3 compatibility workarounds
    pip install sphinx # for documentation generation
    pip install sphinx # for documentation generation
    pip install sphinx_rtd_theme # documentation style
    pip install sphinx_rtd_theme # documentation style
    brew install graphviz # for graphics in the documentation
    brew install graphviz # for graphics in the documentation
@@ -120,6 +122,15 @@ The procedure below works on OpenBSD 5.8 with gcc version 4.8.4, cmake version 3
 Build Options
 Build Options
 -------------
 -------------
 
 
+The open62541 project uses CMake to manage the build options, for code
+generation and to generate build projects for the different systems and IDEs.
+The tools *ccmake* or *cmake-gui* can be used to graphically set the build
+options.
+
+Most options can be changed manually in :file:`ua_config.h` (:file:`open62541.h`
+for the single-file release) after the code generation. But usually there is no
+need to adjust them.
+
 Build Type and Logging
 Build Type and Logging
 ^^^^^^^^^^^^^^^^^^^^^^
 ^^^^^^^^^^^^^^^^^^^^^^
 
 
@@ -130,17 +141,15 @@ Build Type and Logging
   - ``MinSizeRel`` -Os optimization without debug symbols
   - ``MinSizeRel`` -Os optimization without debug symbols
 
 
 **UA_LOGLEVEL**
 **UA_LOGLEVEL**
-   The level of logging events that are reported
+   The SDK logs events of the level defined in ``UA_LOGLEVEL`` and above only.
+   The logging event levels are as follows:
 
 
-     - 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 :file:`ua_config.h`. Usually there is no need to adjust them.
+     - 600: Fatal
+     - 500: Error
+     - 400: Warning
+     - 300: Info
+     - 200: Debug
+     - 100: Trace
 
 
 UA_BUILD_* group
 UA_BUILD_* group
 ^^^^^^^^^^^^^^^^
 ^^^^^^^^^^^^^^^^
@@ -173,7 +182,7 @@ This group contains build options related to the supported OPC UA features.
 **UA_ENABLE_NODEMANAGEMENT**
 **UA_ENABLE_NODEMANAGEMENT**
    Enable dynamic addition and removal of nodes at runtime
    Enable dynamic addition and removal of nodes at runtime
 **UA_ENABLE_AMALGAMATION**
 **UA_ENABLE_AMALGAMATION**
-   Compile a single-file release files :file:`open62541.c` and :file:`open62541.h`
+   Compile a single-file release into the files :file:`open62541.c` and :file:`open62541.h`
 **UA_ENABLE_MULTITHREADING**
 **UA_ENABLE_MULTITHREADING**
    Enable multi-threading support
    Enable multi-threading support
 **UA_ENABLE_COVERAGE**
 **UA_ENABLE_COVERAGE**
@@ -183,19 +192,49 @@ Some options are marked as advanced. The advanced options need to be toggled to
 be visible in the cmake GUIs.
 be visible in the cmake GUIs.
 
 
 **UA_ENABLE_TYPENAMES**
 **UA_ENABLE_TYPENAMES**
-   Add the type and member names to the UA_DataType structure
+   Add the type and member names to the UA_DataType structure. Enabled by default.
+**UA_ENABLE_STATUSCODE_DESCRIPTIONS**
+   Compile the human-readable name of the StatusCodes into the binary. Enabled by default.
 **UA_ENABLE_GENERATE_NAMESPACE0**
 **UA_ENABLE_GENERATE_NAMESPACE0**
    Generate and load UA XML Namespace 0 definition
    Generate and load UA XML Namespace 0 definition
    ``UA_GENERATE_NAMESPACE0_FILE`` is used to specify the file for NS0 generation from namespace0 folder. Default value is ``Opc.Ua.NodeSet2.xml``
    ``UA_GENERATE_NAMESPACE0_FILE`` is used to specify the file for NS0 generation from namespace0 folder. Default value is ``Opc.Ua.NodeSet2.xml``
-**UA_ENABLE_EMBEDDED_LIBC**
-   Use a custom implementation of some libc functions that might be missing on embedded targets (e.g. string handling).
-**UA_ENABLE_NONSTANDARD_STATELESS**
-   Enable stateless extension
 **UA_ENABLE_NONSTANDARD_UDP**
 **UA_ENABLE_NONSTANDARD_UDP**
    Enable udp extension
    Enable udp extension
 
 
+UA_DEBUG_* group
+^^^^^^^^^^^^^^^^
+
+This group contains build options mainly useful for development of the library itself.
+
+**UA_DEBUG**
+   Enable assertions and additional definitions not intended for production builds
+
+**UA_DEBUG_DUMP_PKGS**
+   Dump every package received by the server as hexdump format
+
 Building a shared library
 Building a shared library
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
-open62541 is small enough that most users will want to statically link the library into their programs. If a shared library (.dll, .so) is required, this can be enabled in CMake with the `BUILD_SHARED_LIBS` option.
-Note that this option modifies the :file:`ua_config.h` file that is also included in :file:`open62541.h` for the single-file distribution.
+open62541 is small enough that most users will want to statically link the
+library into their programs. If a shared library (.dll, .so) is required, this
+can be enabled in CMake with the ``BUILD_SHARED_LIBS`` option. Note that this
+option modifies the :file:`ua_config.h` file that is also included in
+:file:`open62541.h` for the single-file distribution.
+
+
+Minimizing the binary size
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The size of the generated binary can be reduced considerably by adjusting the
+build configuration. First, in CMake, the build type can be set to
+``CMAKE_BUILD_TYPE=MinSizeRel``. This sets the compiler flags to minimize the
+binary size. The build type also strips out debug information. Second, the
+binary size can be reduced by removing features via the build-flags described
+above.
+
+Especially, logging takes up a lot of space in the binary and might not be
+needed in embedded scenarios. Setting ``UA_LOGLEVEL`` to a value above 600
+(=FATAL) disables all logging. In addition, the feature-flags
+``UA_ENABLE_TYPENAMES`` and ``UA_ENABLE_STATUSCODE_DESCRIPTIONS`` add static
+information to the binary that is only used for human-readable logging and
+debugging.

+ 15 - 10
doc/index.rst

@@ -1,16 +1,21 @@
 Introduction
 Introduction
 ============
 ============
 
 
-open62541 (http://open62541.org) is an open source implementation of OPC UA
-(short for OPC Unified Architecture). open62541 is a C-based library (linking
-with C++ projects is possible) with all necessary tools to implement dedicated
-OPC UA clients and servers, or to integrate OPC UA-based communication into
-existing applications. open62541 is licensed under Mozilla Public License v2.0.
-So the *open62541 library can be used in projects that are
-not open source*. However, changes to the open62541 library itself need to
-published under the same license. The plugins, as well as the provided example
-servers and clients are in the public domain (CC0 license). They can be reused
-under any license and changes do not have to be published.
+open62541 (http://open62541.org) is an open source and free implementation of
+OPC UA (OPC Unified Architecture) written in the common subset of the C99 and
+C++98 languages. The library is usable with all major compilers and provides the
+necessary tools to implement dedicated OPC UA clients and servers, or to
+integrate OPC UA-based communication into existing applications. open62541
+library is platform independent. All platform-specific functionality is
+implemented via exchangeable plugins. Plugin implementations are provided for
+the major operating systems.
+
+open62541 is licensed under the Mozilla Public License v2.0. So the *open62541
+library can be used in projects that are not open source*. Only changes to the
+open62541 library itself need to published under the same license. The plugins,
+as well as the server and client examples are in the public domain (CC0
+license). They can be reused under any license and changes do not have to be
+published.
 
 
 OPC Unified Architecture
 OPC Unified Architecture
 ------------------------
 ------------------------

+ 3 - 3
doc/internal.rst

@@ -3,6 +3,6 @@ Internals
 
 
 .. toctree::
 .. toctree::
 
 
-   nodestore
-   connection
-   log
+   plugin_network
+   plugin_access_control
+   plugin_log

+ 4 - 5
doc/namespace_compiler.rst

@@ -41,7 +41,7 @@ We take the following information model snippet as the starting point of the fol
                     i=33
                     i=33
                 </Reference>
                 </Reference>
             </References>
             </References>
-            <InverseName Locale="en_US">inputProcidedBy</InverseName>
+            <InverseName Locale="en-US">inputProcidedBy</InverseName>
         </UAReferenceType>
         </UAReferenceType>
         <UAObjectType IsAbstract="true" NodeId="ns=1;i=1001"
         <UAObjectType IsAbstract="true" NodeId="ns=1;i=1001"
                       BrowseName="1:FieldDevice">
                       BrowseName="1:FieldDevice">
@@ -318,11 +318,10 @@ Let's look at an example that will create a pump instance given the newly define
 
 
       UA_NodeId createdNodeId;
       UA_NodeId createdNodeId;
       UA_Int32 myHandle = 42;
       UA_Int32 myHandle = 42;
-      UA_ObjectAttributes object_attr;
-      UA_ObjectAttributes_init(&object_attr);
+      UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
       
       
-      object_attr.description = UA_LOCALIZEDTEXT("en_US","A pump!");
-      object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Pump1");
+      object_attr.description = UA_LOCALIZEDTEXT("en-US","A pump!");
+      object_attr.displayName = UA_LOCALIZEDTEXT("en-US","Pump1");
       
       
       UA_InstantiationCallback theAnswerCallback;
       UA_InstantiationCallback theAnswerCallback;
       theAnswerCallback.method = pumpInstantiationCallback;
       theAnswerCallback.method = pumpInstantiationCallback;

+ 1 - 1
doc/toc.rst

@@ -8,8 +8,8 @@ open62541 Documentation
    tutorials
    tutorials
    protocol
    protocol
    types
    types
-   information_modelling
    services
    services
+   nodestore
    server
    server
    client
    client
    constants
    constants

+ 63 - 65
examples/CMakeLists.txt

@@ -1,94 +1,81 @@
-include_directories(${PROJECT_BINARY_DIR}
-                    ${PROJECT_BINARY_DIR}/src_generated
-                    ${PROJECT_SOURCE_DIR}/plugins)
+include_directories(${PROJECT_SOURCE_DIR}/include)
+include_directories(${PROJECT_SOURCE_DIR}/plugins)
+include_directories(${PROJECT_BINARY_DIR})
+
+#############################
+# Compiled binaries folders #
+#############################
+
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/examples)
+
+macro(add_example EXAMPLE_NAME EXAMPLE_SOURCE)
+  add_executable(${EXAMPLE_NAME} ${STATIC_OBJECTS} ${EXAMPLE_SOURCE} ${ARGN})
+  target_link_libraries(${EXAMPLE_NAME} open62541 ${open62541_LIBRARIES})
+  assign_source_group(${EXAMPLE_SOURCE})
+  add_dependencies(${EXAMPLE_NAME} open62541-amalgamation-header open62541-amalgamation-source)
+  set_target_properties(${EXAMPLE_NAME} PROPERTIES FOLDER "open62541/examples")
+  set_target_properties(${EXAMPLE_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/bin/examples")
+  if(UA_COMPILE_AS_CXX)
+    set_source_files_properties(${EXAMPLE_SOURCE} PROPERTIES LANGUAGE CXX)
+  endif()
+endmacro()
 
 
 #############
 #############
 # Tutorials #
 # Tutorials #
 #############
 #############
 
 
-add_executable(tutorial_datatypes tutorial_datatypes.c)
-target_link_libraries(tutorial_datatypes open62541 ${open62541_LIBRARIES})
+add_example(tutorial_datatypes tutorial_datatypes.c)
 
 
-add_executable(tutorial_server_firststeps tutorial_server_firststeps.c)
-target_link_libraries(tutorial_server_firststeps open62541 ${open62541_LIBRARIES})
+add_example(tutorial_server_firststeps tutorial_server_firststeps.c)
 
 
-add_executable(tutorial_server_variable tutorial_server_variable.c)
-target_link_libraries(tutorial_server_variable open62541 ${open62541_LIBRARIES})
+add_example(tutorial_server_variable tutorial_server_variable.c)
 
 
-add_executable(tutorial_server_datasource tutorial_server_datasource.c)
-target_link_libraries(tutorial_server_datasource open62541 ${open62541_LIBRARIES})
+add_example(tutorial_server_datasource tutorial_server_datasource.c)
 
 
-add_executable(tutorial_server_variabletype tutorial_server_variabletype.c)
-target_link_libraries(tutorial_server_variabletype open62541 ${open62541_LIBRARIES})
+add_example(tutorial_server_variabletype tutorial_server_variabletype.c)
 
 
-add_executable(tutorial_server_object tutorial_server_object.c)
-target_link_libraries(tutorial_server_object open62541 ${open62541_LIBRARIES})
+add_example(tutorial_server_object tutorial_server_object.c)
 
 
 if(UA_ENABLE_METHODCALLS)
 if(UA_ENABLE_METHODCALLS)
-  add_executable(tutorial_server_method tutorial_server_method.c)
-  target_link_libraries(tutorial_server_method open62541 ${open62541_LIBRARIES})
+  add_example(tutorial_server_method tutorial_server_method.c)
 endif()
 endif()
 
 
-add_executable(tutorial_client_firststeps tutorial_client_firststeps.c)
-target_link_libraries(tutorial_client_firststeps open62541 ${open62541_LIBRARIES})
+add_example(tutorial_client_firststeps tutorial_client_firststeps.c)
+
+add_example(tutorial_client_events tutorial_client_events.c)
 
 
 ##################
 ##################
 # Example Server #
 # Example Server #
 ##################
 ##################
 
 
-add_executable(server server.c)
-target_link_libraries(server open62541 ${open62541_LIBRARIES})
-
-if(UA_ENABLE_NONSTANDARD_UDP)
-  add_executable(server_udp server_udp.c ${PROJECT_SOURCE_DIR}/plugins/ua_network_udp.c)
-  target_link_libraries(server_udp open62541 ${open62541_LIBRARIES})
-endif()
+add_example(server server.c)
 
 
 ##################
 ##################
 # Example Client #
 # Example Client #
 ##################
 ##################
 
 
-add_executable(client client.c)
-target_link_libraries(client open62541 ${open62541_LIBRARIES})
+add_example(client client.c)
+
+add_example(client_connect_loop client_connect_loop.c)
 
 
 ####################
 ####################
 # Feature Examples #
 # Feature Examples #
 ####################
 ####################
 
 
-add_executable(server_mainloop server_mainloop.c)
-target_link_libraries(server_mainloop open62541 ${open62541_LIBRARIES})
-
-add_executable(server_instantiation server_instantiation.c)
-target_link_libraries(server_instantiation open62541 ${open62541_LIBRARIES})
-
-add_executable(server_repeated_job server_repeated_job.c)
-target_link_libraries(server_repeated_job open62541 ${open62541_LIBRARIES})
-
-add_executable(server_inheritance server_inheritance.c)
-target_link_libraries(server_inheritance open62541 ${open62541_LIBRARIES})
-
-if(NOT BUILD_SHARED_open62541_LIBRARIES AND UA_BUILD_EXAMPLES_NODESET_COMPILER)
-  # example information model from nodeset xml
-  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/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)
-						  
-  # needs internal methods which are not exported in the dynamic lib
-  add_executable(server_nodeset server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/nodeset.c)
-  target_link_libraries(server_nodeset open62541 ${open62541_LIBRARIES})
-  target_include_directories(server_nodeset PRIVATE ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/deps) # needs an internal header
+add_example(server_mainloop server_mainloop.c)
+
+add_example(server_instantiation server_instantiation.c)
+
+add_example(server_repeated_job server_repeated_job.c)
+
+add_example(server_inheritance server_inheritance.c)
+
+add_example(custom_datatype_client custom_datatype/client_types_custom.c)
+add_example(custom_datatype_server custom_datatype/server_types_custom.c)
+
+if(UA_ENABLE_NODEMANAGEMENT)
+    add_example(access_control_server access_control/server_access_control.c)
+    add_example(access_control_client access_control/client_access_control.c)
 endif()
 endif()
 
 
 if(UA_BUILD_SELFSIGNED_CERTIFICATE)
 if(UA_BUILD_SELFSIGNED_CERTIFICATE)
@@ -97,9 +84,20 @@ if(UA_BUILD_SELFSIGNED_CERTIFICATE)
                      COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py ${CMAKE_CURRENT_BINARY_DIR}
                      COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py ${CMAKE_CURRENT_BINARY_DIR}
                      DEPENDS ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py
                      DEPENDS ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py
                              ${PROJECT_SOURCE_DIR}/tools/certs/localhost.cnf)
                              ${PROJECT_SOURCE_DIR}/tools/certs/localhost.cnf)
-                             
   add_custom_target(selfsigned ALL DEPENDS server_cert.der ca.crt)
   add_custom_target(selfsigned ALL DEPENDS server_cert.der ca.crt)
-
-  add_executable(server_certificate server_certificate.c server_cert.der ca.crt)
+  add_executable(server_certificate server_certificate.c ${STATIC_OBJECTS} server_cert.der ca.crt)
   target_link_libraries(server_certificate open62541 ${open62541_LIBRARIES})
   target_link_libraries(server_certificate open62541 ${open62541_LIBRARIES})
 endif()
 endif()
+
+if(UA_ENABLE_DISCOVERY)
+    add_example(discovery_server_lds discovery/server_lds.c)
+
+    add_example(discovery_server_register discovery/server_register.c)
+
+    add_example(discovery_client_find_servers discovery/client_find_servers.c)
+    if(UA_ENABLE_DISCOVERY_MULTICAST)
+        add_example(discovery_server_multicast discovery/server_multicast.c)
+    endif()
+endif()
+
+add_subdirectory(nodeset)

+ 67 - 0
examples/access_control/client_access_control.c

@@ -0,0 +1,67 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+/**
+ * Using access_control_server
+ */
+
+#include <stdio.h>
+
+#include "open62541.h"
+
+int main(void) {
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+    UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Client_delete(client);
+        return (int)retval;
+    }
+
+    UA_NodeId newVariableIdRequest = UA_NODEID_NUMERIC(1, 1001);
+    UA_NodeId newVariableId = UA_NODEID_NULL;
+
+    UA_VariableAttributes newVariableAttributes = UA_VariableAttributes_default;
+
+    newVariableAttributes.accessLevel = UA_ACCESSLEVELMASK_READ;
+    newVariableAttributes.description = UA_LOCALIZEDTEXT_ALLOC("en-US", "NewVariable desc");
+    newVariableAttributes.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", "NewVariable");
+    newVariableAttributes.dataType = UA_TYPES[UA_TYPES_UINT32].typeId;
+    {
+        UA_UInt32 value = 50;
+        UA_Variant_setScalarCopy(&newVariableAttributes.value, &value, &UA_TYPES[UA_TYPES_UINT32]);
+    }
+
+    UA_StatusCode retCode;
+
+    retCode = UA_Client_addVariableNode(client, newVariableIdRequest,
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                            UA_QUALIFIEDNAME(1, "newVariable"),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                            newVariableAttributes, &newVariableId);
+
+    printf("addVariable returned: %s\n", UA_StatusCode_name(retCode));
+
+    UA_ExpandedNodeId extNodeId = UA_EXPANDEDNODEID_NUMERIC(0, 0);
+    extNodeId.nodeId = newVariableId;
+
+    retCode = UA_Client_addReference(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_TRUE,
+                            UA_STRING_NULL, extNodeId, UA_NODECLASS_VARIABLE);
+
+    printf("addReference returned: %s\n", UA_StatusCode_name(retCode));
+
+    retCode = UA_Client_deleteReference(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_TRUE, extNodeId,
+                            UA_TRUE);
+
+    printf("deleteReference returned: %s\n", UA_StatusCode_name(retCode));
+
+    retCode = UA_Client_deleteNode(client, newVariableId, UA_TRUE);
+    printf("deleteNode returned: %s\n", UA_StatusCode_name(retCode));
+
+    /* Clean up */
+    UA_VariableAttributes_deleteMembers(&newVariableAttributes);
+    UA_Client_delete(client); /* Disconnects the client internally */
+    return UA_STATUSCODE_GOOD;
+}

+ 65 - 0
examples/access_control/server_access_control.c

@@ -0,0 +1,65 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include <signal.h>
+#include <stdio.h>
+
+#include "open62541.h"
+
+static UA_Boolean
+allowAddNode(const UA_NodeId *sessionId, void *sessionContext,
+    const UA_AddNodesItem *item)
+{
+    printf("Called allowAddNode\n");
+    return UA_TRUE;
+}
+
+static UA_Boolean
+allowAddReference(const UA_NodeId *sessionId, void *sessionContext,
+    const UA_AddReferencesItem *item)
+{
+    printf("Called allowAddReference\n");
+    return UA_TRUE;
+}
+
+static UA_Boolean
+allowDeleteNode(const UA_NodeId *sessionId, void *sessionContext,
+    const UA_DeleteNodesItem *item)
+{
+    printf("Called allowDeleteNode\n");
+    return UA_FALSE; // Do not allow deletion from client
+}
+
+static UA_Boolean
+allowDeleteReference(const UA_NodeId *sessionId, void *sessionContext,
+    const UA_DeleteReferencesItem *item)
+{
+    printf("Called allowDeleteReference\n");
+    return UA_TRUE;
+}
+
+UA_Boolean running = true;
+static void stopHandler(int sign) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = false;
+}
+
+int main(void) {
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
+
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
+
+    // Set accessControl functions for nodeManagement
+    config->accessControl.allowAddNode = allowAddNode;
+    config->accessControl.allowAddReference = allowAddReference;
+    config->accessControl.allowDeleteNode = allowDeleteNode;
+    config->accessControl.allowDeleteReference = allowDeleteReference;
+
+    UA_Server *server = UA_Server_new(config);
+
+    UA_StatusCode retval = UA_Server_run(server, &running);
+    UA_Server_delete(server);
+    UA_ServerConfig_delete(config);
+    return (int)retval;
+}

+ 21 - 35
examples/client.c

@@ -1,25 +1,15 @@
 /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 
-#ifdef UA_NO_AMALGAMATION
-# include "ua_types.h"
-# include "ua_client.h"
-# include "ua_client_highlevel.h"
-# include "ua_nodeids.h"
-# include "ua_network_tcp.h"
-# include "ua_config_standard.h"
-#else
-# include "open62541.h"
-# include <string.h>
-# include <stdlib.h>
-#endif
-
 #include <stdio.h>
 #include <stdio.h>
+#include "open62541.h"
 
 
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 static void
 static void
 handler_TheAnswerChanged(UA_UInt32 monId, UA_DataValue *value, void *context) {
 handler_TheAnswerChanged(UA_UInt32 monId, UA_DataValue *value, void *context) {
     printf("The Answer has changed!\n");
     printf("The Answer has changed!\n");
 }
 }
+#endif
 
 
 static UA_StatusCode
 static UA_StatusCode
 nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) {
 nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) {
@@ -34,12 +24,12 @@ nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, voi
 }
 }
 
 
 int main(int argc, char *argv[]) {
 int main(int argc, char *argv[]) {
-    UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
 
 
     /* Listing endpoints */
     /* Listing endpoints */
     UA_EndpointDescription* endpointArray = NULL;
     UA_EndpointDescription* endpointArray = NULL;
     size_t endpointArraySize = 0;
     size_t endpointArraySize = 0;
-    UA_StatusCode retval = UA_Client_getEndpoints(client, "opc.tcp://localhost:16664",
+    UA_StatusCode retval = UA_Client_getEndpoints(client, "opc.tcp://localhost:4840",
                                                   &endpointArraySize, &endpointArray);
                                                   &endpointArraySize, &endpointArray);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
         UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
@@ -55,8 +45,8 @@ int main(int argc, char *argv[]) {
     UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
     UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
 
 
     /* Connect to a server */
     /* Connect to a server */
-    /* anonymous connect would be: retval = UA_Client_connect(client, "opc.tcp://localhost:16664"); */
-    retval = UA_Client_connect_username(client, "opc.tcp://localhost:16664", "user1", "password");
+    /* anonymous connect would be: retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); */
+    retval = UA_Client_connect_username(client, "opc.tcp://localhost:4840", "user1", "password");
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         UA_Client_delete(client);
         return (int)retval;
         return (int)retval;
@@ -104,7 +94,7 @@ int main(int argc, char *argv[]) {
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     /* Create a subscription */
     /* Create a subscription */
     UA_UInt32 subId = 0;
     UA_UInt32 subId = 0;
-    UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_standard, &subId);
+    UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_default, &subId);
     if(subId)
     if(subId)
         printf("Create subscription succeeded, id %u\n", subId);
         printf("Create subscription succeeded, id %u\n", subId);
     /* Add a MonitoredItem */
     /* Add a MonitoredItem */
@@ -188,11 +178,10 @@ int main(int argc, char *argv[]) {
     /* Add new nodes*/
     /* Add new nodes*/
     /* New ReferenceType */
     /* New ReferenceType */
     UA_NodeId ref_id;
     UA_NodeId ref_id;
-    UA_ReferenceTypeAttributes ref_attr;
-    UA_ReferenceTypeAttributes_init(&ref_attr);
-    ref_attr.displayName = UA_LOCALIZEDTEXT("en_US", "NewReference");
-    ref_attr.description = UA_LOCALIZEDTEXT("en_US", "References something that might or might not exist");
-    ref_attr.inverseName = UA_LOCALIZEDTEXT("en_US", "IsNewlyReferencedBy");
+    UA_ReferenceTypeAttributes ref_attr = UA_ReferenceTypeAttributes_default;
+    ref_attr.displayName = UA_LOCALIZEDTEXT("en-US", "NewReference");
+    ref_attr.description = UA_LOCALIZEDTEXT("en-US", "References something that might or might not exist");
+    ref_attr.inverseName = UA_LOCALIZEDTEXT("en-US", "IsNewlyReferencedBy");
     retval = UA_Client_addReferenceTypeNode(client,
     retval = UA_Client_addReferenceTypeNode(client,
                                             UA_NODEID_NUMERIC(1, 12133),
                                             UA_NODEID_NUMERIC(1, 12133),
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
@@ -204,10 +193,9 @@ int main(int argc, char *argv[]) {
 
 
     /* New ObjectType */
     /* New ObjectType */
     UA_NodeId objt_id;
     UA_NodeId objt_id;
-    UA_ObjectTypeAttributes objt_attr;
-    UA_ObjectTypeAttributes_init(&objt_attr);
-    objt_attr.displayName = UA_LOCALIZEDTEXT("en_US", "TheNewObjectType");
-    objt_attr.description = UA_LOCALIZEDTEXT("en_US", "Put innovative description here");
+    UA_ObjectTypeAttributes objt_attr = UA_ObjectTypeAttributes_default;
+    objt_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewObjectType");
+    objt_attr.description = UA_LOCALIZEDTEXT("en-US", "Put innovative description here");
     retval = UA_Client_addObjectTypeNode(client,
     retval = UA_Client_addObjectTypeNode(client,
                                          UA_NODEID_NUMERIC(1, 12134),
                                          UA_NODEID_NUMERIC(1, 12134),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
@@ -219,10 +207,9 @@ int main(int argc, char *argv[]) {
 
 
     /* New Object */
     /* New Object */
     UA_NodeId obj_id;
     UA_NodeId obj_id;
-    UA_ObjectAttributes obj_attr;
-    UA_ObjectAttributes_init(&obj_attr);
-    obj_attr.displayName = UA_LOCALIZEDTEXT("en_US", "TheNewGreatNode");
-    obj_attr.description = UA_LOCALIZEDTEXT("de_DE", "Hier koennte Ihre Webung stehen!");
+    UA_ObjectAttributes obj_attr = UA_ObjectAttributes_default;
+    obj_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewGreatNode");
+    obj_attr.description = UA_LOCALIZEDTEXT("de-DE", "Hier koennte Ihre Webung stehen!");
     retval = UA_Client_addObjectNode(client,
     retval = UA_Client_addObjectNode(client,
                                      UA_NODEID_NUMERIC(1, 0),
                                      UA_NODEID_NUMERIC(1, 0),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
@@ -235,11 +222,10 @@ int main(int argc, char *argv[]) {
 
 
     /* New Integer Variable */
     /* New Integer Variable */
     UA_NodeId var_id;
     UA_NodeId var_id;
-    UA_VariableAttributes var_attr;
-    UA_VariableAttributes_init(&var_attr);
-    var_attr.displayName = UA_LOCALIZEDTEXT("en_US", "TheNewVariableNode");
+    UA_VariableAttributes var_attr = UA_VariableAttributes_default;
+    var_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewVariableNode");
     var_attr.description =
     var_attr.description =
-        UA_LOCALIZEDTEXT("en_US", "This integer is just amazing - it has digits and everything.");
+        UA_LOCALIZEDTEXT("en-US", "This integer is just amazing - it has digits and everything.");
     UA_Int32 int_value = 1234;
     UA_Int32 int_value = 1234;
     /* This does not copy the value */
     /* This does not copy the value */
     UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);

+ 95 - 0
examples/client_connect_loop.c

@@ -0,0 +1,95 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+/* Enable POSIX features */
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+#ifndef _DEFAULT_SOURCE
+# define _DEFAULT_SOURCE
+#endif
+/* On older systems we need to define _BSD_SOURCE.
+ * _DEFAULT_SOURCE is an alias for that. */
+#ifndef _BSD_SOURCE
+# define _BSD_SOURCE
+#endif
+
+/**
+ * Client disconnect handling
+ * --------------------------
+ * This example shows you how to handle a client disconnect, e.g., if the server
+ * is shut down while the client is connected. You just need to call connect
+ * again and the client will automatically reconnect.
+ *
+ * This example is very similar to the tutorial_client_firststeps.c. */
+
+#include "open62541.h"
+#include <signal.h>
+
+#ifdef _WIN32
+# include <windows.h>
+# define UA_sleep_ms(X) Sleep(X)
+#else
+# include <unistd.h>
+# define UA_sleep_ms(X) usleep(X * 1000)
+#endif
+
+UA_Boolean running = true;
+UA_Logger logger = UA_Log_Stdout;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_CLIENT, "Received Ctrl-C");
+    running = 0;
+}
+
+int main(void) {
+    signal(SIGINT, stopHandler); /* catches ctrl-c */
+
+    UA_ClientConfig config = UA_ClientConfig_default;
+    /* default timeout is 5 seconds. Set it to 1 second here for demo */
+    config.timeout = 1000;
+    UA_Client *client = UA_Client_new(config);
+
+    /* Read the value attribute of the node. UA_Client_readValueAttribute is a
+     * wrapper for the raw read service available as UA_Client_Service_read. */
+    UA_Variant value; /* Variants can hold scalar values and arrays of any type */
+    UA_Variant_init(&value);
+
+    /* Endless loop reading the server time */
+    while (running) {
+        /* if already connected, this will return GOOD and do nothing */
+        /* if the connection is closed/errored, the connection will be reset and then reconnected */
+        /* Alternatively you can also use UA_Client_getState to get the current state */
+        UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
+        if (retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_ERROR(logger, UA_LOGCATEGORY_CLIENT, "Not connected. Retrying to connect in 1 second");
+            /* The connect may timeout after 1 second (see above) or it may fail immediately on network errors */
+            /* E.g. name resolution errors or unreachable network. Thus there should be a small sleep here */
+            UA_sleep_ms(1000);
+            continue;
+        }
+
+        /* NodeId of the variable holding the current time */
+        const UA_NodeId nodeId =
+                UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+
+        retval = UA_Client_readValueAttribute(client, nodeId, &value);
+        if (retval == UA_STATUSCODE_BADCONNECTIONCLOSED) {
+            UA_LOG_ERROR(logger, UA_LOGCATEGORY_CLIENT, "Connection was closed. Reconnecting ...");
+            continue;
+        }
+        if (retval == UA_STATUSCODE_GOOD &&
+            UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME])) {
+            UA_DateTime raw_date = *(UA_DateTime *) value.data;
+            UA_String string_date = UA_DateTime_toString(raw_date);
+            UA_LOG_INFO(logger, UA_LOGCATEGORY_CLIENT, "string date is: %.*s", (int) string_date.length, string_date.data);
+            UA_String_deleteMembers(&string_date);
+        }
+        UA_sleep_ms(1000);
+    };
+
+    /* Clean up */
+    UA_Variant_deleteMembers(&value);
+    UA_Client_delete(client); /* Disconnects the client internally */
+    return UA_STATUSCODE_GOOD;
+}

+ 41 - 0
examples/custom_datatype/client_types_custom.c

@@ -0,0 +1,41 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include <stdio.h>
+#include "open62541.h"
+#include "custom_datatype.h"
+
+int main(void) {
+    UA_ClientConfig config = UA_ClientConfig_default;
+
+    /* Make your custom datatype known to the stack */
+    UA_DataType types[1];
+    types[0] = PointType;
+    config.customDataTypes = types;
+    config.customDataTypesSize = 1;
+
+    UA_Client *client = UA_Client_new(config);
+    UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
+    if (retval != UA_STATUSCODE_GOOD) {
+        UA_Client_delete(client);
+        return (int)retval;
+    }
+    
+    UA_Variant value; /* Variants can hold scalar values and arrays of any type */
+    UA_Variant_init(&value);
+    
+     UA_NodeId nodeId =
+        UA_NODEID_STRING(1, "3D.Point");
+
+    retval = UA_Client_readValueAttribute(client, nodeId, &value);
+            
+    if (retval == UA_STATUSCODE_GOOD) {
+        Point *p = (Point *)value.data;
+        printf("Point = %f, %f, %f \n", p->x, p->y, p->z);
+    }
+
+    /* Clean up */
+    UA_Variant_deleteMembers(&value);
+    UA_Client_delete(client); /* Disconnects the client internally */
+    return UA_STATUSCODE_GOOD;
+}

+ 51 - 0
examples/custom_datatype/custom_datatype.h

@@ -0,0 +1,51 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+typedef struct {
+    UA_Float x;
+    UA_Float y;
+    UA_Float z;
+} Point;
+
+/* The datatype description for the Point datatype */
+#define Point_padding_y offsetof(Point,y) - offsetof(Point,x) - sizeof(UA_Float)
+#define Point_padding_z offsetof(Point,z) - offsetof(Point,y) - sizeof(UA_Float)
+
+static UA_DataTypeMember Point_members[3] = {
+        /* x */
+        {
+                UA_TYPENAME("x") /* .memberName */
+                UA_TYPES_FLOAT,  /* .memberTypeIndex, points into UA_TYPES since namespaceZero is true */
+                0,               /* .padding */
+                true,            /* .namespaceZero, see .memberTypeIndex */
+                false            /* .isArray */
+        },
+
+        /* y */
+        {
+                UA_TYPENAME("y")
+                UA_TYPES_FLOAT, Point_padding_y, true, false
+        },
+
+        /* z */
+        {
+                UA_TYPENAME("z")
+                UA_TYPES_FLOAT, Point_padding_z, true, false
+        }
+};
+
+static const UA_DataType PointType = {
+        UA_TYPENAME("Point")             /* .typeName */
+        {1, UA_NODEIDTYPE_NUMERIC, {4242}}, /* .typeId */
+        sizeof(Point),                   /* .memSize */
+        0,                               /* .typeIndex, in the array of custom types */
+        3,                               /* .membersSize */
+        false,                           /* .builtin */
+        true,                            /* .pointerFree */
+        false,                           /* .overlayable (depends on endianness and
+                                         the absence of padding) */
+        0,                               /* .binaryEncodingId, the numeric
+                                         identifier used on the wire (the
+                                         namespaceindex is from .typeId) */
+        Point_members
+};

+ 86 - 0
examples/custom_datatype/server_types_custom.c

@@ -0,0 +1,86 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include <signal.h>
+#include <open62541.h>
+#include "custom_datatype.h"
+
+UA_Boolean running = true;
+
+static void stopHandler(int sig) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
+    running = false;
+}
+
+static void
+add3PointDataType(UA_Server *server) {
+    UA_VariableTypeAttributes dattr = UA_VariableTypeAttributes_default;
+    dattr.description = UA_LOCALIZEDTEXT("en-US", "3D Point");
+    dattr.displayName = UA_LOCALIZEDTEXT("en-US", "3D Point");
+    dattr.dataType = PointType.typeId;
+    dattr.valueRank = -1;
+
+    Point p;
+    p.x = 0.0;
+    p.y = 0.0;
+    p.z = 0.0;
+    UA_Variant_setScalar(&dattr.value, &p, &PointType);
+
+
+    UA_Server_addVariableTypeNode(server, PointType.typeId,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                  UA_QUALIFIEDNAME(1, "3D.Point"),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                  dattr,
+                                  NULL, NULL
+    );
+
+}
+
+static void
+add3DPointVariable(UA_Server *server) {
+    Point p;
+    p.x = 3.0;
+    p.y = 4.0;
+    p.z = 5.0;
+    UA_VariableAttributes vattr = UA_VariableAttributes_default;
+    vattr.description = UA_LOCALIZEDTEXT("en-US", "3D Point");
+    vattr.displayName = UA_LOCALIZEDTEXT("en-US", "3D Point");
+    vattr.dataType = PointType.typeId;
+    vattr.valueRank = -1;
+    UA_Variant_setScalar(&vattr.value, &p, &PointType);
+
+    UA_Server_addVariableNode(server, UA_NODEID_STRING(1, "3D.Point"),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                              UA_QUALIFIEDNAME(1, "3D.Point"),
+                              PointType.typeId,
+                              vattr,
+                              NULL,
+                              NULL
+    );
+}
+
+int main(void) {
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
+
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
+    /* Make your custom datatype known to the stack */
+    UA_DataType types[1];
+    types[0] = PointType;
+    config->customDataTypes = types;
+    config->customDataTypesSize = 1;
+
+    UA_Server *server = UA_Server_new(config);
+
+    add3PointDataType(server);
+    add3DPointVariable(server);
+
+    UA_Server_run(server, &running);
+
+    UA_Server_delete(server);
+    UA_ServerConfig_delete(config);
+    return 0;
+}

+ 186 - 0
examples/discovery/client_find_servers.c

@@ -0,0 +1,186 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+/**
+ * This client requests all the available servers from the discovery server (see server_lds.c)
+ * and then calls GetEndpoints on the returned list of servers.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <open62541.h>
+
+UA_Logger logger = UA_Log_Stdout;
+
+#define DISCOVERY_SERVER_ENDPOINT "opc.tcp://localhost:4840"
+
+int main(void) {
+
+    /*
+     * Example for calling FindServersOnNetwork
+     */
+
+    {
+        UA_ServerOnNetwork *serverOnNetwork = NULL;
+        size_t serverOnNetworkSize = 0;
+
+        UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+        UA_StatusCode retval = UA_Client_findServersOnNetwork(client, DISCOVERY_SERVER_ENDPOINT, 0, 0,
+                                                              0, NULL, &serverOnNetworkSize, &serverOnNetwork);
+        if (retval != UA_STATUSCODE_GOOD) {
+            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
+                         "Could not call FindServersOnNetwork service. "
+                         "Is the discovery server started? StatusCode %s",
+                         UA_StatusCode_name(retval));
+            UA_Client_delete(client);
+            return (int) retval;
+        }
+
+        // output all the returned/registered servers
+        for (size_t i = 0; i < serverOnNetworkSize; i++) {
+            UA_ServerOnNetwork *server = &serverOnNetwork[i];
+            printf("Server[%lu]: %.*s", (unsigned long) i,
+                   (int) server->serverName.length, server->serverName.data);
+            printf("\n\tRecordID: %d", server->recordId);
+            printf("\n\tDiscovery URL: %.*s", (int) server->discoveryUrl.length,
+                   server->discoveryUrl.data);
+            printf("\n\tCapabilities: ");
+            for (size_t j = 0; j < server->serverCapabilitiesSize; j++) {
+                printf("%.*s,", (int) server->serverCapabilities[j].length,
+                       server->serverCapabilities[j].data);
+            }
+            printf("\n\n");
+        }
+
+        UA_Array_delete(serverOnNetwork, serverOnNetworkSize,
+                        &UA_TYPES[UA_TYPES_SERVERONNETWORK]);
+    }
+
+    /* Example for calling FindServers */
+    UA_ApplicationDescription *applicationDescriptionArray = NULL;
+    size_t applicationDescriptionArraySize = 0;
+
+    UA_StatusCode retval;
+    {
+        UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+        retval = UA_Client_findServers(client, DISCOVERY_SERVER_ENDPOINT, 0, NULL, 0, NULL,
+                                       &applicationDescriptionArraySize, &applicationDescriptionArray);
+        UA_Client_delete(client);
+    }
+    if (retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not call FindServers service. "
+                "Is the discovery server started? StatusCode %s", UA_StatusCode_name(retval));
+        return (int) retval;
+    }
+
+    // output all the returned/registered servers
+    for (size_t i = 0; i < applicationDescriptionArraySize; i++) {
+        UA_ApplicationDescription *description = &applicationDescriptionArray[i];
+        printf("Server[%lu]: %.*s", (unsigned long) i, (int) description->applicationUri.length,
+               description->applicationUri.data);
+        printf("\n\tName: %.*s", (int) description->applicationName.text.length,
+               description->applicationName.text.data);
+        printf("\n\tApplication URI: %.*s", (int) description->applicationUri.length,
+               description->applicationUri.data);
+        printf("\n\tProduct URI: %.*s", (int) description->productUri.length,
+               description->productUri.data);
+        printf("\n\tType: ");
+        switch (description->applicationType) {
+            case UA_APPLICATIONTYPE_SERVER:
+                printf("Server");
+                break;
+            case UA_APPLICATIONTYPE_CLIENT:
+                printf("Client");
+                break;
+            case UA_APPLICATIONTYPE_CLIENTANDSERVER:
+                printf("Client and Server");
+                break;
+            case UA_APPLICATIONTYPE_DISCOVERYSERVER:
+                printf("Discovery Server");
+                break;
+            default:
+                printf("Unknown");
+        }
+        printf("\n\tDiscovery URLs:");
+        for (size_t j = 0; j < description->discoveryUrlsSize; j++) {
+            printf("\n\t\t[%lu]: %.*s", (unsigned long) j,
+                   (int) description->discoveryUrls[j].length,
+                   description->discoveryUrls[j].data);
+        }
+        printf("\n\n");
+    }
+
+
+    /*
+     * Now that we have the list of available servers, call get endpoints on all of them
+     */
+
+    printf("-------- Server Endpoints --------\n");
+
+    for (size_t i = 0; i < applicationDescriptionArraySize; i++) {
+        UA_ApplicationDescription *description = &applicationDescriptionArray[i];
+        if (description->discoveryUrlsSize == 0) {
+            UA_LOG_INFO(logger, UA_LOGCATEGORY_CLIENT,
+                        "[GetEndpoints] Server %.*s did not provide any discovery urls. Skipping.",
+                        (int)description->applicationUri.length, description->applicationUri.data);
+            continue;
+        }
+
+        printf("\nEndpoints for Server[%lu]: %.*s\n", (unsigned long) i,
+               (int) description->applicationUri.length, description->applicationUri.data);
+
+        UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+
+        char *discoveryUrl = (char *) UA_malloc(sizeof(char) * description->discoveryUrls[0].length + 1);
+        memcpy(discoveryUrl, description->discoveryUrls[0].data, description->discoveryUrls[0].length);
+        discoveryUrl[description->discoveryUrls[0].length] = '\0';
+
+        UA_EndpointDescription *endpointArray = NULL;
+        size_t endpointArraySize = 0;
+        retval = UA_Client_getEndpoints(client, discoveryUrl, &endpointArraySize, &endpointArray);
+        UA_free(discoveryUrl);
+        if (retval != UA_STATUSCODE_GOOD) {
+            UA_Client_disconnect(client);
+            UA_Client_delete(client);
+            break;
+        }
+
+        for (size_t j = 0; j < endpointArraySize; j++) {
+            UA_EndpointDescription *endpoint = &endpointArray[j];
+            printf("\n\tEndpoint[%lu]:", (unsigned long) j);
+            printf("\n\t\tEndpoint URL: %.*s", (int) endpoint->endpointUrl.length, endpoint->endpointUrl.data);
+            printf("\n\t\tTransport profile URI: %.*s", (int) endpoint->transportProfileUri.length,
+                   endpoint->transportProfileUri.data);
+            printf("\n\t\tSecurity Mode: ");
+            switch (endpoint->securityMode) {
+            case UA_MESSAGESECURITYMODE_INVALID:
+                printf("Invalid");
+                break;
+            case UA_MESSAGESECURITYMODE_NONE:
+                printf("None");
+                break;
+            case UA_MESSAGESECURITYMODE_SIGN:
+                printf("Sign");
+                break;
+            case UA_MESSAGESECURITYMODE_SIGNANDENCRYPT:
+                printf("Sign and Encrypt");
+                break;
+            default:
+                printf("No valid security mode");
+                break;
+            }
+            printf("\n\t\tSecurity profile URI: %.*s", (int) endpoint->securityPolicyUri.length,
+                   endpoint->securityPolicyUri.data);
+            printf("\n\t\tSecurity Level: %d", endpoint->securityLevel);
+        }
+
+        UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+        UA_Client_delete(client);
+    }
+
+    printf("\n");
+
+    UA_Array_delete(applicationDescriptionArray, applicationDescriptionArraySize,
+                    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
+
+    return (int) UA_STATUSCODE_GOOD;
+}

+ 46 - 0
examples/discovery/server_lds.c

@@ -0,0 +1,46 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+/*
+ * Server representing a local discovery server as a central instance.
+ * Any other server can register with this server (see server_register.c). Clients can then call the
+ * find servers service to get all registered servers (see client_find_servers.c).
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include "open62541.h"
+
+UA_Boolean running = true;
+static void stopHandler(int sig) {
+    running = false;
+}
+
+int main(void) {
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
+
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
+    config->applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER;
+    UA_String_deleteMembers(&config->applicationDescription.applicationUri);
+    config->applicationDescription.applicationUri =
+            UA_String_fromChars("urn:open62541.example.local_discovery_server");
+    config->mdnsServerName = UA_String_fromChars("LDS");
+    // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
+    config->serverCapabilitiesSize = 1;
+    UA_String *caps = UA_String_new();
+    *caps = UA_String_fromChars("LDS");
+    config->serverCapabilities = caps;
+    /* timeout in seconds when to automatically remove a registered server from
+     * the list, if it doesn't re-register within the given time frame. A value
+     * of 0 disables automatic removal. Default is 60 Minutes (60*60). Must be
+     * bigger than 10 seconds, because cleanup is only triggered approximately
+     * ervery 10 seconds. The server will still be removed depending on the
+     * state of the semaphore file. */
+    // config.discoveryCleanupTimeout = 60*60;
+    UA_Server *server = UA_Server_new(config);
+
+    UA_StatusCode retval = UA_Server_run(server, &running);
+    UA_Server_delete(server);
+    UA_ServerConfig_delete(config);
+    return (int)retval;
+}

+ 187 - 0
examples/discovery/server_multicast.c

@@ -0,0 +1,187 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+/*
+ * A simple server instance which registers with the discovery server.
+ * Compared to server_register.c this example waits until the LDS server announces
+ * itself through mDNS. Therefore the LDS server needs to support multicast extension
+ * (i.e., LDS-ME).
+ */
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "open62541.h"
+
+UA_Logger logger = UA_Log_Stdout;
+UA_Boolean running = true;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = false;
+}
+
+static UA_StatusCode
+readInteger(UA_Server *server, const UA_NodeId *sessionId,
+            void *sessionContext, const UA_NodeId *nodeId,
+            void *nodeContext, UA_Boolean includeSourceTimeStamp,
+            const UA_NumericRange *range, UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    value->hasValue = true;
+    UA_Variant_setScalarCopy(&value->value, myInteger, &UA_TYPES[UA_TYPES_INT32]);
+
+    // we know the nodeid is a string
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node read %.*s",
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "read value %i", *(UA_UInt32 *)myInteger);
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+writeInteger(UA_Server *server, const UA_NodeId *sessionId,
+             void *sessionContext, const UA_NodeId *nodeId,
+             void *nodeContext, const UA_NumericRange *range,
+             const UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    if(value->hasValue && UA_Variant_isScalar(&value->value) &&
+       value->value.type == &UA_TYPES[UA_TYPES_INT32] && value->value.data)
+        *myInteger = *(UA_Int32 *)value->value.data;
+
+    // we know the nodeid is a string
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node written %.*s",
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "written value %i", *(UA_UInt32 *)myInteger);
+    return UA_STATUSCODE_GOOD;
+}
+
+char *discovery_url = NULL;
+UA_String *self_discovery_url = NULL;
+
+static void
+serverOnNetworkCallback(const UA_ServerOnNetwork *serverOnNetwork, UA_Boolean isServerAnnounce,
+                        UA_Boolean isTxtReceived, void *data) {
+
+    if (discovery_url != NULL || !isServerAnnounce) {
+        UA_LOG_DEBUG(logger, UA_LOGCATEGORY_SERVER,
+                     "serverOnNetworkCallback called, but discovery URL "
+                     "already initialized or is not announcing. Ignoring.");
+        return; // we already have everything we need or we only want server announces
+    }
+
+    if (self_discovery_url != NULL && UA_String_equal(&serverOnNetwork->discoveryUrl, self_discovery_url)) {
+        // skip self
+        return;
+    }
+
+    if (!isTxtReceived)
+        return; // we wait until the corresponding TXT record is announced.
+                // Problem: how to handle if a Server does not announce the
+                // optional TXT?
+
+    // here you can filter for a specific LDS server, e.g. call FindServers on
+    // the serverOnNetwork to make sure you are registering with the correct
+    // LDS. We will ignore this for now
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Another server announced itself on %.*s",
+                (int)serverOnNetwork->discoveryUrl.length, serverOnNetwork->discoveryUrl.data);
+
+    if (discovery_url != NULL)
+        UA_free(discovery_url);
+    discovery_url = (char*)UA_malloc(serverOnNetwork->discoveryUrl.length + 1);
+    memcpy(discovery_url, serverOnNetwork->discoveryUrl.data, serverOnNetwork->discoveryUrl.length);
+    discovery_url[serverOnNetwork->discoveryUrl.length] = 0;
+}
+
+int main(int argc, char **argv) {
+    signal(SIGINT, stopHandler); /* catches ctrl-c */
+    signal(SIGTERM, stopHandler);
+
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
+    // To enable mDNS discovery, set application type to discovery server.
+    config->applicationDescription.applicationType = UA_APPLICATIONTYPE_DISCOVERYSERVER;
+    UA_String_deleteMembers(&config->applicationDescription.applicationUri);
+    config->applicationDescription.applicationUri =
+        UA_String_fromChars("urn:open62541.example.server_multicast");
+    config->mdnsServerName = UA_String_fromChars("Sample Multicast Server");
+    // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
+    //config.serverCapabilitiesSize = 1;
+    //UA_String caps = UA_String_fromChars("LDS");
+    //config.serverCapabilities = &caps;
+    UA_Server *server = UA_Server_new(config);
+    self_discovery_url = &config->networkLayers[0].discoveryUrl;
+
+    /* 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;
+    dateDataSource.read = readInteger;
+    dateDataSource.write = writeInteger;
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.description = UA_LOCALIZEDTEXT("en-US", "the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "the answer");
+
+    UA_Server_addDataSourceVariableNode(server, myIntegerNodeId,
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource,
+                                        &myInteger, NULL);
+
+    // callback which is called when a new server is detected through mDNS
+    UA_Server_setServerOnNetworkCallback(server, serverOnNetworkCallback, NULL);
+
+    // Start the server and call iterate to wait for the multicast discovery of the LDS
+    UA_StatusCode retval = UA_Server_run_startup(server);
+    if (retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
+                     "Could not start the server. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        UA_Server_delete(server);
+        UA_ServerConfig_delete(config);
+        UA_free(discovery_url);
+        return 1;
+    }
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER,
+                "Server started. Waiting for announce of LDS Server.");
+    while (running && discovery_url == NULL)
+        UA_Server_run_iterate(server, true);
+    if (!running) {
+        UA_Server_delete(server);
+        UA_ServerConfig_delete(config);
+        UA_free(discovery_url);
+        return 1;
+    }
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "LDS-ME server found on %s", discovery_url);
+
+    // periodic server register after 10 Minutes, delay first register for 500ms
+    retval = UA_Server_addPeriodicServerRegisterCallback(server, discovery_url,
+                                                         10 * 60 * 1000, 500, NULL);
+    if (retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
+                     "Could not create periodic job for server register. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        UA_Server_delete(server);
+        UA_ServerConfig_delete(config);
+        return 1;
+    }
+
+    while (running)
+        UA_Server_run_iterate(server, true);
+
+    UA_Server_run_shutdown(server);
+
+    // UNregister the server from the discovery server.
+    retval = UA_Server_unregister_discovery(server, discovery_url);
+    //retval = UA_Server_unregister_discovery(server, "opc.tcp://localhost:4840" );
+    if(retval != UA_STATUSCODE_GOOD)
+        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
+                     "Could not unregister server from discovery server. "
+                     "StatusCode %s", UA_StatusCode_name(retval));
+
+    UA_Server_delete(server);
+    UA_ServerConfig_delete(config);
+    UA_free(discovery_url);
+    return (int)retval;
+}

+ 131 - 0
examples/discovery/server_register.c

@@ -0,0 +1,131 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+/*
+ * A simple server instance which registers with the discovery server (see server_lds.c).
+ * Before shutdown it has to unregister itself.
+ */
+
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "open62541.h"
+
+#define DISCOVERY_SERVER_ENDPOINT "opc.tcp://localhost:4840"
+
+UA_Logger logger = UA_Log_Stdout;
+UA_Boolean running = true;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = false;
+}
+
+static UA_StatusCode
+readInteger(UA_Server *server, const UA_NodeId *sessionId,
+            void *sessionContext, const UA_NodeId *nodeId,
+            void *nodeContext, UA_Boolean includeSourceTimeStamp,
+            const UA_NumericRange *range, UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    value->hasValue = true;
+    UA_Variant_setScalarCopy(&value->value, myInteger, &UA_TYPES[UA_TYPES_INT32]);
+
+    // we know the nodeid is a string
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node read %.*s",
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "read value %i", *(UA_UInt32 *)myInteger);
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+writeInteger(UA_Server *server, const UA_NodeId *sessionId,
+             void *sessionContext, const UA_NodeId *nodeId,
+             void *nodeContext, const UA_NumericRange *range,
+             const UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    if(value->hasValue && UA_Variant_isScalar(&value->value) &&
+       value->value.type == &UA_TYPES[UA_TYPES_INT32] && value->value.data)
+        *myInteger = *(UA_Int32 *)value->value.data;
+
+    // we know the nodeid is a string
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node written %.*s",
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "written value %i", *(UA_UInt32 *)myInteger);
+    return UA_STATUSCODE_GOOD;
+}
+
+int main(int argc, char **argv) {
+    signal(SIGINT, stopHandler); /* catches ctrl-c */
+    signal(SIGTERM, stopHandler);
+
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
+    UA_String_deleteMembers(&config->applicationDescription.applicationUri);
+    config->applicationDescription.applicationUri =
+        UA_String_fromChars("urn:open62541.example.server_register");
+    config->mdnsServerName = UA_String_fromChars("Sample Server");
+    // See http://www.opcfoundation.org/UA/schemas/1.03/ServerCapabilities.csv
+    //config.serverCapabilitiesSize = 1;
+    //UA_String caps = UA_String_fromChars("LDS");
+    //config.serverCapabilities = &caps;
+
+    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;
+    dateDataSource.read = readInteger;
+    dateDataSource.write = writeInteger;
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.description = UA_LOCALIZEDTEXT("en-US", "the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "the answer");
+
+    UA_Server_addDataSourceVariableNode(server, myIntegerNodeId,
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource,
+                                        &myInteger, NULL);
+
+
+    // periodic server register after 10 Minutes, delay first register for 500ms
+    UA_StatusCode retval =
+        UA_Server_addPeriodicServerRegisterCallback(server, DISCOVERY_SERVER_ENDPOINT,
+                                                    10 * 60 * 1000, 500, NULL);
+    // UA_StatusCode retval = UA_Server_addPeriodicServerRegisterJob(server,
+    // "opc.tcp://localhost:4840", 10*60*1000, 500, NULL);
+    if (retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
+                     "Could not create periodic job for server register. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        UA_Server_delete(server);
+        UA_ServerConfig_delete(config);
+        return (int)retval;
+    }
+
+    retval = UA_Server_run(server, &running);
+    if (retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
+                     "Could not start the server. StatusCode %s",
+                     UA_StatusCode_name(retval));
+        UA_Server_delete(server);
+        UA_ServerConfig_delete(config);
+        return (int)retval;
+    }
+
+    // UNregister the server from the discovery server.
+    retval = UA_Server_unregister_discovery(server, DISCOVERY_SERVER_ENDPOINT);
+    //retval = UA_Server_unregister_discovery(server, "opc.tcp://localhost:4840" );
+    if(retval != UA_STATUSCODE_GOOD)
+        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
+                     "Could not unregister server from discovery server. StatusCode %s",
+                     UA_StatusCode_name(retval));
+
+    UA_Server_delete(server);
+    UA_ServerConfig_delete(config);
+    return (int)retval;
+}

+ 124 - 0
examples/nodeset/CMakeLists.txt

@@ -0,0 +1,124 @@
+####################
+# Nodeset Examples #
+####################
+
+###################
+# Custom XML      #
+###################
+
+# generate namespace from XML file
+add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/example_nodeset.c
+                   ${PROJECT_BINARY_DIR}/src_generated/example_nodeset.h
+                   PRE_BUILD
+                   COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                   --types-array=UA_TYPES
+                   --existing ${UA_FILE_NS0}
+                   --xml ${PROJECT_SOURCE_DIR}/examples/nodeset/server_nodeset.xml
+                   ${PROJECT_BINARY_DIR}/src_generated/example_nodeset
+                   DEPENDS ${UA_FILE_NS0}
+                   ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                   ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodes.py
+                   ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset.py
+                   ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/datatypes.py
+                   ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541.py
+                   ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_nodes.py
+                   ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_datatypes.py
+                   ${PROJECT_SOURCE_DIR}/examples/nodeset/server_nodeset.xml)
+
+add_example(server_nodeset server_nodeset.c ${PROJECT_BINARY_DIR}/src_generated/example_nodeset.c)
+if(UA_COMPILE_AS_CXX)
+    set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/example_nodeset.c PROPERTIES LANGUAGE CXX)
+endif()
+
+###################
+# PLCopen Nodeset #
+###################
+
+# PLCopen requires the full ns0 as basis
+if(UA_ENABLE_FULL_NS0)
+
+    # Generate types for DI namespace
+    set(UA_TYPES_OUT "ua_types_di")
+    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/${UA_TYPES_OUT}_generated.c
+                       ${PROJECT_BINARY_DIR}/src_generated/${UA_TYPES_OUT}_generated.h
+                       ${PROJECT_BINARY_DIR}/src_generated/${UA_TYPES_OUT}_generated_handling.h
+                       ${PROJECT_BINARY_DIR}/src_generated/${UA_TYPES_OUT}_generated_encoding_binary.h
+                       PRE_BUILD
+                       COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
+                       --namespace=2
+                       --type-csv=${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/OpcUaDiModel.csv
+                       --type-bsd=${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd
+                       --no-builtin
+                       ${PROJECT_BINARY_DIR}/src_generated/${UA_TYPES_OUT}
+                       DEPENDS ${PROJECT_SOURCE_DIR}/tools/generate_datatypes.py
+                       ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/OpcUaDiModel.csv
+                       ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.Types.bsd)
+    add_custom_target(open62541-generator-types-di DEPENDS ${PROJECT_BINARY_DIR}/src_generated/${UA_TYPES_OUT}_generated.c)
+
+    # generate DI namespace
+    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_di.c
+                       ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_di.h
+                       PRE_BUILD
+                       COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                       --internal-headers
+                       --types-array=UA_TYPES
+                       --types-array=UA_TYPES_DI
+                       --existing ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
+                       --xml ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml
+                       ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_di
+                       DEPENDS ${UA_FILE_NS0}
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodes.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/datatypes.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_nodes.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_datatypes.py
+                       ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
+                       ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml
+                       )
+    add_custom_target(open62541-generator-ns-di DEPENDS ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_di.c)
+    add_dependencies(open62541-generator-ns-di open62541-generator-types-di)
+
+    # generate PLCopen namespace which is using DI
+    add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_plc.c
+                       ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_plc.h
+                       PRE_BUILD
+                       COMMAND ${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                       --internal-headers
+                       --types-array=UA_TYPES
+                       --types-array=UA_TYPES_DI
+                       # PLCopen has no specific type definition, thus use the default UA_TYPES to ignore it
+                       --types-array=UA_TYPES
+                       --existing ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
+                       --existing ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml
+                       --xml ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/PLCopen/Opc.Ua.Plc.NodeSet2.xml
+                       ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_plc
+                       DEPENDS ${UA_FILE_NS0}
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset_compiler.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodes.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/nodeset.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/datatypes.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_nodes.py
+                       ${PROJECT_SOURCE_DIR}/tools/nodeset_compiler/backend_open62541_datatypes.py
+                       ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml
+                       ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/DI/Opc.Ua.Di.NodeSet2.xml
+                       ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/PLCopen/Opc.Ua.Plc.NodeSet2.xml
+                       )
+    add_custom_target(open62541-generator-ns-plc DEPENDS ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_plc.c)
+    add_dependencies(open62541-generator-ns-plc open62541-generator-ns-di)
+
+    add_example(server_nodeset_plcopen server_nodeset_plcopen.c
+                ${PROJECT_BINARY_DIR}/src_generated/ua_types_di_generated.c
+                ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_di.c
+                ${PROJECT_BINARY_DIR}/src_generated/ua_namespace_plc.c)
+    add_dependencies(server_nodeset_plcopen open62541-generator-ns-plc)
+    target_include_directories(server_nodeset_plcopen PRIVATE ${PROJECT_SOURCE_DIR}/src) # needs an internal header
+
+    if(UA_COMPILE_AS_CXX)
+        set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/ua_types_di_generated.c PROPERTIES LANGUAGE CXX)
+        set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/ua_namespace_di.c PROPERTIES LANGUAGE CXX)
+        set_source_files_properties(${PROJECT_BINARY_DIR}/src_generated/ua_namespace_plc.c PROPERTIES LANGUAGE CXX)
+    endif()
+endif()

+ 37 - 0
examples/nodeset/server_nodeset.c

@@ -0,0 +1,37 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include <signal.h>
+#include "open62541.h"
+
+/* Files example_namespace.h and example_namespace.c are created from server_nodeset.xml in the
+ * /src_generated directory by CMake */
+#include "example_nodeset.h"
+
+UA_Boolean running = true;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = false;
+}
+
+int main(int argc, char** argv) {
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
+    
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
+    UA_Server *server = UA_Server_new(config);
+
+    UA_StatusCode retval;
+    /* create nodes from nodeset */
+    if(example_nodeset(server) != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Could not add the example nodeset. "
+        "Check previous output for any error.");
+        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    } else {
+        retval = UA_Server_run(server, &running);
+    }
+    UA_Server_delete(server);
+    UA_ServerConfig_delete(config);
+    return (int)retval;
+}

+ 26 - 11
examples/server_nodeset.xml

@@ -10,6 +10,22 @@
         <Alias Alias="HasSubtype">i=45</Alias>
         <Alias Alias="HasSubtype">i=45</Alias>
         <Alias Alias="HasComponent">i=47</Alias>
         <Alias Alias="HasComponent">i=47</Alias>
     </Aliases>
     </Aliases>
+    <!-- Following object has only references to nodes defined after itself -->
+    <UAObject NodeId="ns=1;i=5001" BrowseName="1:testInstance">
+        <DisplayName>testInstance</DisplayName>
+        <References>
+            <Reference ReferenceType="Organizes" IsForward="false">ns=1;i=5002</Reference>
+            <Reference ReferenceType="HasTypeDefinition">ns=1;i=1001</Reference>
+            <Reference ReferenceType="HasComponent">ns=1;i=6002</Reference>
+        </References>
+    </UAObject>
+    <UAObject NodeId="ns=1;i=5002" BrowseName="1:testFolder">
+        <DisplayName>testFolder</DisplayName>
+        <References>
+            <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
+            <Reference ReferenceType="HasTypeDefinition">i=61</Reference>
+        </References>
+    </UAObject>
     <UAObjectType NodeId="ns=1;i=1001" BrowseName="1:testType">
     <UAObjectType NodeId="ns=1;i=1001" BrowseName="1:testType">
         <DisplayName>testType</DisplayName>
         <DisplayName>testType</DisplayName>
         <References>
         <References>
@@ -24,23 +40,22 @@
             <Reference ReferenceType="HasModellingRule">i=78</Reference>
             <Reference ReferenceType="HasModellingRule">i=78</Reference>
             <Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=1001</Reference>
             <Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=1001</Reference>
         </References>
         </References>
+        <Value>
+            <uax:Double>42.0</uax:Double>
+        </Value>
     </UAVariable>
     </UAVariable>
-    <UAObject NodeId="ns=1;i=5001" BrowseName="1:testInstance">
-        <DisplayName>testInstance</DisplayName>
-        <References>
-            <Reference ReferenceType="Organizes" IsForward="false">i=85</Reference>
-            <Reference ReferenceType="HasTypeDefinition">ns=1;i=1001</Reference>
-            <Reference ReferenceType="HasComponent">ns=1;i=6002</Reference>
-        </References>
-    </UAObject>
-    <UAVariable DataType="Double" ParentNodeId="ns=1;i=5001" NodeId="ns=1;i=6002" BrowseName="1:Var1" UserAccessLevel="3" AccessLevel="3">
-        <DisplayName>Var1</DisplayName>
+    <UAVariable ParentNodeId="ns=1;i=5001" NodeId="ns=1;i=6002" BrowseName="1:Var1" DataType="i=7" UserAccessLevel="3" AccessLevel="3">
+        <DisplayName>Var2</DisplayName>
         <References>
         <References>
             <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
             <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
             <Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=5001</Reference>
             <Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=5001</Reference>
         </References>
         </References>
         <Value>
         <Value>
-            <uax:Double>42.0</uax:Double>
+            <ListOfUInt32 xmlns="http://opcfoundation.org/UA/2008/02/Types.xsd">
+                <uax:UInt32>1</uax:UInt32>
+                <uax:UInt32>2</uax:UInt32>
+                <uax:UInt32>3</uax:UInt32>
+            </ListOfUInt32>
         </Value>
         </Value>
     </UAVariable>
     </UAVariable>
 </UANodeSet>
 </UANodeSet>

+ 52 - 0
examples/nodeset/server_nodeset_plcopen.c

@@ -0,0 +1,52 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include <signal.h>
+#ifdef UA_NO_AMALGAMATION
+#include "ua_server.h"
+#include "ua_log_stdout.h"
+#include "ua_config_default.h"
+#else
+#include "open62541.h"
+#endif
+
+/* Files example_namespace.h and example_namespace.c are created from server_nodeset.xml in the
+ * /src_generated directory by CMake */
+#include "ua_namespace_di.h"
+#include "ua_namespace_plc.h"
+
+UA_Boolean running = true;
+
+static void stopHandler(int sign) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    running = false;
+}
+
+int main(int argc, char** argv) {
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
+
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
+    UA_Server *server = UA_Server_new(config);
+
+    /* create nodes from nodeset */
+    UA_StatusCode retval = ua_namespace_di(server);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Adding the DI namespace failed. Please check previous error output.");
+        UA_Server_delete(server);
+        UA_ServerConfig_delete(config);
+        return (int)UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    retval |= ua_namespace_plc(server);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "Adding the PLCopen namespace failed. Please check previous error output.");
+        UA_Server_delete(server);
+        UA_ServerConfig_delete(config);
+        return (int)UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+
+    retval = UA_Server_run(server, &running);
+    UA_Server_delete(server);
+    UA_ServerConfig_delete(config);
+    return (int)retval;
+}

+ 77 - 90
examples/server.c

@@ -2,25 +2,16 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 
 #ifdef _MSC_VER
 #ifdef _MSC_VER
-#define _CRT_SECURE_NO_WARNINGS //disable fopen deprication warning in msvs
+#define _CRT_SECURE_NO_WARNINGS /* disable fopen deprication warning in msvs */
 #endif
 #endif
 
 
-#ifdef UA_NO_AMALGAMATION
-# include <time.h>
-# include "ua_types.h"
-# include "ua_server.h"
-# include "ua_config_standard.h"
-# include "ua_network_tcp.h"
-# include "ua_log_stdout.h"
-#else
-# include "open62541.h"
-#endif
 
 
 #include <signal.h>
 #include <signal.h>
 #include <errno.h> // errno, EINTR
 #include <errno.h> // errno, EINTR
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
+#include "open62541.h"
 
 
 UA_Boolean running = true;
 UA_Boolean running = true;
 UA_Logger logger = UA_Log_Stdout;
 UA_Logger logger = UA_Log_Stdout;
@@ -38,7 +29,7 @@ static UA_ByteString loadCertificate(void) {
 
 
     fseek(fp, 0, SEEK_END);
     fseek(fp, 0, SEEK_END);
     certificate.length = (size_t)ftell(fp);
     certificate.length = (size_t)ftell(fp);
-    certificate.data = malloc(certificate.length*sizeof(UA_Byte));
+    certificate.data = (UA_Byte*)UA_malloc(certificate.length*sizeof(UA_Byte));
     if(!certificate.data)
     if(!certificate.data)
         return certificate;
         return certificate;
 
 
@@ -57,7 +48,10 @@ static void stopHandler(int sign) {
 
 
 /* Datasource Example */
 /* Datasource Example */
 static UA_StatusCode
 static UA_StatusCode
-readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
+readTimeData(UA_Server *server,
+             const UA_NodeId *sessionId, void *sessionContext,
+             const UA_NodeId *nodeId, void *nodeContext,
+             UA_Boolean sourceTimeStamp,
              const UA_NumericRange *range, UA_DataValue *value) {
              const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
     if(range) {
         value->hasStatus = true;
         value->hasStatus = true;
@@ -77,7 +71,10 @@ readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
 /* Method Node Example */
 /* Method Node Example */
 #ifdef UA_ENABLE_METHODCALLS
 #ifdef UA_ENABLE_METHODCALLS
 static UA_StatusCode
 static UA_StatusCode
-helloWorld(void *methodHandle, const UA_NodeId objectId,
+helloWorld(UA_Server *server,
+           const UA_NodeId *sessionId, void *sessionContext,
+           const UA_NodeId *methodId, void *methodContext,
+           const UA_NodeId *objectId, void *objectContext,
            size_t inputSize, const UA_Variant *input,
            size_t inputSize, const UA_Variant *input,
            size_t outputSize, UA_Variant *output) {
            size_t outputSize, UA_Variant *output) {
     /* input is a scalar string (checked by the server) */
     /* input is a scalar string (checked by the server) */
@@ -85,7 +82,7 @@ helloWorld(void *methodHandle, const UA_NodeId objectId,
     UA_String hello = UA_STRING("Hello ");
     UA_String hello = UA_STRING("Hello ");
     UA_String greet;
     UA_String greet;
     greet.length = hello.length + name->length;
     greet.length = hello.length + name->length;
-    greet.data = malloc(greet.length);
+    greet.data = (UA_Byte*)UA_malloc(greet.length);
     memcpy(greet.data, hello.data, hello.length);
     memcpy(greet.data, hello.data, hello.length);
     memcpy(greet.data + hello.length, name->data, name->length);
     memcpy(greet.data + hello.length, name->data, name->length);
     UA_Variant_setScalarCopy(output, &greet, &UA_TYPES[UA_TYPES_STRING]);
     UA_Variant_setScalarCopy(output, &greet, &UA_TYPES[UA_TYPES_STRING]);
@@ -94,16 +91,22 @@ helloWorld(void *methodHandle, const UA_NodeId objectId,
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
-noargMethod (void *methodHandle, const UA_NodeId objectId,
-           size_t inputSize, const UA_Variant *input,
-           size_t outputSize, UA_Variant *output) {
+noargMethod(UA_Server *server,
+            const UA_NodeId *sessionId, void *sessionContext,
+            const UA_NodeId *methodId, void *methodContext,
+            const UA_NodeId *objectId, void *objectContext,
+            size_t inputSize, const UA_Variant *input,
+            size_t outputSize, UA_Variant *output) {
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
-outargMethod (void *methodHandle, const UA_NodeId objectId,
-           size_t inputSize, const UA_Variant *input,
-           size_t outputSize, UA_Variant *output) {
+outargMethod(UA_Server *server,
+             const UA_NodeId *sessionId, void *sessionContext,
+             const UA_NodeId *methodId, void *methodContext,
+             const UA_NodeId *objectId, void *objectContext,
+             size_t inputSize, const UA_Variant *input,
+             size_t outputSize, UA_Variant *output) {
     UA_Int32 out = 42;
     UA_Int32 out = 42;
     UA_Variant_setScalarCopy(output, &out, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalarCopy(output, &out, &UA_TYPES[UA_TYPES_INT32]);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
@@ -113,21 +116,16 @@ outargMethod (void *methodHandle, const UA_NodeId objectId,
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
 
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
-
-    /* load certificate */
-    config.serverCertificate = loadCertificate();
-
+    UA_ByteString certificate = loadCertificate();
+    UA_ServerConfig *config =
+        UA_ServerConfig_new_minimal(4840, &certificate);
+    UA_ByteString_deleteMembers(&certificate);
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
     /* add a static variable node to the server */
     /* add a static variable node to the server */
-    UA_VariableAttributes myVar;
-    UA_VariableAttributes_init(&myVar);
-    myVar.description = UA_LOCALIZEDTEXT("en_US", "the answer");
-    myVar.displayName = UA_LOCALIZEDTEXT("en_US", "the answer");
+    UA_VariableAttributes myVar = UA_VariableAttributes_default;
+    myVar.description = UA_LOCALIZEDTEXT("en-US", "the answer");
+    myVar.displayName = UA_LOCALIZEDTEXT("en-US", "the answer");
     myVar.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     myVar.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(&myVar.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalarCopy(&myVar.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
@@ -140,17 +138,18 @@ int main(int argc, char** argv) {
     UA_Variant_deleteMembers(&myVar.value);
     UA_Variant_deleteMembers(&myVar.value);
 
 
     /* add a variable with the datetime data source */
     /* add a variable with the datetime data source */
-    UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
-    UA_VariableAttributes v_attr;
-    UA_VariableAttributes_init(&v_attr);
-    v_attr.description = UA_LOCALIZEDTEXT("en_US","current time");
-    v_attr.displayName = UA_LOCALIZEDTEXT("en_US","current time");
+    UA_DataSource dateDataSource;
+    dateDataSource.read = readTimeData;
+    dateDataSource.write = NULL;
+    UA_VariableAttributes v_attr = UA_VariableAttributes_default;
+    v_attr.description = UA_LOCALIZEDTEXT("en-US","current time");
+    v_attr.displayName = UA_LOCALIZEDTEXT("en-US","current time");
     v_attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     v_attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
     const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
     UA_NodeId dataSourceId;
     UA_NodeId dataSourceId;
     UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
     UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,
-                                        UA_NODEID_NULL, v_attr, dateDataSource, &dataSourceId);
+                                        UA_NODEID_NULL, v_attr, dateDataSource, NULL, &dataSourceId);
 
 
     /* Add HelloWorld method to the server */
     /* Add HelloWorld method to the server */
 #ifdef UA_ENABLE_METHODCALLS
 #ifdef UA_ENABLE_METHODCALLS
@@ -158,7 +157,7 @@ int main(int argc, char** argv) {
     UA_Argument inputArguments;
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
     UA_Argument_init(&inputArguments);
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
-    inputArguments.description = UA_LOCALIZEDTEXT("en_US", "Say your name");
+    inputArguments.description = UA_LOCALIZEDTEXT("en-US", "Say your name");
     inputArguments.name = UA_STRING("Name");
     inputArguments.name = UA_STRING("Name");
     inputArguments.valueRank = -1; /* scalar argument */
     inputArguments.valueRank = -1; /* scalar argument */
 
 
@@ -167,13 +166,12 @@ int main(int argc, char** argv) {
     outputArguments.arrayDimensionsSize = 0;
     outputArguments.arrayDimensionsSize = 0;
     outputArguments.arrayDimensions = NULL;
     outputArguments.arrayDimensions = NULL;
     outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
-    outputArguments.description = UA_LOCALIZEDTEXT("en_US", "Receive a greeting");
+    outputArguments.description = UA_LOCALIZEDTEXT("en-US", "Receive a greeting");
     outputArguments.name = UA_STRING("greeting");
     outputArguments.name = UA_STRING("greeting");
     outputArguments.valueRank = -1;
     outputArguments.valueRank = -1;
 
 
-    UA_MethodAttributes addmethodattributes;
-    UA_MethodAttributes_init(&addmethodattributes);
-    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "Hello World");
+    UA_MethodAttributes addmethodattributes = UA_MethodAttributes_default;
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "Hello World");
     addmethodattributes.executable = true;
     addmethodattributes.executable = true;
     addmethodattributes.userExecutable = true;
     addmethodattributes.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, 62541),
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, 62541),
@@ -181,8 +179,7 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "hello_world"), addmethodattributes,
         UA_QUALIFIEDNAME(1, "hello_world"), addmethodattributes,
         &helloWorld, /* callback of the method node */
         &helloWorld, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 1, &outputArguments, NULL);
+        1, &inputArguments, 1, &outputArguments, NULL, NULL);
 #endif
 #endif
 
 
     /* Add folders for demo information model */
     /* Add folders for demo information model */
@@ -192,31 +189,30 @@ int main(int argc, char** argv) {
 #define MATRIXID 50003
 #define MATRIXID 50003
 #define DEPTHID 50004
 #define DEPTHID 50004
 
 
-    UA_ObjectAttributes object_attr;
-    UA_ObjectAttributes_init(&object_attr);
-    object_attr.description = UA_LOCALIZEDTEXT("en_US", "Demo");
-    object_attr.displayName = UA_LOCALIZEDTEXT("en_US", "Demo");
+    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
+    object_attr.description = UA_LOCALIZEDTEXT("en-US", "Demo");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Demo");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 
-    object_attr.description = UA_LOCALIZEDTEXT("en_US", "Scalar");
-    object_attr.displayName = UA_LOCALIZEDTEXT("en_US", "Scalar");
+    object_attr.description = UA_LOCALIZEDTEXT("en-US", "Scalar");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Scalar");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
         UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
         UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
         UA_QUALIFIEDNAME(1, "Scalar"),
         UA_QUALIFIEDNAME(1, "Scalar"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 
-    object_attr.description = UA_LOCALIZEDTEXT("en_US", "Array");
-    object_attr.displayName = UA_LOCALIZEDTEXT("en_US", "Array");
+    object_attr.description = UA_LOCALIZEDTEXT("en-US", "Array");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en-US", "Array");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
         UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
         UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
         UA_QUALIFIEDNAME(1, "Array"),
         UA_QUALIFIEDNAME(1, "Array"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 
-    object_attr.description = UA_LOCALIZEDTEXT("en_US", "Matrix");
-    object_attr.displayName = UA_LOCALIZEDTEXT("en_US", "Matrix");
+    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_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_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
@@ -227,8 +223,7 @@ int main(int argc, char** argv) {
         if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
         if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
             continue;
             continue;
 
 
-        UA_VariableAttributes attr;
-        UA_VariableAttributes_init(&attr);
+        UA_VariableAttributes attr = UA_VariableAttributes_default;
         attr.valueRank = -2;
         attr.valueRank = -2;
         attr.dataType = UA_TYPES[type].typeId;
         attr.dataType = UA_TYPES[type].typeId;
 #ifndef UA_ENABLE_TYPENAMES
 #ifndef UA_ENABLE_TYPENAMES
@@ -238,10 +233,10 @@ int main(int argc, char** argv) {
 #else
 #else
         sprintf(name, "%02d", type);
         sprintf(name, "%02d", type);
 #endif
 #endif
-        attr.displayName = UA_LOCALIZEDTEXT("en_US", name);
+        attr.displayName = UA_LOCALIZEDTEXT("en-US", name);
         UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name);
         UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name);
 #else
 #else
-        attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", UA_TYPES[type].typeName);
+        attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US", UA_TYPES[type].typeName);
         UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME_ALLOC(1, UA_TYPES[type].typeName);
         UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME_ALLOC(1, UA_TYPES[type].typeName);
 #endif
 #endif
         attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
         attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
@@ -265,7 +260,7 @@ int main(int argc, char** argv) {
 
 
         /* add an matrix node for every built-in type */
         /* add an matrix node for every built-in type */
         void* myMultiArray = UA_Array_new(9, &UA_TYPES[type]);
         void* myMultiArray = UA_Array_new(9, &UA_TYPES[type]);
-        attr.value.arrayDimensions = UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
+        attr.value.arrayDimensions = (UA_UInt32*)UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
         attr.value.arrayDimensions[0] = 3;
         attr.value.arrayDimensions[0] = 3;
         attr.value.arrayDimensions[1] = 3;
         attr.value.arrayDimensions[1] = 3;
         attr.value.arrayDimensionsSize = 2;
         attr.value.arrayDimensionsSize = 2;
@@ -285,8 +280,8 @@ int main(int argc, char** argv) {
     /* Hierarchy of depth 10 for CTT testing with forward and inverse references */
     /* Hierarchy of depth 10 for CTT testing with forward and inverse references */
     /* Enter node "depth 9" in CTT configuration - Project->Settings->Server
     /* Enter node "depth 9" in CTT configuration - Project->Settings->Server
        Test->NodeIds->Paths->Starting Node 1 */
        Test->NodeIds->Paths->Starting Node 1 */
-    object_attr.description = UA_LOCALIZEDTEXT("en_US","DepthDemo");
-    object_attr.displayName = UA_LOCALIZEDTEXT("en_US","DepthDemo");
+    object_attr.description = UA_LOCALIZEDTEXT("en-US","DepthDemo");
+    object_attr.displayName = UA_LOCALIZEDTEXT("en-US","DepthDemo");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEPTHID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEPTHID),
                             UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "DepthDemo"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "DepthDemo"),
@@ -300,8 +295,8 @@ int main(int argc, char** argv) {
 #else
 #else
         sprintf(name, "depth%i", i);
         sprintf(name, "depth%i", i);
 #endif
 #endif
-        object_attr.description = UA_LOCALIZEDTEXT("en_US",name);
-        object_attr.displayName = UA_LOCALIZEDTEXT("en_US",name);
+        object_attr.description = UA_LOCALIZEDTEXT("en-US",name);
+        object_attr.displayName = UA_LOCALIZEDTEXT("en-US",name);
         UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, id+i),
         UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, id+i),
                                 UA_NODEID_NUMERIC(1, i==1 ? DEPTHID : id+i-1), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                 UA_NODEID_NUMERIC(1, i==1 ? DEPTHID : id+i-1), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                 UA_QUALIFIEDNAME(1, name),
                                 UA_QUALIFIEDNAME(1, name),
@@ -316,7 +311,7 @@ int main(int argc, char** argv) {
                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), answer_nodeid, true);
                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), answer_nodeid, true);
 
 
     /* Example for manually setting an attribute within the server */
     /* Example for manually setting an attribute within the server */
-    UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("en_US", "Objects");
+    UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("en-US", "Objects");
     UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
     UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
 
 
 #define NOARGID     60000
 #define NOARGID     60000
@@ -326,8 +321,8 @@ int main(int argc, char** argv) {
 #ifdef UA_ENABLE_METHODCALLS
 #ifdef UA_ENABLE_METHODCALLS
     /* adding some more method nodes to pass CTT */
     /* adding some more method nodes to pass CTT */
     /* Method without arguments */
     /* Method without arguments */
-    UA_MethodAttributes_init(&addmethodattributes);
-    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "noarg");
+    addmethodattributes = UA_MethodAttributes_default;
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "noarg");
     addmethodattributes.executable = true;
     addmethodattributes.executable = true;
     addmethodattributes.userExecutable = true;
     addmethodattributes.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, NOARGID),
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1, NOARGID),
@@ -335,18 +330,17 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         &noargMethod, /* callback of the method node */
         &noargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        0, NULL, 0, NULL, NULL);
+        0, NULL, 0, NULL, NULL, NULL);
 
 
     /* Method with in arguments */
     /* Method with in arguments */
-    UA_MethodAttributes_init(&addmethodattributes);
-    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "inarg");
+    addmethodattributes = UA_MethodAttributes_default;
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "inarg");
     addmethodattributes.executable = true;
     addmethodattributes.executable = true;
     addmethodattributes.userExecutable = true;
     addmethodattributes.userExecutable = true;
 
 
     UA_Argument_init(&inputArguments);
     UA_Argument_init(&inputArguments);
     inputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     inputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
-    inputArguments.description = UA_LOCALIZEDTEXT("en_US", "Input");
+    inputArguments.description = UA_LOCALIZEDTEXT("en-US", "Input");
     inputArguments.name = UA_STRING("Input");
     inputArguments.name = UA_STRING("Input");
     inputArguments.valueRank = -1; //uaexpert will crash if set to 0 ;)
     inputArguments.valueRank = -1; //uaexpert will crash if set to 0 ;)
 
 
@@ -355,18 +349,17 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         &noargMethod, /* callback of the method node */
         &noargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 0, NULL, NULL);
+        1, &inputArguments, 0, NULL, NULL, NULL);
 
 
     /* Method with out arguments */
     /* Method with out arguments */
-    UA_MethodAttributes_init(&addmethodattributes);
-    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "outarg");
+    addmethodattributes = UA_MethodAttributes_default;
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "outarg");
     addmethodattributes.executable = true;
     addmethodattributes.executable = true;
     addmethodattributes.userExecutable = true;
     addmethodattributes.userExecutable = true;
 
 
     UA_Argument_init(&outputArguments);
     UA_Argument_init(&outputArguments);
     outputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     outputArguments.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
-    outputArguments.description = UA_LOCALIZEDTEXT("en_US", "Output");
+    outputArguments.description = UA_LOCALIZEDTEXT("en-US", "Output");
     outputArguments.name = UA_STRING("Output");
     outputArguments.name = UA_STRING("Output");
     outputArguments.valueRank = -1;
     outputArguments.valueRank = -1;
 
 
@@ -375,12 +368,11 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "outarg"), addmethodattributes,
         UA_QUALIFIEDNAME(1, "outarg"), addmethodattributes,
         &outargMethod, /* callback of the method node */
         &outargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        0, NULL, 1, &outputArguments, NULL);
+        0, NULL, 1, &outputArguments, NULL, NULL);
 
 
     /* Method with inout arguments */
     /* Method with inout arguments */
-    UA_MethodAttributes_init(&addmethodattributes);
-    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "inoutarg");
+    addmethodattributes = UA_MethodAttributes_default;
+    addmethodattributes.displayName = UA_LOCALIZEDTEXT("en-US", "inoutarg");
     addmethodattributes.executable = true;
     addmethodattributes.executable = true;
     addmethodattributes.userExecutable = true;
     addmethodattributes.userExecutable = true;
 
 
@@ -389,17 +381,12 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "inoutarg"), addmethodattributes,
         UA_QUALIFIEDNAME(1, "inoutarg"), addmethodattributes,
         &outargMethod, /* callback of the method node */
         &outargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 1, &outputArguments, NULL);
+        1, &inputArguments, 1, &outputArguments, NULL, NULL);
 #endif
 #endif
 
 
     /* run server */
     /* run server */
-    UA_StatusCode retval = UA_Server_run(server, &running); /* run until ctrl-c is received */
-
-    /* deallocate certificate's memory */
-    UA_ByteString_deleteMembers(&config.serverCertificate);
-
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     return (int)retval;
     return (int)retval;
 }
 }

+ 7 - 18
examples/server.cpp

@@ -4,14 +4,7 @@
 #include <signal.h>
 #include <signal.h>
 #include <iostream>
 #include <iostream>
 #include <cstring>
 #include <cstring>
-
-#ifdef UA_NO_AMALGAMATION
-# include "ua_server.h"
-# include "ua_log_stdout.h"
-# include "ua_network_tcp.h"
-#else
 # include "open62541.h"
 # include "open62541.h"
-#endif
 
 
 /* Build Instructions (Linux)
 /* Build Instructions (Linux)
  * - gcc -std=c99 -c open62541.c
  * - gcc -std=c99 -c open62541.c
@@ -28,21 +21,18 @@ static void stopHandler(int sign) {
 }
 }
 
 
 int main() {
 int main() {
-    signal(SIGINT, stopHandler); /* catches ctrl-c */
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
     // add a variable node to the adresspace
     // add a variable node to the adresspace
-    UA_VariableAttributes attr;
-    UA_VariableAttributes_init(&attr);
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    attr.description = UA_LOCALIZEDTEXT_ALLOC("en_US","the answer");
-    attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US","the answer");
+    attr.description = UA_LOCALIZEDTEXT_ALLOC("en-US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en-US","the answer");
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME_ALLOC(1, "the answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME_ALLOC(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
@@ -58,7 +48,6 @@ int main() {
 
 
     UA_StatusCode retval = UA_Server_run(server, &running);
     UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-
+    UA_ServerConfig_delete(config);
     return retval;
     return retval;
 }
 }

+ 9 - 23
examples/server_certificate.c

@@ -5,30 +5,19 @@
 #define _CRT_SECURE_NO_WARNINGS //disable fopen deprication warning in msvs
 #define _CRT_SECURE_NO_WARNINGS //disable fopen deprication warning in msvs
 #endif
 #endif
 
 
-#ifdef UA_NO_AMALGAMATION
-#include "ua_types.h"
-#include "ua_server.h"
-#include "ua_config_standard.h"
-#include "ua_network_tcp.h"
-#include "ua_log_stdout.h"
-#else
-#include "open62541.h"
-#endif
-
-#include <errno.h> // errno, EINTR
 #include <stdio.h>
 #include <stdio.h>
 #include <signal.h>
 #include <signal.h>
+#include <errno.h> // errno, EINTR
 #include <stdlib.h>
 #include <stdlib.h>
+#include "open62541.h"
 
 
 UA_Boolean running = true;
 UA_Boolean running = true;
 UA_Logger logger = UA_Log_Stdout;
 UA_Logger logger = UA_Log_Stdout;
 
 
 static UA_ByteString loadCertificate(void) {
 static UA_ByteString loadCertificate(void) {
     UA_ByteString certificate = UA_STRING_NULL;
     UA_ByteString certificate = UA_STRING_NULL;
-    FILE *fp = NULL;
     //FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
     //FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
-    fp=fopen("server_cert.der", "rb");
-
+    FILE *fp = fopen("server_cert.der", "rb");
     if(!fp) {
     if(!fp) {
         errno = 0; // we read errno also from the tcp layer...
         errno = 0; // we read errno also from the tcp layer...
         UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not open certificate file");
         UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Could not open certificate file");
@@ -37,7 +26,7 @@ static UA_ByteString loadCertificate(void) {
 
 
     fseek(fp, 0, SEEK_END);
     fseek(fp, 0, SEEK_END);
     certificate.length = (size_t)ftell(fp);
     certificate.length = (size_t)ftell(fp);
-    certificate.data = malloc(certificate.length*sizeof(UA_Byte));
+    certificate.data = (UA_Byte *)UA_malloc(certificate.length*sizeof(UA_Byte));
     if(!certificate.data)
     if(!certificate.data)
         return certificate;
         return certificate;
 
 
@@ -57,14 +46,11 @@ static void stopHandler(int sign) {
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
 
 
     /* load certificate */
     /* load certificate */
-    config.serverCertificate = loadCertificate();
-    if(config.serverCertificate.length > 0)
+    config->serverCertificate = loadCertificate();
+    if(config->serverCertificate.length > 0)
         UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Certificate loaded");
         UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "Certificate loaded");
 
 
 
 
@@ -73,10 +59,10 @@ int main(int argc, char** argv) {
     UA_StatusCode retval = UA_Server_run(server, &running);
     UA_StatusCode retval = UA_Server_run(server, &running);
 
 
     /* deallocate certificate's memory */
     /* deallocate certificate's memory */
-    UA_ByteString_deleteMembers(&config.serverCertificate);
+    UA_ByteString_deleteMembers(&config->serverCertificate);
 
 
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
 
 
     return (int)retval;
     return (int)retval;
 }
 }

+ 71 - 75
examples/server_inheritance.c

@@ -2,15 +2,7 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 
 #include <signal.h>
 #include <signal.h>
-
-#ifdef UA_NO_AMALGAMATION
-#include "ua_types.h"
-#include "ua_server.h"
-#include "ua_config_standard.h"
-#include "ua_network_tcp.h"
-#else
 #include "open62541.h"
 #include "open62541.h"
-#endif
 
 
 UA_Boolean running = true;
 UA_Boolean running = true;
 static void stopHandler(int sig) {
 static void stopHandler(int sig) {
@@ -21,13 +13,9 @@ int main(void) {
     signal(SIGINT,  stopHandler);
     signal(SIGINT,  stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
-
     /* Create a rudimentary objectType
     /* Create a rudimentary objectType
      *
      *
      * Type:
      * Type:
@@ -44,60 +32,65 @@ int main(void) {
      *          v- MakeSound = "Wuff"
      *          v- MakeSound = "Wuff"
      *           v- FetchNewPaper
      *           v- FetchNewPaper
      */
      */
-    UA_StatusCode retval;
-    UA_ObjectTypeAttributes otAttr;
-    UA_ObjectTypeAttributes_init(&otAttr);
 
 
-    otAttr.description = UA_LOCALIZEDTEXT("en_US", "A mamal");
-    otAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MamalType");
+    UA_StatusCode retval;
+    UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default;
+    otAttr.description = UA_LOCALIZEDTEXT("en-US", "A mamal");
+    otAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MamalType");
     UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 10000),
     UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 10000),
-                                UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "MamalType"), otAttr, NULL, NULL);
                                 UA_QUALIFIEDNAME(1, "MamalType"), otAttr, NULL, NULL);
 
 
-    UA_VariableAttributes   vAttr;
-    UA_VariableAttributes_init(&vAttr);
-    vAttr.description =  UA_LOCALIZEDTEXT("en_US", "This mamals class");
-    vAttr.displayName =  UA_LOCALIZEDTEXT("en_US", "Class");
+    UA_VariableAttributes vAttr = UA_VariableAttributes_default;
+    vAttr.description =  UA_LOCALIZEDTEXT("en-US", "This mamals class");
+    vAttr.displayName =  UA_LOCALIZEDTEXT("en-US", "Class");
     UA_String classVar = UA_STRING("mamalia");
     UA_String classVar = UA_STRING("mamalia");
-    UA_Variant_setScalarCopy(&vAttr.value, &classVar, &UA_TYPES[UA_TYPES_STRING]);
+    UA_Variant_setScalar(&vAttr.value, &classVar, &UA_TYPES[UA_TYPES_STRING]);
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10001),
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10001),
-                              UA_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
-                              UA_QUALIFIEDNAME(1, "Class"), UA_NODEID_NULL, vAttr, NULL, NULL);
-
-    UA_VariableAttributes_init(&vAttr);
-    vAttr.description =  UA_LOCALIZEDTEXT("en_US", "This mamals species");
-    vAttr.displayName =  UA_LOCALIZEDTEXT("en_US", "Species");
+                              UA_NODEID_NUMERIC(1, 10000),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
+                              UA_QUALIFIEDNAME(1, "Class"), UA_NODEID_NULL,
+                              vAttr, NULL, NULL);
+
+    vAttr = UA_VariableAttributes_default;
+    vAttr.description =  UA_LOCALIZEDTEXT("en-US", "This mamals species");
+    vAttr.displayName =  UA_LOCALIZEDTEXT("en-US", "Species");
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10002),
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10002),
-                            UA_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
-                            UA_QUALIFIEDNAME(1, "Species"), UA_NODEID_NULL, vAttr, NULL, NULL);
-
-
-
-    UA_ObjectTypeAttributes_init(&otAttr);
-    otAttr.description = UA_LOCALIZEDTEXT("en_US", "A dog, subtype of mamal");
-    otAttr.displayName = UA_LOCALIZEDTEXT("en_US", "DogType");
+                              UA_NODEID_NUMERIC(1, 10000),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
+                              UA_QUALIFIEDNAME(1, "Species"), UA_NODEID_NULL,
+                              vAttr, NULL, NULL);
+
+    otAttr = UA_ObjectTypeAttributes_default;
+    otAttr.description = UA_LOCALIZEDTEXT("en-US", "A dog, subtype of mamal");
+    otAttr.displayName = UA_LOCALIZEDTEXT("en-US", "DogType");
     UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 20000),
     UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 20000),
-                                UA_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                UA_NODEID_NUMERIC(1, 10000),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "DogType"), otAttr, NULL, NULL);
                                 UA_QUALIFIEDNAME(1, "DogType"), otAttr, NULL, NULL);
 
 
-    UA_VariableAttributes_init(&vAttr);
-    vAttr.description =  UA_LOCALIZEDTEXT("en_US", "This dogs species");
-    vAttr.displayName =  UA_LOCALIZEDTEXT("en_US", "Species");
+    vAttr = UA_VariableAttributes_default;
+    vAttr.description =  UA_LOCALIZEDTEXT("en-US", "This dogs species");
+    vAttr.displayName =  UA_LOCALIZEDTEXT("en-US", "Species");
     UA_String defaultSpecies = UA_STRING("Canis");
     UA_String defaultSpecies = UA_STRING("Canis");
-    UA_Variant_setScalarCopy(&vAttr.value, &defaultSpecies, &UA_TYPES[UA_TYPES_STRING]);
+    UA_Variant_setScalar(&vAttr.value, &defaultSpecies, &UA_TYPES[UA_TYPES_STRING]);
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 20001),
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 20001),
-                            UA_NODEID_NUMERIC(1, 20000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
-                            UA_QUALIFIEDNAME(1, "Species"), UA_NODEID_NULL, vAttr, NULL, NULL);
-
-    UA_VariableAttributes_init(&vAttr);
-    vAttr.description =  UA_LOCALIZEDTEXT("en_US", "This dogs name");
-    vAttr.displayName =  UA_LOCALIZEDTEXT("en_US", "Name");
+                              UA_NODEID_NUMERIC(1, 20000),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
+                              UA_QUALIFIEDNAME(1, "Species"), UA_NODEID_NULL,
+                              vAttr, NULL, NULL);
+
+    vAttr = UA_VariableAttributes_default;
+    vAttr.description =  UA_LOCALIZEDTEXT("en-US", "This dogs name");
+    vAttr.displayName =  UA_LOCALIZEDTEXT("en-US", "Name");
     UA_String defaultName = UA_STRING("unnamed dog");
     UA_String defaultName = UA_STRING("unnamed dog");
-    UA_Variant_setScalarCopy(&vAttr.value, &defaultName, &UA_TYPES[UA_TYPES_STRING]);
+    UA_Variant_setScalar(&vAttr.value, &defaultName, &UA_TYPES[UA_TYPES_STRING]);
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 20002),
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 20002),
-                              UA_NODEID_NUMERIC(1, 20000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
-                              UA_QUALIFIEDNAME(1, "Name"), UA_NODEID_NULL, vAttr, NULL, NULL);
-
+                              UA_NODEID_NUMERIC(1, 20000),
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
+                              UA_QUALIFIEDNAME(1, "Name"), UA_NODEID_NULL,
+                              vAttr, NULL, NULL);
 
 
     /* Instatiate a dog named bello:
     /* Instatiate a dog named bello:
      * (O) Objects
      * (O) Objects
@@ -106,33 +99,36 @@ int main(void) {
      *     + Name
      *     + Name
      */
      */
 
 
-    UA_ObjectAttributes oAttr;
-    UA_ObjectAttributes_init(&oAttr);
-    oAttr.description = UA_LOCALIZEDTEXT("en_US", "A dog named Bello");
-    oAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Bello");
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    oAttr.description = UA_LOCALIZEDTEXT("en-US", "A dog named Bello");
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Bello");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                            UA_QUALIFIEDNAME(1, "Bello"), UA_NODEID_NUMERIC(1, 20000), oAttr, NULL, NULL);
-
-
-    UA_ObjectAttributes_init(&oAttr);
-    oAttr.description = UA_LOCALIZEDTEXT("en_US", "Another dog");
-    oAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Dog2");
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "Bello"), UA_NODEID_NUMERIC(1, 20000),
+                            oAttr, NULL, NULL);
+
+    oAttr = UA_ObjectAttributes_default;
+    oAttr.description = UA_LOCALIZEDTEXT("en-US", "Another dog");
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Dog2");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                            UA_QUALIFIEDNAME(1, "Dog2"), UA_NODEID_NUMERIC(1, 20000), oAttr, NULL, NULL);
-
-
-    UA_ObjectAttributes_init(&oAttr);
-    oAttr.description = UA_LOCALIZEDTEXT("en_US", "A mamal");
-    oAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Mamal1");
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "Dog2"), UA_NODEID_NUMERIC(1, 20000),
+                            oAttr, NULL, NULL);
+
+    oAttr = UA_ObjectAttributes_default;
+    oAttr.description = UA_LOCALIZEDTEXT("en-US", "A mamal");
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Mamal1");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                            UA_QUALIFIEDNAME(1, "Mamal1"), UA_NODEID_NUMERIC(1, 10000), oAttr, NULL, NULL);
-
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "Mamal1"), UA_NODEID_NUMERIC(1, 10000),
+                            oAttr, NULL, NULL);
 
 
+    /* Run the server */
     retval = UA_Server_run(server, &running);
     retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     return (int)retval;
     return (int)retval;
 }
 }

+ 27 - 39
examples/server_instantiation.c

@@ -2,15 +2,7 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 
 #include <signal.h>
 #include <signal.h>
-
-#ifdef UA_NO_AMALGAMATION
-#include "ua_types.h"
-#include "ua_server.h"
-#include "ua_config_standard.h"
-#include "ua_network_tcp.h"
-#else
 #include "open62541.h"
 #include "open62541.h"
-#endif
 
 
 UA_Boolean running = true;
 UA_Boolean running = true;
 static void stopHandler(int sig) {
 static void stopHandler(int sig) {
@@ -21,10 +13,7 @@ int main(void) {
     signal(SIGINT,  stopHandler);
     signal(SIGINT,  stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
     
     
     /* Create a rudimentary objectType
     /* Create a rudimentary objectType
@@ -38,37 +27,35 @@ int main(void) {
      *      + (V) Name
      *      + (V) Name
      */ 
      */ 
     UA_StatusCode retval;
     UA_StatusCode retval;
-    UA_ObjectTypeAttributes otAttr;
-    UA_ObjectTypeAttributes_init(&otAttr);
-    
-    otAttr.description = UA_LOCALIZEDTEXT("en_US", "A mamal");
-    otAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MamalType");
+    UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default;
+    otAttr.description = UA_LOCALIZEDTEXT("en-US", "A mamal");
+    otAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MamalType");
     UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 10000), 
     UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 10000), 
-                                UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "MamalType"), otAttr, NULL, NULL);
                                 UA_QUALIFIEDNAME(1, "MamalType"), otAttr, NULL, NULL);
   
   
-    UA_VariableAttributes   vAttr;
-    UA_VariableAttributes_init(&vAttr);
-    vAttr.description =  UA_LOCALIZEDTEXT("en_US", "This mamals Age in months");
-    vAttr.displayName =  UA_LOCALIZEDTEXT("en_US", "Age");
+    UA_VariableAttributes vAttr = UA_VariableAttributes_default;
+    vAttr.description =  UA_LOCALIZEDTEXT("en-US", "This mamals Age in months");
+    vAttr.displayName =  UA_LOCALIZEDTEXT("en-US", "Age");
     UA_UInt32 ageVar = 0;
     UA_UInt32 ageVar = 0;
-    UA_Variant_setScalarCopy(&vAttr.value, &ageVar, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_Variant_setScalar(&vAttr.value, &ageVar, &UA_TYPES[UA_TYPES_UINT32]);
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10001), 
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10001), 
                               UA_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               UA_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               UA_QUALIFIEDNAME(1, "Age"), UA_NODEID_NULL, vAttr, NULL, NULL);
                               UA_QUALIFIEDNAME(1, "Age"), UA_NODEID_NULL, vAttr, NULL, NULL);
   
   
-    UA_ObjectTypeAttributes_init(&otAttr);
-    otAttr.description = UA_LOCALIZEDTEXT("en_US", "A dog, subtype of mamal");
-    otAttr.displayName = UA_LOCALIZEDTEXT("en_US", "DogType");
-    UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 10002), 
+    otAttr = UA_ObjectTypeAttributes_default;
+    otAttr.description = UA_LOCALIZEDTEXT("en-US", "A dog, subtype of mamal");
+    otAttr.displayName = UA_LOCALIZEDTEXT("en-US", "DogType");
+    UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 10002),
                                 UA_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "DogType"), otAttr, NULL, NULL);
                                 UA_QUALIFIEDNAME(1, "DogType"), otAttr, NULL, NULL);
     
     
-    UA_VariableAttributes_init(&vAttr);
-    vAttr.description =  UA_LOCALIZEDTEXT("en_US", "This mamals Age in months");
-    vAttr.displayName =  UA_LOCALIZEDTEXT("en_US", "Name");
+    vAttr = UA_VariableAttributes_default;
+    vAttr.description =  UA_LOCALIZEDTEXT("en-US", "This mamals Age in months");
+    vAttr.displayName =  UA_LOCALIZEDTEXT("en-US", "Name");
     UA_String defaultName = UA_STRING("unnamed dog");
     UA_String defaultName = UA_STRING("unnamed dog");
-    UA_Variant_setScalarCopy(&vAttr.value, &defaultName, &UA_TYPES[UA_TYPES_STRING]);
+    UA_Variant_setScalar(&vAttr.value, &defaultName, &UA_TYPES[UA_TYPES_STRING]);
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10003), 
     UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, 10003), 
                               UA_NODEID_NUMERIC(1, 10002), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               UA_NODEID_NUMERIC(1, 10002), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               UA_QUALIFIEDNAME(1, "Name"), UA_NODEID_NULL, vAttr, NULL, NULL);
                               UA_QUALIFIEDNAME(1, "Name"), UA_NODEID_NULL, vAttr, NULL, NULL);
@@ -80,16 +67,17 @@ int main(void) {
      *     + Name
      *     + Name
      */
      */
     
     
-    UA_ObjectAttributes oAttr;
-    UA_ObjectAttributes_init(&oAttr);
-    oAttr.description = UA_LOCALIZEDTEXT("en_US", "A dog named Bello");
-    oAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Bello");
-    UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0), 
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                            UA_QUALIFIEDNAME(1, "Bello"), UA_NODEID_NUMERIC(1, 10002), oAttr, NULL, NULL);
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    oAttr.description = UA_LOCALIZEDTEXT("en-US", "A dog named Bello");
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Bello");
+    UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 0),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                            UA_QUALIFIEDNAME(1, "Bello"), UA_NODEID_NUMERIC(1, 10002),
+                            oAttr, NULL, NULL);
     
     
     retval = UA_Server_run(server, &running);
     retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     return (int)retval;
     return (int)retval;
 }
 }

+ 13 - 22
examples/server_mainloop.c

@@ -9,22 +9,11 @@
 #else
 #else
 # include <sys/select.h>
 # include <sys/select.h>
 #endif
 #endif
-
-#ifdef UA_NO_AMALGAMATION
-# include "ua_types.h"
-# include "ua_server.h"
-# include "ua_config_standard.h"
-# include "ua_network_tcp.h"
-# include "ua_log_stdout.h"
-#else
 # include "open62541.h"
 # include "open62541.h"
-#endif
 
 
 UA_Boolean running = true;
 UA_Boolean running = true;
-UA_Logger logger = UA_Log_Stdout;
-
 static void stopHandler(int sign) {
 static void stopHandler(int sign) {
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
     running = false;
     running = false;
 }
 }
 
 
@@ -32,26 +21,28 @@ static void stopHandler(int sign) {
    can be for example the event-loop used in GUI toolkits, such as Qt or GTK. */
    can be for example the event-loop used in GUI toolkits, such as Qt or GTK. */
 
 
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
-    signal(SIGINT, stopHandler); /* catches ctrl-c */
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
-    UA_StatusCode retval = UA_Server_run_startup(server);
-    if(retval != UA_STATUSCODE_GOOD)
-        goto cleanup;
-
     /* Should the server networklayer block (with a timeout) until a message
     /* Should the server networklayer block (with a timeout) until a message
        arrives or should it return immediately? */
        arrives or should it return immediately? */
     UA_Boolean waitInternal = false;
     UA_Boolean waitInternal = false;
 
 
+    UA_StatusCode retval = UA_Server_run_startup(server);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto cleanup;
+
     while(running) {
     while(running) {
         /* timeout is the maximum possible delay (in millisec) until the next
         /* timeout is the maximum possible delay (in millisec) until the next
            _iterate call. Otherwise, the server might miss an internal timeout
            _iterate call. Otherwise, the server might miss an internal timeout
            or cannot react to messages with the promised responsiveness. */
            or cannot react to messages with the promised responsiveness. */
+        /* If multicast discovery server is enabled, the timeout does not not consider new input data (requests) on the mDNS socket.
+         * It will be handled on the next call, which may be too late for requesting clients.
+         * if needed, the select with timeout on the multicast socket server->mdnsSocket (see example in mdnsd library)
+         */
         UA_UInt16 timeout = UA_Server_run_iterate(server, waitInternal);
         UA_UInt16 timeout = UA_Server_run_iterate(server, waitInternal);
 
 
         /* Now we can use the max timeout to do something else. In this case, we
         /* Now we can use the max timeout to do something else. In this case, we
@@ -66,6 +57,6 @@ int main(int argc, char** argv) {
 
 
  cleanup:
  cleanup:
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     return (int)retval;
     return (int)retval;
 }
 }

+ 0 - 53
examples/server_nodeset.c

@@ -1,53 +0,0 @@
-/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
- * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
-
-#include <signal.h>
-#include <stdlib.h>
-
-#ifdef UA_NO_AMALGAMATION
-# include "ua_types.h"
-# include "ua_server.h"
-# include "ua_config_standard.h"
-# include "ua_network_tcp.h"
-# include "ua_log_stdout.h"
-#else
-# include "open62541.h"
-#endif
-
-/* files nodeset.h and nodeset.c are created from server_nodeset.xml in the /src_generated directory by CMake */
-#include "nodeset.h"
-
-UA_Logger logger = UA_Log_Stdout;
-UA_Boolean running = true;
-
-static void stopHandler(int sign) {
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_SERVER, "received ctrl-c");
-    running = false;
-}
-
-int main(int argc, char** argv) {
-    signal(SIGINT, stopHandler); /* catches ctrl-c */
-
-    /* initialize the server */
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
-    UA_Server *server = UA_Server_new(config);
-
-    /* create nodes from nodeset */
-    if (nodeset(server) != UA_STATUSCODE_GOOD) {
-        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER, "Namespace index for generated nodeset does not match. The call to the generated method has to be before any other namespace add calls.");
-        UA_Server_delete(server);
-        nl.deleteMembers(&nl);
-        return (int)UA_STATUSCODE_BADUNEXPECTEDERROR;
-    }
-
-    /* start server */
-    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 (int)retval;
-}

+ 7 - 21
examples/server_repeated_job.c

@@ -2,16 +2,7 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 
 #include <signal.h>
 #include <signal.h>
-
-#ifdef UA_NO_AMALGAMATION
-# include "ua_types.h"
-# include "ua_server.h"
-# include "ua_config_standard.h"
-# include "ua_network_tcp.h"
-# include "ua_log_stdout.h"
-#else
-# include "open62541.h"
-#endif
+#include "open62541.h"
 
 
 static void
 static void
 testCallback(UA_Server *server, void *data) {
 testCallback(UA_Server *server, void *data) {
@@ -28,19 +19,14 @@ int main(void) {
     signal(SIGINT, stopHandler);
     signal(SIGINT, stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     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 */
+    /* Add a repeated callback to the server */
+    UA_Server_addRepeatedCallback(server, testCallback, NULL, 2000, NULL); /* call every 2 sec */
 
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-    return 0;
+    UA_ServerConfig_delete(config);
+    return (int)retval;
 }
 }

+ 3 - 15
examples/server_udp.c

@@ -4,22 +4,11 @@
  */
  */
 #include <stdio.h>
 #include <stdio.h>
 #include <signal.h>
 #include <signal.h>
-
-#ifdef UA_NO_AMALGAMATION
-#include "ua_types.h"
-#include "ua_server.h"
-#include "ua_config_standard.h"
-#include "ua_log_stdout.h"
-#include "ua_network_udp.h"
-#else
 #include "open62541.h"
 #include "open62541.h"
-#endif
-
 
 
 UA_Logger logger = UA_Log_Stdout;
 UA_Logger logger = UA_Log_Stdout;
 
 
 UA_Boolean running = 1;
 UA_Boolean running = 1;
-
 static void stopHandler(int sign) {
 static void stopHandler(int sign) {
     printf("Received Ctrl-C\n");
     printf("Received Ctrl-C\n");
     running = 0;
     running = 0;
@@ -37,12 +26,11 @@ int main(int argc, char** argv) {
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
     // add a variable node to the adresspace
     // add a variable node to the adresspace
-    UA_VariableAttributes attr;
-    UA_VariableAttributes_init(&attr);
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
-    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
+    attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);

+ 131 - 0
examples/tutorial_client_events.c

@@ -0,0 +1,131 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include <signal.h>
+#include "open62541.h"
+
+static UA_Boolean running = true;
+static void stopHandler(int sig) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
+    running = false;
+}
+
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+static void
+handler_events(const UA_UInt32 monId, const size_t nEventFields, const UA_Variant *eventFields, void *context) {
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Notification");
+    for(size_t i = 0; i < nEventFields; ++i) {
+        if (UA_Variant_hasScalarType(&eventFields[i], &UA_TYPES[UA_TYPES_UINT16])) {
+            UA_UInt16 severity = *(UA_UInt16 *)eventFields[i].data;
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Severity: %u", severity);
+        } else if (UA_Variant_hasScalarType(&eventFields[i], &UA_TYPES[UA_TYPES_LOCALIZEDTEXT])) {
+            UA_LocalizedText *lt = (UA_LocalizedText *)eventFields[i].data;
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                        "Message: '%.*s'", (int)lt->text.length, lt->text.data);
+        }
+        else {
+            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
+                        "Don't know how to handle type: '%s'", eventFields[i].type->typeName);
+        }
+    }
+}
+
+const size_t nSelectClauses = 2;
+
+static UA_SimpleAttributeOperand *
+setupSelectClauses(void) {
+    UA_SimpleAttributeOperand *selectClauses = (UA_SimpleAttributeOperand*)
+        UA_Array_new(nSelectClauses, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
+    if(!selectClauses)
+        return NULL;
+
+    for(size_t i =0; i<nSelectClauses; ++i) {
+        UA_SimpleAttributeOperand_init(&selectClauses[i]);
+    }
+
+    selectClauses[0].typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
+    selectClauses[0].browsePathSize = 1;
+    selectClauses[0].browsePath = (UA_QualifiedName*)UA_Array_new(selectClauses[0].browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+    if(!selectClauses[0].browsePath) {
+        UA_SimpleAttributeOperand_delete(selectClauses);
+        return NULL;
+    }
+    selectClauses[0].attributeId = UA_ATTRIBUTEID_VALUE;
+    selectClauses[0].browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, "Message");
+
+    selectClauses[1].typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
+    selectClauses[1].browsePathSize = 1;
+    selectClauses[1].browsePath = (UA_QualifiedName*)UA_Array_new(selectClauses[1].browsePathSize, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+    if(!selectClauses[1].browsePath) {
+        UA_SimpleAttributeOperand_deleteMembers(selectClauses);
+        UA_SimpleAttributeOperand_delete(selectClauses);
+        return NULL;
+    }
+    selectClauses[1].attributeId = UA_ATTRIBUTEID_VALUE;
+    selectClauses[1].browsePath[0] = UA_QUALIFIEDNAME_ALLOC(0, "Severity");
+
+    return selectClauses;
+}
+
+#endif
+
+int main(int argc, char *argv[]) {
+    signal(SIGINT, stopHandler);
+    signal(SIGTERM, stopHandler);
+
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+
+    UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://uademo.prosysopc.com:53530/OPCUA/SimulationServer");
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Client_delete(client);
+        return (int)retval;
+    }
+
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+    /* Create a subscription */
+    UA_UInt32 subId = 0;
+    retval = UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_default, &subId);
+    if(!subId) {
+        UA_Client_disconnect(client);
+        UA_Client_delete(client);
+        return (int)retval;
+    }
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Create subscription succeeded, id %u", subId);
+
+    /* Add a MonitoredItem */
+    UA_NodeId monitorThis = UA_NODEID_NUMERIC(0, 2253); // Root->Objects->Server
+    UA_UInt32 monId = 0;
+
+    UA_SimpleAttributeOperand *selectClauses = setupSelectClauses();
+    if(!selectClauses){
+        UA_Client_Subscriptions_remove(client, subId);
+        UA_Client_disconnect(client);
+        UA_Client_delete(client);
+        return (int)UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    UA_Client_Subscriptions_addMonitoredEvent(client, subId, monitorThis, UA_ATTRIBUTEID_EVENTNOTIFIER,
+                                              selectClauses, nSelectClauses,
+                                              NULL, 0,
+                                              &handler_events, NULL, &monId);
+    if (!monId) {
+        UA_Array_delete(selectClauses, nSelectClauses, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
+        UA_Client_Subscriptions_remove(client, subId);
+        UA_Client_disconnect(client);
+        UA_Client_delete(client);
+        return (int)retval;
+    }
+    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Monitoring 'Root->Objects->Server', id %u", subId);
+
+    while (running)
+        UA_Client_Subscriptions_manuallySendPublishRequest(client);
+
+    /* Delete the subscription */
+    if(!UA_Client_Subscriptions_remove(client, subId))
+        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Subscription removed");
+#endif
+
+    UA_Client_disconnect(client);
+    UA_Client_delete(client);
+    return (int) UA_STATUSCODE_GOOD;
+}

+ 1 - 2
examples/tutorial_client_firststeps.c

@@ -4,7 +4,6 @@
 /**
 /**
  * Building a Simple Client
  * Building a Simple Client
  * ------------------------
  * ------------------------
-
  * You should already have a basic server from the previous tutorials. open62541
  * You should already have a basic server from the previous tutorials. open62541
  * provides both a server- and clientside API, so creating a client is as easy as
  * provides both a server- and clientside API, so creating a client is as easy as
  * creating a server. Copy the following into a file `myClient.c`: */
  * creating a server. Copy the following into a file `myClient.c`: */
@@ -13,7 +12,7 @@
 #include "open62541.h"
 #include "open62541.h"
 
 
 int main(void) {
 int main(void) {
-    UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
     UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
     UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         UA_Client_delete(client);

+ 2 - 2
examples/tutorial_datatypes.c

@@ -55,7 +55,7 @@ variables_basic(void) {
 
 
     cr.requestHeader.timestamp = UA_DateTime_now(); /* Members of a structure */
     cr.requestHeader.timestamp = UA_DateTime_now(); /* Members of a structure */
 
 
-    cr.methodsToCall = UA_Array_new(5, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST]);
+    cr.methodsToCall = (UA_CallMethodRequest *)UA_Array_new(5, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST]);
     cr.methodsToCallSize = 5; /* Array size needs to be made known */
     cr.methodsToCallSize = 5; /* Array size needs to be made known */
 
 
     UA_CallRequest *cr2 = UA_CallRequest_new();
     UA_CallRequest *cr2 = UA_CallRequest_new();
@@ -120,7 +120,7 @@ variables_variants(void) {
     UA_Variant_setArrayCopy(&v3, d, 9, &UA_TYPES[UA_TYPES_DOUBLE]);
     UA_Variant_setArrayCopy(&v3, d, 9, &UA_TYPES[UA_TYPES_DOUBLE]);
 
 
     /* Set array dimensions */
     /* Set array dimensions */
-    v3.arrayDimensions = UA_Array_new(2, &UA_TYPES[UA_TYPES_UINT32]);
+    v3.arrayDimensions = (UA_UInt32 *)UA_Array_new(2, &UA_TYPES[UA_TYPES_UINT32]);
     v3.arrayDimensionsSize = 2;
     v3.arrayDimensionsSize = 2;
     v3.arrayDimensions[0] = 3;
     v3.arrayDimensions[0] = 3;
     v3.arrayDimensions[1] = 3;
     v3.arrayDimensions[1] = 3;

+ 28 - 26
examples/tutorial_server_datasource.c

@@ -40,9 +40,9 @@ updateCurrentTime(UA_Server *server) {
 static void
 static void
 addCurrentTimeVariable(UA_Server *server) {
 addCurrentTimeVariable(UA_Server *server) {
     UA_DateTime now = 0;
     UA_DateTime now = 0;
-    UA_VariableAttributes attr;
-    UA_VariableAttributes_init(&attr);
-    attr.displayName = UA_LOCALIZEDTEXT("en_US", "Current time");
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
     UA_Variant_setScalar(&attr.value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
 
 
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
@@ -68,9 +68,10 @@ addCurrentTimeVariable(UA_Server *server) {
  * write operation. */
  * write operation. */
 
 
 static void
 static void
-beforeReadTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
-               const UA_NumericRange *range) {
-    UA_Server *server = (UA_Server*)handle;
+beforeReadTime(UA_Server *server,
+               const UA_NodeId *sessionId, void *sessionContext,
+               const UA_NodeId *nodeid, void *nodeContext, 
+               const UA_NumericRange *range, const UA_DataValue *data) {
     UA_DateTime now = UA_DateTime_now();
     UA_DateTime now = UA_DateTime_now();
     UA_Variant value;
     UA_Variant value;
     UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
     UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
@@ -79,8 +80,10 @@ beforeReadTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
 }
 }
 
 
 static void
 static void
-afterWriteTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
-               const UA_NumericRange *range) {
+afterWriteTime(UA_Server *server,
+               const UA_NodeId *sessionId, void *sessionContext,
+               const UA_NodeId *nodeId, void *nodeContext,
+               const UA_NumericRange *range, const UA_DataValue *data) {
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                 "The variable was updated");
                 "The variable was updated");
 }
 }
@@ -89,7 +92,6 @@ static void
 addValueCallbackToCurrentTimeVariable(UA_Server *server) {
 addValueCallbackToCurrentTimeVariable(UA_Server *server) {
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
     UA_ValueCallback callback ;
     UA_ValueCallback callback ;
-    callback.handle = server;
     callback.onRead = beforeReadTime;
     callback.onRead = beforeReadTime;
     callback.onWrite = afterWriteTime;
     callback.onWrite = afterWriteTime;
     UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);
     UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);
@@ -106,8 +108,11 @@ addValueCallbackToCurrentTimeVariable(UA_Server *server) {
  * own memory management. */
  * own memory management. */
 
 
 static UA_StatusCode
 static UA_StatusCode
-readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
-                const UA_NumericRange *range, UA_DataValue *dataValue) {
+readCurrentTime(UA_Server *server,
+                const UA_NodeId *sessionId, void *sessionContext,
+                const UA_NodeId *nodeId, void *nodeContext,
+                UA_Boolean sourceTimeStamp, const UA_NumericRange *range,
+                UA_DataValue *dataValue) {
     UA_DateTime now = UA_DateTime_now();
     UA_DateTime now = UA_DateTime_now();
     UA_Variant_setScalarCopy(&dataValue->value, &now,
     UA_Variant_setScalarCopy(&dataValue->value, &now,
                              &UA_TYPES[UA_TYPES_DATETIME]);
                              &UA_TYPES[UA_TYPES_DATETIME]);
@@ -116,8 +121,10 @@ readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
-writeCurrentTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
-                 const UA_NumericRange *range) {
+writeCurrentTime(UA_Server *server,
+                 const UA_NodeId *sessionId, void *sessionContext,
+                 const UA_NodeId *nodeId, void *nodeContext,
+                 const UA_NumericRange *range, const UA_DataValue *data) {
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                 "Changing the system time is not implemented");
                 "Changing the system time is not implemented");
     return UA_STATUSCODE_BADINTERNALERROR;
     return UA_STATUSCODE_BADINTERNALERROR;
@@ -125,9 +132,9 @@ writeCurrentTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
 
 
 static void
 static void
 addCurrentTimeDataSourceVariable(UA_Server *server) {
 addCurrentTimeDataSourceVariable(UA_Server *server) {
-    UA_VariableAttributes attr;
-    UA_VariableAttributes_init(&attr);
-    attr.displayName = UA_LOCALIZEDTEXT("en_US", "Current time - data source");
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("en-US", "Current time - data source");
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
 
 
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-datasource");
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time-datasource");
     UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-datasource");
     UA_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-datasource");
@@ -136,13 +143,12 @@ addCurrentTimeDataSourceVariable(UA_Server *server) {
     UA_NodeId variableTypeNodeId = UA_NODEID_NULL;
     UA_NodeId variableTypeNodeId = UA_NODEID_NULL;
 
 
     UA_DataSource timeDataSource;
     UA_DataSource timeDataSource;
-    timeDataSource.handle = NULL;
     timeDataSource.read = readCurrentTime;
     timeDataSource.read = readCurrentTime;
     timeDataSource.write = writeCurrentTime;
     timeDataSource.write = writeCurrentTime;
     UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId,
     UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId,
                                         parentReferenceNodeId, currentName,
                                         parentReferenceNodeId, currentName,
                                         variableTypeNodeId, attr,
                                         variableTypeNodeId, attr,
-                                        timeDataSource, NULL);
+                                        timeDataSource, NULL, NULL);
 }
 }
 
 
 /** It follows the main server code, making use of the above definitions. */
 /** It follows the main server code, making use of the above definitions. */
@@ -157,21 +163,17 @@ int main(void) {
     signal(SIGINT, stopHandler);
     signal(SIGINT, stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl =
-        UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
     addCurrentTimeVariable(server);
     addCurrentTimeVariable(server);
     addValueCallbackToCurrentTimeVariable(server);
     addValueCallbackToCurrentTimeVariable(server);
     addCurrentTimeDataSourceVariable(server);
     addCurrentTimeDataSourceVariable(server);
 
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-    return 0;
+    UA_ServerConfig_delete(config);
+    return (int)retval;
 }
 }
 
 
 /**
 /**

+ 4 - 9
examples/tutorial_server_firststeps.c

@@ -33,18 +33,13 @@ int main(void) {
     signal(SIGINT, stopHandler);
     signal(SIGINT, stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl =
-        UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 4840);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
-    UA_Server_run(server, &running);
-
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-    return 0;
+    UA_ServerConfig_delete(config);
+    return (int)retval;
 }
 }
 
 
 /**
 /**

+ 29 - 28
examples/tutorial_server_method.c

@@ -34,13 +34,16 @@
 #include "open62541.h"
 #include "open62541.h"
 
 
 static UA_StatusCode
 static UA_StatusCode
-helloWorldMethodCallback(void *handle, const UA_NodeId objectId,
+helloWorldMethodCallback(UA_Server *server,
+                         const UA_NodeId *sessionId, void *sessionHandle,
+                         const UA_NodeId *methodId, void *methodContext,
+                         const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
                          size_t outputSize, UA_Variant *output) {
     UA_String *inputStr = (UA_String*)input->data;
     UA_String *inputStr = (UA_String*)input->data;
     UA_String tmp = UA_STRING_ALLOC("Hello ");
     UA_String tmp = UA_STRING_ALLOC("Hello ");
     if(inputStr->length > 0) {
     if(inputStr->length > 0) {
-        tmp.data = realloc(tmp.data, tmp.length + inputStr->length);
+        tmp.data = (UA_Byte *)UA_realloc(tmp.data, tmp.length + inputStr->length);
         memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length);
         memcpy(&tmp.data[tmp.length], inputStr->data, inputStr->length);
         tmp.length += inputStr->length;
         tmp.length += inputStr->length;
     }
     }
@@ -54,30 +57,29 @@ static void
 addHellWorldMethod(UA_Server *server) {
 addHellWorldMethod(UA_Server *server) {
     UA_Argument inputArgument;
     UA_Argument inputArgument;
     UA_Argument_init(&inputArgument);
     UA_Argument_init(&inputArgument);
-    inputArgument.description = UA_LOCALIZEDTEXT("en_US", "A String");
+    inputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String");
     inputArgument.name = UA_STRING("MyInput");
     inputArgument.name = UA_STRING("MyInput");
     inputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArgument.valueRank = -1; /* scalar */
     inputArgument.valueRank = -1; /* scalar */
 
 
     UA_Argument outputArgument;
     UA_Argument outputArgument;
     UA_Argument_init(&outputArgument);
     UA_Argument_init(&outputArgument);
-    outputArgument.description = UA_LOCALIZEDTEXT("en_US", "A String");
+    outputArgument.description = UA_LOCALIZEDTEXT("en-US", "A String");
     outputArgument.name = UA_STRING("MyOutput");
     outputArgument.name = UA_STRING("MyOutput");
     outputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArgument.valueRank = -1; /* scalar */
     outputArgument.valueRank = -1; /* scalar */
 
 
-    UA_MethodAttributes helloAttr;
-    UA_MethodAttributes_init(&helloAttr);
-    helloAttr.description = UA_LOCALIZEDTEXT("en_US","Say `Hello World`");
-    helloAttr.displayName = UA_LOCALIZEDTEXT("en_US","Hello World");
+    UA_MethodAttributes helloAttr = UA_MethodAttributes_default;
+    helloAttr.description = UA_LOCALIZEDTEXT("en-US","Say `Hello World`");
+    helloAttr.displayName = UA_LOCALIZEDTEXT("en-US","Hello World");
     helloAttr.executable = true;
     helloAttr.executable = true;
     helloAttr.userExecutable = true;
     helloAttr.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                             UA_QUALIFIEDNAME(1, "hello world"),
                             UA_QUALIFIEDNAME(1, "hello world"),
-                            helloAttr, &helloWorldMethodCallback, NULL,
-                            1, &inputArgument, 1, &outputArgument, NULL);
+                            helloAttr, &helloWorldMethodCallback,
+                            1, &inputArgument, 1, &outputArgument, NULL, NULL);
 }
 }
 
 
 /**
 /**
@@ -87,7 +89,10 @@ addHellWorldMethod(UA_Server *server) {
  * copy of the array with every entry increased by the scalar. */
  * copy of the array with every entry increased by the scalar. */
 
 
 static UA_StatusCode
 static UA_StatusCode
-IncInt32ArrayMethodCallback(void *handle, const UA_NodeId objectId,
+IncInt32ArrayMethodCallback(UA_Server *server,
+                            const UA_NodeId *sessionId, void *sessionContext,
+                            const UA_NodeId *methodId, void *methodContext,
+                            const UA_NodeId *objectId, void *objectContext,
                             size_t inputSize, const UA_Variant *input,
                             size_t inputSize, const UA_Variant *input,
                             size_t outputSize, UA_Variant *output) {
                             size_t outputSize, UA_Variant *output) {
     UA_Int32 *inputArray = (UA_Int32*)input[0].data;
     UA_Int32 *inputArray = (UA_Int32*)input[0].data;
@@ -112,7 +117,7 @@ addIncInt32ArrayMethod(UA_Server *server) {
     /* Two input arguments */
     /* Two input arguments */
     UA_Argument inputArguments[2];
     UA_Argument inputArguments[2];
     UA_Argument_init(&inputArguments[0]);
     UA_Argument_init(&inputArguments[0]);
-    inputArguments[0].description = UA_LOCALIZEDTEXT("en_US", "int32[5] array");
+    inputArguments[0].description = UA_LOCALIZEDTEXT("en-US", "int32[5] array");
     inputArguments[0].name = UA_STRING("int32 array");
     inputArguments[0].name = UA_STRING("int32 array");
     inputArguments[0].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     inputArguments[0].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     inputArguments[0].valueRank = 1;
     inputArguments[0].valueRank = 1;
@@ -121,7 +126,7 @@ addIncInt32ArrayMethod(UA_Server *server) {
     inputArguments[0].arrayDimensions = &pInputDimension;
     inputArguments[0].arrayDimensions = &pInputDimension;
 
 
     UA_Argument_init(&inputArguments[1]);
     UA_Argument_init(&inputArguments[1]);
-    inputArguments[1].description = UA_LOCALIZEDTEXT("en_US", "int32 delta");
+    inputArguments[1].description = UA_LOCALIZEDTEXT("en-US", "int32 delta");
     inputArguments[1].name = UA_STRING("int32 delta");
     inputArguments[1].name = UA_STRING("int32 delta");
     inputArguments[1].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     inputArguments[1].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     inputArguments[1].valueRank = -1; /* scalar */
     inputArguments[1].valueRank = -1; /* scalar */
@@ -129,7 +134,7 @@ addIncInt32ArrayMethod(UA_Server *server) {
     /* One output argument */
     /* One output argument */
     UA_Argument outputArgument;
     UA_Argument outputArgument;
     UA_Argument_init(&outputArgument);
     UA_Argument_init(&outputArgument);
-    outputArgument.description = UA_LOCALIZEDTEXT("en_US", "int32[5] array");
+    outputArgument.description = UA_LOCALIZEDTEXT("en-US", "int32[5] array");
     outputArgument.name = UA_STRING("each entry is incremented by the delta");
     outputArgument.name = UA_STRING("each entry is incremented by the delta");
     outputArgument.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     outputArgument.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     outputArgument.valueRank = 1;
     outputArgument.valueRank = 1;
@@ -138,18 +143,18 @@ addIncInt32ArrayMethod(UA_Server *server) {
     outputArgument.arrayDimensions = &pOutputDimension;
     outputArgument.arrayDimensions = &pOutputDimension;
 
 
     /* Add the method node */
     /* Add the method node */
-    UA_MethodAttributes incAttr;
-    UA_MethodAttributes_init(&incAttr);
-    incAttr.description = UA_LOCALIZEDTEXT("en_US", "IncInt32ArrayValues");
-    incAttr.displayName = UA_LOCALIZEDTEXT("en_US", "IncInt32ArrayValues");
+    UA_MethodAttributes incAttr = UA_MethodAttributes_default;
+    incAttr.description = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues");
+    incAttr.displayName = UA_LOCALIZEDTEXT("en-US", "IncInt32ArrayValues");
     incAttr.executable = true;
     incAttr.executable = true;
     incAttr.userExecutable = true;
     incAttr.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"),
     UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                             UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
                             UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
-                            incAttr, &IncInt32ArrayMethodCallback, NULL,
-                            2, inputArguments, 1, &outputArgument, NULL);
+                            incAttr, &IncInt32ArrayMethodCallback,
+                            2, inputArguments, 1, &outputArgument,
+                            NULL, NULL);
 }
 }
 
 
 /** It follows the main server code, making use of the above definitions. */
 /** It follows the main server code, making use of the above definitions. */
@@ -164,18 +169,14 @@ int main(void) {
     signal(SIGINT, stopHandler);
     signal(SIGINT, stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl =
-        UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
     addHellWorldMethod(server);
     addHellWorldMethod(server);
     addIncInt32ArrayMethod(server);
     addIncInt32ArrayMethod(server);
 
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-    return 0;
+    UA_ServerConfig_delete(config);
+    return (int)retval;
 }
 }

+ 44 - 60
examples/tutorial_server_object.c

@@ -61,50 +61,45 @@
 static void
 static void
 manuallyDefinePump(UA_Server *server) {
 manuallyDefinePump(UA_Server *server) {
     UA_NodeId pumpId; /* get the nodeid assigned by the server */
     UA_NodeId pumpId; /* get the nodeid assigned by the server */
-    UA_ObjectAttributes oAttr;
-    UA_ObjectAttributes_init(&oAttr);
-    oAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Pump (Manual)");
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Pump (Manual)");
     UA_Server_addObjectNode(server, UA_NODEID_NULL,
     UA_Server_addObjectNode(server, UA_NODEID_NULL,
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Pump (Manual)"), UA_NODEID_NULL,
                             UA_QUALIFIEDNAME(1, "Pump (Manual)"), UA_NODEID_NULL,
                             oAttr, NULL, &pumpId);
                             oAttr, NULL, &pumpId);
 
 
-    UA_VariableAttributes mnAttr;
-    UA_VariableAttributes_init(&mnAttr);
+    UA_VariableAttributes mnAttr = UA_VariableAttributes_default;
     UA_String manufacturerName = UA_STRING("Pump King Ltd.");
     UA_String manufacturerName = UA_STRING("Pump King Ltd.");
     UA_Variant_setScalar(&mnAttr.value, &manufacturerName, &UA_TYPES[UA_TYPES_STRING]);
     UA_Variant_setScalar(&mnAttr.value, &manufacturerName, &UA_TYPES[UA_TYPES_STRING]);
-    mnAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ManufacturerName");
+    mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName");
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "ManufacturerName"),
                               UA_QUALIFIEDNAME(1, "ManufacturerName"),
                               UA_NODEID_NULL, mnAttr, NULL, NULL);
                               UA_NODEID_NULL, mnAttr, NULL, NULL);
 
 
-    UA_VariableAttributes modelAttr;
-    UA_VariableAttributes_init(&modelAttr);
+    UA_VariableAttributes modelAttr = UA_VariableAttributes_default;
     UA_String modelName = UA_STRING("Mega Pump 3000");
     UA_String modelName = UA_STRING("Mega Pump 3000");
     UA_Variant_setScalar(&modelAttr.value, &modelName, &UA_TYPES[UA_TYPES_STRING]);
     UA_Variant_setScalar(&modelAttr.value, &modelName, &UA_TYPES[UA_TYPES_STRING]);
-    modelAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ModelName");
+    modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName");
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "ModelName"),
                               UA_QUALIFIEDNAME(1, "ModelName"),
                               UA_NODEID_NULL, modelAttr, NULL, NULL);
                               UA_NODEID_NULL, modelAttr, NULL, NULL);
 
 
-    UA_VariableAttributes statusAttr;
-    UA_VariableAttributes_init(&statusAttr);
+    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;
     UA_Boolean status = true;
     UA_Boolean status = true;
     UA_Variant_setScalar(&statusAttr.value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
     UA_Variant_setScalar(&statusAttr.value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
-    statusAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Status");
+    statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status");
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "Status"),
                               UA_QUALIFIEDNAME(1, "Status"),
                               UA_NODEID_NULL, statusAttr, NULL, NULL);
                               UA_NODEID_NULL, statusAttr, NULL, NULL);
 
 
-    UA_VariableAttributes rpmAttr;
-    UA_VariableAttributes_init(&rpmAttr);
+    UA_VariableAttributes rpmAttr = UA_VariableAttributes_default;
     UA_Double rpm = 50.0;
     UA_Double rpm = 50.0;
     UA_Variant_setScalar(&rpmAttr.value, &rpm, &UA_TYPES[UA_TYPES_DOUBLE]);
     UA_Variant_setScalar(&rpmAttr.value, &rpm, &UA_TYPES[UA_TYPES_DOUBLE]);
-    rpmAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MotorRPM");
+    rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM");
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "MotorRPMs"),
                               UA_QUALIFIEDNAME(1, "MotorRPMs"),
@@ -174,18 +169,16 @@ static void
 defineObjectTypes(UA_Server *server) {
 defineObjectTypes(UA_Server *server) {
     /* Define the object type for "Device" */
     /* Define the object type for "Device" */
     UA_NodeId deviceTypeId; /* get the nodeid assigned by the server */
     UA_NodeId deviceTypeId; /* get the nodeid assigned by the server */
-    UA_ObjectTypeAttributes dtAttr;
-    UA_ObjectTypeAttributes_init(&dtAttr);
-    dtAttr.displayName = UA_LOCALIZEDTEXT("en_US", "DeviceType");
+    UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default;
+    dtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "DeviceType");
     UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,
     UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,
                                 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                                 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                                 UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "DeviceType"), dtAttr,
                                 UA_QUALIFIEDNAME(1, "DeviceType"), dtAttr,
                                 NULL, &deviceTypeId);
                                 NULL, &deviceTypeId);
 
 
-    UA_VariableAttributes mnAttr;
-    UA_VariableAttributes_init(&mnAttr);
-    mnAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ManufacturerName");
+    UA_VariableAttributes mnAttr = UA_VariableAttributes_default;
+    mnAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ManufacturerName");
     UA_NodeId manufacturerNameId;
     UA_NodeId manufacturerNameId;
     UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
@@ -197,26 +190,23 @@ defineObjectTypes(UA_Server *server) {
                            UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
                            UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
 
 
 
 
-    UA_VariableAttributes modelAttr;
-    UA_VariableAttributes_init(&modelAttr);
-    modelAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ModelName");
+    UA_VariableAttributes modelAttr = UA_VariableAttributes_default;
+    modelAttr.displayName = UA_LOCALIZEDTEXT("en-US", "ModelName");
     UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "ModelName"),
                               UA_QUALIFIEDNAME(1, "ModelName"),
                               UA_NODEID_NULL, modelAttr, NULL, NULL);
                               UA_NODEID_NULL, modelAttr, NULL, NULL);
 
 
     /* Define the object type for "Pump" */
     /* Define the object type for "Pump" */
-    UA_ObjectTypeAttributes ptAttr;
-    UA_ObjectTypeAttributes_init(&ptAttr);
-    ptAttr.displayName = UA_LOCALIZEDTEXT("en_US", "PumpType");
+    UA_ObjectTypeAttributes ptAttr = UA_ObjectTypeAttributes_default;
+    ptAttr.displayName = UA_LOCALIZEDTEXT("en-US", "PumpType");
     UA_Server_addObjectTypeNode(server, pumpTypeId,
     UA_Server_addObjectTypeNode(server, pumpTypeId,
                                 deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "PumpType"), ptAttr,
                                 UA_QUALIFIEDNAME(1, "PumpType"), ptAttr,
                                 NULL, NULL);
                                 NULL, NULL);
 
 
-    UA_VariableAttributes statusAttr;
-    UA_VariableAttributes_init(&statusAttr);
-    statusAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Status");
+    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;
+    statusAttr.displayName = UA_LOCALIZEDTEXT("en-US", "Status");
     statusAttr.valueRank = -1;
     statusAttr.valueRank = -1;
     UA_NodeId statusId;
     UA_NodeId statusId;
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
@@ -228,9 +218,8 @@ defineObjectTypes(UA_Server *server) {
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
                            UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
                            UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
 
 
-    UA_VariableAttributes rpmAttr;
-    UA_VariableAttributes_init(&rpmAttr);
-    rpmAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MotorRPM");
+    UA_VariableAttributes rpmAttr = UA_VariableAttributes_default;
+    rpmAttr.displayName = UA_LOCALIZEDTEXT("en-US", "MotorRPM");
     rpmAttr.valueRank = -1;
     rpmAttr.valueRank = -1;
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
@@ -248,9 +237,8 @@ defineObjectTypes(UA_Server *server) {
 
 
 static void
 static void
 addPumpObjectInstance(UA_Server *server, char *name) {
 addPumpObjectInstance(UA_Server *server, char *name) {
-    UA_ObjectAttributes oAttr;
-    UA_ObjectAttributes_init(&oAttr);
-    oAttr.displayName = UA_LOCALIZEDTEXT("en_US", name);
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
+    oAttr.displayName = UA_LOCALIZEDTEXT("en-US", name);
     UA_Server_addObjectNode(server, UA_NODEID_NULL,
     UA_Server_addObjectNode(server, UA_NODEID_NULL,
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
@@ -268,11 +256,11 @@ addPumpObjectInstance(UA_Server *server, char *name) {
  * pump status to on.
  * pump status to on.
  */
  */
 
 
-UA_Server *s = NULL; /* required to get the server pointer into the constructor
-                        function (will change for v0.3) */
-
-static void *
-pumpTypeConstructor(const UA_NodeId instance) {
+static UA_StatusCode
+pumpTypeConstructor(UA_Server *server,
+                    const UA_NodeId *sessionId, void *sessionContext,
+                    const UA_NodeId *typeId, void *typeContext,
+                    const UA_NodeId *nodeId, void **nodeContext) {
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New pump created");
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New pump created");
 
 
     /* Find the NodeId of the status child variable */
     /* Find the NodeId of the status child variable */
@@ -285,33 +273,34 @@ pumpTypeConstructor(const UA_NodeId instance) {
     
     
     UA_BrowsePath bp;
     UA_BrowsePath bp;
     UA_BrowsePath_init(&bp);
     UA_BrowsePath_init(&bp);
-    bp.startingNode = instance;
+    bp.startingNode = *nodeId;
     bp.relativePath.elementsSize = 1;
     bp.relativePath.elementsSize = 1;
     bp.relativePath.elements = &rpe;
     bp.relativePath.elements = &rpe;
     
     
     UA_BrowsePathResult bpr =
     UA_BrowsePathResult bpr =
-        UA_Server_translateBrowsePathToNodeIds(s, &bp);
+        UA_Server_translateBrowsePathToNodeIds(server, &bp);
     if(bpr.statusCode != UA_STATUSCODE_GOOD ||
     if(bpr.statusCode != UA_STATUSCODE_GOOD ||
        bpr.targetsSize < 1)
        bpr.targetsSize < 1)
-        return NULL;
+        return bpr.statusCode;
 
 
     /* Set the status value */
     /* Set the status value */
     UA_Boolean status = true;
     UA_Boolean status = true;
     UA_Variant value;
     UA_Variant value;
     UA_Variant_setScalar(&value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
     UA_Variant_setScalar(&value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
-    UA_Server_writeValue(s, bpr.targets[0].targetId.nodeId, value);
+    UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
     UA_BrowsePathResult_deleteMembers(&bpr);
     UA_BrowsePathResult_deleteMembers(&bpr);
 
 
-    /* The return pointer of the constructor is attached to the ObjectNode */
-    return NULL;
+    /* At this point we could replace the node context .. */
+
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
 static void
 static void
 addPumpTypeConstructor(UA_Server *server) {
 addPumpTypeConstructor(UA_Server *server) {
-    UA_ObjectLifecycleManagement olm;
-    olm.constructor = pumpTypeConstructor;
-    olm.destructor = NULL;
-    UA_Server_setObjectTypeNode_lifecycleManagement(server, pumpTypeId, olm);
+    UA_NodeTypeLifecycle lifecycle;
+    lifecycle.constructor = pumpTypeConstructor;
+    lifecycle.destructor = NULL;
+    UA_Server_setNodeTypeLifecycle(server, pumpTypeId, lifecycle);
 }
 }
 
 
 /** It follows the main server code, making use of the above definitions. */
 /** It follows the main server code, making use of the above definitions. */
@@ -326,13 +315,8 @@ int main(void) {
     signal(SIGINT, stopHandler);
     signal(SIGINT, stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl =
-        UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
-    s = server; /* required for the constructor */
 
 
     manuallyDefinePump(server);
     manuallyDefinePump(server);
     defineObjectTypes(server);
     defineObjectTypes(server);
@@ -342,8 +326,8 @@ int main(void) {
     addPumpObjectInstance(server, "pump4");
     addPumpObjectInstance(server, "pump4");
     addPumpObjectInstance(server, "pump5");
     addPumpObjectInstance(server, "pump5");
 
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-    return 0;
+    UA_ServerConfig_delete(config);
+    return (int)retval;
 }
 }

+ 11 - 12
examples/tutorial_server_variable.c

@@ -9,6 +9,9 @@
  * to a server. First, we add a new variable to the server. Take a look at the
  * to a server. First, we add a new variable to the server. Take a look at the
  * definition of the ``UA_VariableAttrbitues`` structure to see the list of all
  * definition of the ``UA_VariableAttrbitues`` structure to see the list of all
  * attributes defined for VariableNodes.
  * attributes defined for VariableNodes.
+ *
+ * Note that the default settings have the AccessLevel of the variable value as
+ * read only. See below for making the variable writable.
  */
  */
 
 
 #include <signal.h>
 #include <signal.h>
@@ -18,13 +21,13 @@
 static void
 static void
 addVariable(UA_Server *server) {
 addVariable(UA_Server *server) {
     /* Define the attribute of the myInteger variable node */
     /* Define the attribute of the myInteger variable node */
-    UA_VariableAttributes attr;
-    UA_VariableAttributes_init(&attr);
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
-    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
+    attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
     attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
 
 
     /* Add the variable node to the information model */
     /* Add the variable node to the information model */
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
@@ -103,19 +106,15 @@ int main(void) {
     signal(SIGINT, stopHandler);
     signal(SIGINT, stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl =
-        UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
     addVariable(server);
     addVariable(server);
     writeVariable(server);
     writeVariable(server);
     writeWrongVariable(server);
     writeWrongVariable(server);
 
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-    return 0;
+    UA_ServerConfig_delete(config);
+    return (int)retval;
 }
 }

+ 14 - 19
examples/tutorial_server_variabletype.c

@@ -25,21 +25,20 @@ static UA_NodeId pointTypeId;
 
 
 static void
 static void
 addVariableType2DPoint(UA_Server *server) {
 addVariableType2DPoint(UA_Server *server) {
-    UA_VariableTypeAttributes vtAttr;
-    UA_VariableTypeAttributes_init(&vtAttr);
+    UA_VariableTypeAttributes vtAttr = UA_VariableTypeAttributes_default;
     vtAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
     vtAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
     vtAttr.valueRank = 1; /* array with one dimension */
     vtAttr.valueRank = 1; /* array with one dimension */
     UA_UInt32 arrayDims[1] = {2};
     UA_UInt32 arrayDims[1] = {2};
     vtAttr.arrayDimensions = arrayDims;
     vtAttr.arrayDimensions = arrayDims;
     vtAttr.arrayDimensionsSize = 1;
     vtAttr.arrayDimensionsSize = 1;
-    vtAttr.displayName = UA_LOCALIZEDTEXT("en_US", "2DPoint Type");
+    vtAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Type");
 
 
     /* a matching default value is required */
     /* a matching default value is required */
     UA_Double zero[2] = {0.0, 0.0};
     UA_Double zero[2] = {0.0, 0.0};
     UA_Variant_setArray(&vtAttr.value, zero, 2, &UA_TYPES[UA_TYPES_DOUBLE]);
     UA_Variant_setArray(&vtAttr.value, zero, 2, &UA_TYPES[UA_TYPES_DOUBLE]);
 
 
     UA_Server_addVariableTypeNode(server, UA_NODEID_NULL,
     UA_Server_addVariableTypeNode(server, UA_NODEID_NULL,
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                   UA_QUALIFIEDNAME(1, "2DPoint Type"), UA_NODEID_NULL,
                                   UA_QUALIFIEDNAME(1, "2DPoint Type"), UA_NODEID_NULL,
                                   vtAttr, NULL, &pointTypeId);
                                   vtAttr, NULL, &pointTypeId);
@@ -56,14 +55,14 @@ static UA_NodeId pointVariableId;
 static void
 static void
 addVariable(UA_Server *server) {
 addVariable(UA_Server *server) {
     /* Prepare the node attributes */
     /* Prepare the node attributes */
-    UA_VariableAttributes vAttr;
-    UA_VariableAttributes_init(&vAttr);
+    UA_VariableAttributes vAttr = UA_VariableAttributes_default;
     vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
     vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
     vAttr.valueRank = 1; /* array with one dimension */
     vAttr.valueRank = 1; /* array with one dimension */
     UA_UInt32 arrayDims[1] = {2};
     UA_UInt32 arrayDims[1] = {2};
     vAttr.arrayDimensions = arrayDims;
     vAttr.arrayDimensions = arrayDims;
     vAttr.arrayDimensionsSize = 1;
     vAttr.arrayDimensionsSize = 1;
-    vAttr.displayName = UA_LOCALIZEDTEXT("en_US", "2DPoint Variable");
+    vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable");
+    vAttr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     /* vAttr.value is left empty, the server instantiates with the default value */
     /* vAttr.value is left empty, the server instantiates with the default value */
 
 
     /* Add the node */
     /* Add the node */
@@ -83,11 +82,10 @@ addVariable(UA_Server *server) {
 static void
 static void
 addVariableFail(UA_Server *server) {
 addVariableFail(UA_Server *server) {
     /* Prepare the node attributes */
     /* Prepare the node attributes */
-    UA_VariableAttributes vAttr;
-    UA_VariableAttributes_init(&vAttr);
+    UA_VariableAttributes vAttr = UA_VariableAttributes_default;
     vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
     vAttr.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
     vAttr.valueRank = -1; /* a scalar. this is not allowed per the variable type */
     vAttr.valueRank = -1; /* a scalar. this is not allowed per the variable type */
-    vAttr.displayName = UA_LOCALIZEDTEXT("en_US", "2DPoint Variable (fail)");
+    vAttr.displayName = UA_LOCALIZEDTEXT("en-US", "2DPoint Variable (fail)");
     UA_String s = UA_STRING("2dpoint?");
     UA_String s = UA_STRING("2dpoint?");
     UA_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]);
     UA_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]);
 
 
@@ -108,7 +106,7 @@ static void
 writeVariable(UA_Server *server) {
 writeVariable(UA_Server *server) {
     UA_StatusCode retval = UA_Server_writeValueRank(server, pointVariableId, 0);
     UA_StatusCode retval = UA_Server_writeValueRank(server, pointVariableId, 0);
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
-                "Setting the Value Rank failed with Status Code %s\n",
+                "Setting the Value Rank failed with Status Code %s",
                 UA_StatusCode_name(retval));
                 UA_StatusCode_name(retval));
 
 
 }
 }
@@ -125,19 +123,16 @@ int main(void) {
     signal(SIGINT, stopHandler);
     signal(SIGINT, stopHandler);
     signal(SIGTERM, stopHandler);
     signal(SIGTERM, stopHandler);
 
 
-    UA_ServerConfig config = UA_ServerConfig_standard;
-    UA_ServerNetworkLayer nl =
-        UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
-    config.networkLayers = &nl;
-    config.networkLayersSize = 1;
+    UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
     UA_Server *server = UA_Server_new(config);
 
 
     addVariableType2DPoint(server);
     addVariableType2DPoint(server);
     addVariable(server);
     addVariable(server);
     addVariableFail(server);
     addVariableFail(server);
+    writeVariable(server);
 
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
-    return 0;
+    UA_ServerConfig_delete(config);
+    return (int)retval;
 }
 }

+ 15 - 0
include/open62541.pc.in

@@ -0,0 +1,15 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_PREFIX@/lib
+sharedlibdir=@CMAKE_INSTALL_PREFIX@/share
+includedir=@CMAKE_INSTALL_PREFIX@/include
+
+Name: open62541
+Description: open62541 is an open source C (C99) implementation of OPC UA
+Version: @OPEN62541_VER_MAJOR@.@OPEN62541_VER_MINOR@.@OPEN62541_VER_PATCH@
+Libs: -L${libdir} -lopen62541
+Cflags: -I${includedir}/open62541

+ 129 - 50
include/ua_client.h

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef UA_CLIENT_H_
 #ifndef UA_CLIENT_H_
 #define UA_CLIENT_H_
 #define UA_CLIENT_H_
@@ -9,12 +9,11 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#include "ua_config.h"
 #include "ua_types.h"
 #include "ua_types.h"
-#include "ua_connection.h"
-#include "ua_log.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated_handling.h"
 #include "ua_types_generated_handling.h"
+#include "ua_plugin_network.h"
+#include "ua_plugin_log.h"
 
 
 /**
 /**
  * .. _client:
  * .. _client:
@@ -35,74 +34,59 @@ extern "C" {
  *
  *
  * Client Configuration
  * Client Configuration
  * -------------------- */
  * -------------------- */
-typedef UA_Connection
-(*UA_ConnectClientConnection)(UA_ConnectionConfig localConf,
-                              const char *endpointUrl, UA_Logger logger);
 
 
 typedef struct UA_ClientConfig {
 typedef struct UA_ClientConfig {
-    UA_UInt32 timeout;               /* Sync response timeout */
+    UA_UInt32 timeout;               /* Sync response timeout in ms */
     UA_UInt32 secureChannelLifeTime; /* Lifetime in ms (then the channel needs
     UA_UInt32 secureChannelLifeTime; /* Lifetime in ms (then the channel needs
                                         to be renewed) */
                                         to be renewed) */
     UA_Logger logger;
     UA_Logger logger;
     UA_ConnectionConfig localConnectionConfig;
     UA_ConnectionConfig localConnectionConfig;
     UA_ConnectClientConnection connectionFunc;
     UA_ConnectClientConnection connectionFunc;
+
+    /* Custom DataTypes */
+    size_t customDataTypesSize;
+    const UA_DataType *customDataTypes;
 } UA_ClientConfig;
 } UA_ClientConfig;
 
 
 /**
 /**
  * Client Lifecycle
  * Client Lifecycle
  * ---------------- */
  * ---------------- */
+
 typedef enum {
 typedef enum {
-     UA_CLIENTSTATE_READY,     /* The client is not connected but initialized
-                                  and ready to use. */
-     UA_CLIENTSTATE_CONNECTED, /* The client is connected to a server. */
-     UA_CLIENTSTATE_FAULTED,   /* An error has occured that might have
-                                  influenced the connection state. A successfull
-                                  service call or renewal of the secure channel
-                                  will reset the state to CONNECTED. */
-     UA_CLIENTSTATE_ERRORED    /* A non-recoverable error has occured and the
-                                  connection is no longer reliable. The client
-                                  needs to be disconnected and reinitialized to
-                                  recover into a CONNECTED state. */
+    UA_CLIENTSTATE_DISCONNECTED,        /* The client is not connected */
+    UA_CLIENTSTATE_CONNECTED,           /* A TCP connection to the server is open */
+    UA_CLIENTSTATE_SECURECHANNEL,       /* A SecureChannel to the server is open */
+    UA_CLIENTSTATE_SESSION,             /* A session with the server is open */
+    UA_CLIENTSTATE_SESSION_DISCONNECTED /* A session with the server is open.
+                                         * But the SecureChannel was lost. Try
+                                         * to establish a new SecureChannel and
+                                         * reattach the existing session. */
 } UA_ClientState;
 } UA_ClientState;
 
 
 struct UA_Client;
 struct UA_Client;
 typedef struct UA_Client UA_Client;
 typedef struct UA_Client UA_Client;
 
 
-/* Create a new client
- *
- * @param config for the new client. You can use UA_ClientConfig_standard
- *        which has sane defaults
- * @param logger function pointer to a logger function. See
- *        examples/logger_stdout.c for a simple implementation
- * @return return the new Client object */
-UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config);
+/* Create a new client */
+UA_Client UA_EXPORT *
+UA_Client_new(UA_ClientConfig config);
 
 
 /* Get the client connection status */
 /* Get the client connection status */
-UA_ClientState UA_EXPORT UA_Client_getState(UA_Client *client);
+UA_ClientState UA_EXPORT
+UA_Client_getState(UA_Client *client);
 
 
 /* Reset a client */
 /* Reset a client */
-void UA_EXPORT UA_Client_reset(UA_Client *client);
+void UA_EXPORT
+UA_Client_reset(UA_Client *client);
 
 
 /* Delete a client */
 /* Delete a client */
-void UA_EXPORT UA_Client_delete(UA_Client *client);
+void UA_EXPORT
+UA_Client_delete(UA_Client *client);
 
 
 /**
 /**
- * Manage the Connection
- * --------------------- */
-/* Gets a list of endpoints of a server
- *
- * @param client to use
- * @param server url to connect (for example "opc.tcp://localhost:16664")
- * @param endpointDescriptionsSize size of the array of endpoint descriptions
- * @param endpointDescriptions array of endpoint descriptions that is allocated
- *        by the function (you need to free manually)
- * @return Indicates whether the operation succeeded or returns an error code */
-UA_StatusCode UA_EXPORT
-UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
-                       size_t* endpointDescriptionsSize,
-                       UA_EndpointDescription** endpointDescriptions);
+ * Connect to a Server
+ * ------------------- */
 
 
-/* Connect to the selected server
+/* Connect to the server
  *
  *
  * @param client to use
  * @param client to use
  * @param endpointURL to connect (for example "opc.tcp://localhost:16664")
  * @param endpointURL to connect (for example "opc.tcp://localhost:16664")
@@ -122,16 +106,87 @@ UA_Client_connect_username(UA_Client *client, const char *endpointUrl,
                            const char *username, const char *password);
                            const char *username, const char *password);
 
 
 /* Close a connection to the selected server */
 /* Close a connection to the selected server */
-UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client);
+UA_StatusCode UA_EXPORT
+UA_Client_disconnect(UA_Client *client);
 
 
 /* Renew the underlying secure channel */
 /* Renew the underlying secure channel */
-UA_StatusCode UA_EXPORT UA_Client_manuallyRenewSecureChannel(UA_Client *client);
+UA_StatusCode UA_EXPORT
+UA_Client_manuallyRenewSecureChannel(UA_Client *client);
+
+/**
+ * Discovery
+ * --------- */
+
+/* Gets a list of endpoints of a server
+ *
+ * @param client to use. Must be connected to the same endpoint given in
+ *        serverUrl or otherwise in disconnected state.
+ * @param serverUrl url to connect (for example "opc.tcp://localhost:16664")
+ * @param endpointDescriptionsSize size of the array of endpoint descriptions
+ * @param endpointDescriptions array of endpoint descriptions that is allocated
+ *        by the function (you need to free manually)
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode UA_EXPORT
+UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
+                       size_t* endpointDescriptionsSize,
+                       UA_EndpointDescription** endpointDescriptions);
+
+/* Gets a list of all registered servers at the given server.
+ *
+ * You can pass an optional filter for serverUris. If the given server is not registered,
+ * an empty array will be returned. If the server is registered, only that application
+ * description will be returned.
+ *
+ * Additionally you can optionally indicate which locale you want for the server name
+ * in the returned application description. The array indicates the order of preference.
+ * A server may have localized names.
+ *
+ * @param client to use. Must be connected to the same endpoint given in
+ *        serverUrl or otherwise in disconnected state.
+ * @param serverUrl url to connect (for example "opc.tcp://localhost:16664")
+ * @param serverUrisSize Optional filter for specific server uris
+ * @param serverUris Optional filter for specific server uris
+ * @param localeIdsSize Optional indication which locale you prefer
+ * @param localeIds Optional indication which locale you prefer
+ * @param registeredServersSize size of returned array, i.e., number of found/registered servers
+ * @param registeredServers array containing found/registered servers
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode UA_EXPORT
+UA_Client_findServers(UA_Client *client, const char *serverUrl,
+                      size_t serverUrisSize, UA_String *serverUris,
+                      size_t localeIdsSize, UA_String *localeIds,
+                      size_t *registeredServersSize,
+                      UA_ApplicationDescription **registeredServers);
+
+/* Get a list of all known server in the network. Only supported by LDS servers.
+ *
+ * @param client to use. Must be connected to the same endpoint given in
+ * serverUrl or otherwise in disconnected state.
+ * @param serverUrl url to connect (for example "opc.tcp://localhost:16664")
+ * @param startingRecordId optional. Only return the records with an ID higher
+ *        or equal the given. Can be used for pagination to only get a subset of
+ *        the full list
+ * @param maxRecordsToReturn optional. Only return this number of records
+
+ * @param serverCapabilityFilterSize optional. Filter the returned list to only
+ *        get servers with given capabilities, e.g. "LDS"
+ * @param serverCapabilityFilter optional. Filter the returned list to only get
+ *        servers with given capabilities, e.g. "LDS"
+ * @param serverOnNetworkSize size of returned array, i.e., number of
+ *        known/registered servers
+ * @param serverOnNetwork array containing known/registered servers
+ * @return Indicates whether the operation succeeded or returns an error code */
+UA_StatusCode UA_EXPORT
+UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl,
+                               UA_UInt32 startingRecordId, UA_UInt32 maxRecordsToReturn,
+                               size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter,
+                               size_t *serverOnNetworkSize, UA_ServerOnNetwork **serverOnNetwork);
 
 
 /**
 /**
  * .. _client-services:
  * .. _client-services:
  *
  *
- * Raw Services
- * ------------
+ * Services
+ * --------
  * The raw OPC UA services are exposed to the client. But most of them time, it
  * The raw OPC UA services are exposed to the client. But most of them time, it
  * is better to use the convenience functions from ``ua_client_highlevel.h``
  * is better to use the convenience functions from ``ua_client_highlevel.h``
  * that wrap the raw services. */
  * that wrap the raw services. */
@@ -350,6 +405,30 @@ UA_Client_Service_publish(UA_Client *client, const UA_PublishRequest request) {
 
 
 #endif
 #endif
 
 
+/**
+ * .. _client-async-services:
+ *
+ * Asynchronous Services
+ * ---------------------
+ * All OPC UA services are asynchronous in nature. So several service calls can
+ * be made without waiting for a response first. Responess may come in a
+ * different ordering. */
+
+typedef void
+(*UA_ClientAsyncServiceCallback)(UA_Client *client, void *userdata,
+                                 UA_UInt32 requestId, const void *response);
+
+/* Don't use this function. Use the type versions below instead. */
+UA_StatusCode UA_EXPORT
+__UA_Client_AsyncService(UA_Client *client, const void *request,
+                         const UA_DataType *requestType,
+                         UA_ClientAsyncServiceCallback callback,
+                         const UA_DataType *responseType,
+                         void *userdata, UA_UInt32 *requestId);
+
+UA_StatusCode UA_EXPORT
+UA_Client_runAsync(UA_Client *client, UA_UInt16 timeout);
+
 /**
 /**
  * .. toctree::
  * .. toctree::
  *
  *

+ 39 - 7
include/ua_client_highlevel.h

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef UA_CLIENT_HIGHLEVEL_H_
 #ifndef UA_CLIENT_HIGHLEVEL_H_
 #define UA_CLIENT_HIGHLEVEL_H_
 #define UA_CLIENT_HIGHLEVEL_H_
@@ -152,8 +152,8 @@ UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
 UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                       UA_UInt32 **outArrayDimensions,
-                                       size_t *outArrayDimensionsSize);
+                                       size_t *outArrayDimensionsSize,
+                                       UA_UInt32 **outArrayDimensions);
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Client_readAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
 UA_Client_readAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
@@ -333,8 +333,8 @@ UA_Client_writeValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
 UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                        const UA_UInt32 *newArrayDimensions,
-                                        size_t newArrayDimensionsSize);
+                                        size_t newArrayDimensionsSize,
+                                        const UA_UInt32 *newArrayDimensions);
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Client_writeAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
 UA_Client_writeAccessLevelAttribute(UA_Client *client, const UA_NodeId nodeId,
@@ -413,6 +413,23 @@ UA_StatusCode UA_EXPORT
 UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
 UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
                      UA_Boolean deleteTargetReferences);
                      UA_Boolean deleteTargetReferences);
 
 
+/* Protect against redundant definitions for server/client */
+#ifndef UA_DEFAULT_ATTRIBUTES_DEFINED
+#define UA_DEFAULT_ATTRIBUTES_DEFINED
+/* The default for variables is "BaseDataType" for the datatype, -2 for the
+ * valuerank and a read-accesslevel. */
+UA_EXPORT extern const UA_VariableAttributes UA_VariableAttributes_default;
+UA_EXPORT extern const UA_VariableTypeAttributes UA_VariableTypeAttributes_default;
+/* Methods are executable by default */
+UA_EXPORT extern const UA_MethodAttributes UA_MethodAttributes_default;
+/* The remaining attribute definitions are currently all zeroed out */
+UA_EXPORT extern const UA_ObjectAttributes UA_ObjectAttributes_default;
+UA_EXPORT extern const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default;
+UA_EXPORT extern const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default;
+UA_EXPORT extern const UA_DataTypeAttributes UA_DataTypeAttributes_default;
+UA_EXPORT extern const UA_ViewAttributes UA_ViewAttributes_default;
+#endif
+
 /* Don't call this function, use the typed versions */
 /* Don't call this function, use the typed versions */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
 __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
@@ -558,7 +575,7 @@ typedef struct {
     UA_Byte priority;
     UA_Byte priority;
 } UA_SubscriptionSettings;
 } UA_SubscriptionSettings;
 
 
-extern const UA_EXPORT UA_SubscriptionSettings UA_SubscriptionSettings_standard;
+extern const UA_EXPORT UA_SubscriptionSettings UA_SubscriptionSettings_default;
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
 UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
@@ -570,6 +587,21 @@ UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId);
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client);
 UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client);
 
 
+typedef void (*UA_MonitoredEventHandlingFunction)(const UA_UInt32 monId,
+                                                  const size_t nEventFields,
+                                                  const UA_Variant *eventFields,
+                                                  void *context);
+
+UA_StatusCode UA_EXPORT
+UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, const UA_UInt32 subscriptionId,
+                                          const UA_NodeId nodeId, const UA_UInt32 attributeID,
+                                          UA_SimpleAttributeOperand *selectClause,
+                                          const size_t nSelectClauses,
+                                          UA_ContentFilterElement *whereClause,
+                                          const size_t nWhereClauses,
+                                          const UA_MonitoredEventHandlingFunction hf,
+                                          void *hfContext, UA_UInt32 *newMonitoredItemId);
+
 typedef void (*UA_MonitoredItemHandlingFunction)(UA_UInt32 monId,
 typedef void (*UA_MonitoredItemHandlingFunction)(UA_UInt32 monId,
                                                  UA_DataValue *value,
                                                  UA_DataValue *value,
                                                  void *context);
                                                  void *context);

+ 87 - 82
include/ua_config.h.in

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef UA_CONFIG_H_
 #ifndef UA_CONFIG_H_
 #define UA_CONFIG_H_
 #define UA_CONFIG_H_
@@ -10,8 +10,8 @@ extern "C" {
 #endif
 #endif
 
 
 /**
 /**
- * Library Version
- * --------------- */
+ * open62541 Version
+ * ----------------- */
 #define UA_OPEN62541_VER_MAJOR ${OPEN62541_VER_MAJOR}
 #define UA_OPEN62541_VER_MAJOR ${OPEN62541_VER_MAJOR}
 #define UA_OPEN62541_VER_MINOR ${OPEN62541_VER_MINOR}
 #define UA_OPEN62541_VER_MINOR ${OPEN62541_VER_MINOR}
 #define UA_OPEN62541_VER_PATCH ${OPEN62541_VER_PATCH}
 #define UA_OPEN62541_VER_PATCH ${OPEN62541_VER_PATCH}
@@ -19,59 +19,89 @@ extern "C" {
 #define UA_OPEN62541_VER_COMMIT "${OPEN62541_VER_COMMIT}"
 #define UA_OPEN62541_VER_COMMIT "${OPEN62541_VER_COMMIT}"
 
 
 /**
 /**
- * Options
- * ------- */
+ * Feature Options
+ * ---------------
+ * Changing the feature options has no effect on a pre-compiled library. */
 #define UA_LOGLEVEL ${UA_LOGLEVEL}
 #define UA_LOGLEVEL ${UA_LOGLEVEL}
 #cmakedefine UA_ENABLE_METHODCALLS
 #cmakedefine UA_ENABLE_METHODCALLS
 #cmakedefine UA_ENABLE_NODEMANAGEMENT
 #cmakedefine UA_ENABLE_NODEMANAGEMENT
 #cmakedefine UA_ENABLE_SUBSCRIPTIONS
 #cmakedefine UA_ENABLE_SUBSCRIPTIONS
 #cmakedefine UA_ENABLE_MULTITHREADING
 #cmakedefine UA_ENABLE_MULTITHREADING
 
 
-/**
- * Advanced Options
- * ---------------- */
+/* Advanced Options */
 #cmakedefine UA_ENABLE_STATUSCODE_DESCRIPTIONS
 #cmakedefine UA_ENABLE_STATUSCODE_DESCRIPTIONS
 #cmakedefine UA_ENABLE_TYPENAMES
 #cmakedefine UA_ENABLE_TYPENAMES
-#cmakedefine UA_ENABLE_EMBEDDED_LIBC
 #cmakedefine UA_ENABLE_DETERMINISTIC_RNG
 #cmakedefine UA_ENABLE_DETERMINISTIC_RNG
 #cmakedefine UA_ENABLE_GENERATE_NAMESPACE0
 #cmakedefine UA_ENABLE_GENERATE_NAMESPACE0
-#cmakedefine UA_ENABLE_NONSTANDARD_STATELESS
 #cmakedefine UA_ENABLE_NONSTANDARD_UDP
 #cmakedefine UA_ENABLE_NONSTANDARD_UDP
+#cmakedefine UA_ENABLE_DISCOVERY
+#cmakedefine UA_ENABLE_DISCOVERY_MULTICAST
+#cmakedefine UA_ENABLE_DISCOVERY_SEMAPHORE
+#cmakedefine UA_ENABLE_UNIT_TEST_FAILURE_HOOKS
 
 
-/**
- * Standard Includes
- * ----------------- */
-#ifndef _XOPEN_SOURCE
-# define _XOPEN_SOURCE 500
-#endif
-#ifndef _DEFAULT_SOURCE
-# define _DEFAULT_SOURCE
-#endif
+/* Options for Debugging */
+#cmakedefine UA_DEBUG
+#cmakedefine UA_DEBUG_DUMP_PKGS
 
 
+/**
+ * C99 Definitions
+ * --------------- */
+#include <string.h>
 #include <stddef.h>
 #include <stddef.h>
 
 
-/* Include stdint.h or workaround for older Visual Studios */
+/* Include stdint.h and stdbool.h or workaround for older Visual Studios */
 #if !defined(_MSC_VER) || _MSC_VER >= 1600
 #if !defined(_MSC_VER) || _MSC_VER >= 1600
 # include <stdint.h>
 # include <stdint.h>
+# include <stdbool.h> /* C99 Boolean */
 #else
 #else
 # include "ms_stdint.h"
 # include "ms_stdint.h"
+# if !defined(__bool_true_false_are_defined)
+#  define bool short
+#  define true 1
+#  define false 0
+#  define __bool_true_false_are_defined
+# endif
 #endif
 #endif
 
 
-#ifndef __cplusplus
-# include <stdbool.h> /* C99 Boolean */
-/* Manual Boolean:
-typedef uint8_t bool;
-#define true 1
-#define false 0 */
+/**
+ * Assertions
+ * ----------
+ * The assert macro is disabled by defining NDEBUG. It is often forgotten to
+ * include -DNDEBUG in the compiler flags when using the single-file release. So
+ * we make assertions dependent on the UA_DEBUG definition handled by CMake. */
+#ifdef UA_DEBUG
+# include <assert.h>
+# define UA_assert(ignore) assert(ignore)
+#else
+# define UA_assert(ignore)
 #endif
 #endif
 
 
-#include <stdlib.h>
+/* Outputs an error message at compile time if the assert fails.
+ * Example usage:
+ * UA_STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
+ * See: https://stackoverflow.com/a/4815532/869402 */
+#if defined(__cplusplus) && __cplusplus >= 201103L /* C++11 or above */
+# define UA_STATIC_ASSERT(cond,msg) static_assert(cond, #msg)
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L /* C11 or above */
+# define UA_STATIC_ASSERT(cond,msg) _Static_assert(cond, #msg)
+#elif defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) /* GCC, Clang, MSC */
+# define UA_CTASTR2(pre,post) pre ## post
+# define UA_CTASTR(pre,post) UA_CTASTR2(pre,post)
+# define UA_STATIC_ASSERT(cond,msg)                             \
+    typedef struct {                                            \
+        int UA_CTASTR(static_assertion_failed_,msg) : !!(cond); \
+    } UA_CTASTR(static_assertion_failed_,__COUNTER__)
+#else /* Everybody else */
+# define UA_STATIC_ASSERT(cond,msg) typedef char static_assertion_##msg[(cond)?1:-1]
+#endif
 
 
 /**
 /**
  * Memory Management
  * Memory Management
- * ---------------
- * The default malloc implementation from ``stdlib.h`` is used internally.
- * Override if required. */
+ * -----------------
+ * The default is to use the malloc implementation from ``stdlib.h``. Override
+ * if required. Changing the settings has no effect on a pre-compiled
+ * library. */
+#include <stdlib.h>
 #if defined(_WIN32) && !defined(__clang__)
 #if defined(_WIN32) && !defined(__clang__)
 # include <malloc.h>
 # include <malloc.h>
 #endif
 #endif
@@ -97,6 +127,7 @@ typedef uint8_t bool;
  * order to export symbols for a DLL. Define ``UA_DYNAMIC_LINKING`` only to
  * order to export symbols for a DLL. Define ``UA_DYNAMIC_LINKING`` only to
  * import symbols from a DLL.*/
  * import symbols from a DLL.*/
 #cmakedefine UA_DYNAMIC_LINKING
 #cmakedefine UA_DYNAMIC_LINKING
+
 #if defined(_WIN32) && defined(UA_DYNAMIC_LINKING)
 #if defined(_WIN32) && defined(UA_DYNAMIC_LINKING)
 # ifdef UA_DYNAMIC_LINKING_EXPORT /* export dll */
 # ifdef UA_DYNAMIC_LINKING_EXPORT /* export dll */
 #  ifdef __GNUC__
 #  ifdef __GNUC__
@@ -143,36 +174,31 @@ typedef uint8_t bool;
 /**
 /**
  * Function attributes
  * Function attributes
  * ------------------- */
  * ------------------- */
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(__clang__)
 # define UA_FUNC_ATTR_MALLOC __attribute__((malloc))
 # define UA_FUNC_ATTR_MALLOC __attribute__((malloc))
 # define UA_FUNC_ATTR_PURE __attribute__ ((pure))
 # define UA_FUNC_ATTR_PURE __attribute__ ((pure))
 # define UA_FUNC_ATTR_CONST __attribute__((const))
 # define UA_FUNC_ATTR_CONST __attribute__((const))
 # define UA_FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
 # define UA_FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+# define UA_FORMAT(X,Y) __attribute__ ((format (printf, X, Y)))
 #else
 #else
 # define UA_FUNC_ATTR_MALLOC
 # define UA_FUNC_ATTR_MALLOC
 # define UA_FUNC_ATTR_PURE
 # define UA_FUNC_ATTR_PURE
 # define UA_FUNC_ATTR_CONST
 # define UA_FUNC_ATTR_CONST
 # define UA_FUNC_ATTR_WARN_UNUSED_RESULT
 # define UA_FUNC_ATTR_WARN_UNUSED_RESULT
+# define UA_FORMAT(X,Y)
 #endif
 #endif
 
 
-/**
- * String Manipulation
- * -------------------
- * The header ``string.h`` is defined in the C-standard. If no libc is provided
- * (e.g. on some embedded target), use the following definitions and the
- * implementation in ``/deps/libc_string.c`` */
-#ifndef UA_ENABLE_EMBEDDED_LIBC
-# include <string.h>
+#if defined(__GNUC__) || defined(__clang__)
+# define UA_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+# define UA_DEPRECATED __declspec(deprecated)
 #else
 #else
-  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);
-  int memcmp(const void *vl, const void *vr, size_t n);
+# define UA_DEPRECATED
 #endif
 #endif
 
 
 /**
 /**
- * Binary Encoding Overlays
- * ------------------------
+ * Detect Binary Overlaying for Encoding
+ * -------------------------------------
  * Integers and floating point numbers are transmitted in little-endian (IEEE 754
  * Integers and floating point numbers are transmitted in little-endian (IEEE 754
  * for floating point) encoding. If the target architecture uses the same
  * for floating point) encoding. If the target architecture uses the same
  * format, numeral datatypes can be memcpy'd (overlayed) on the binary stream.
  * format, numeral datatypes can be memcpy'd (overlayed) on the binary stream.
@@ -184,44 +210,44 @@ typedef uint8_t bool;
  * representation of the target architecture is little-endian. */
  * representation of the target architecture is little-endian. */
 #if defined(_WIN32) || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
 #if defined(_WIN32) || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
                         (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
                         (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
-# define UA_BINARY_OVERLAYABLE_INTEGER true
+# define UA_BINARY_OVERLAYABLE_INTEGER 1
 #elif defined(__ANDROID__) /* Andoid */
 #elif defined(__ANDROID__) /* Andoid */
 # include <endian.h>
 # include <endian.h>
 # if __BYTE_ORDER == __LITTLE_ENDIAN
 # if __BYTE_ORDER == __LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 # endif
 #elif defined(__linux__) /* Linux */
 #elif defined(__linux__) /* Linux */
 # include <endian.h>
 # include <endian.h>
 # if __BYTE_ORDER == __LITTLE_ENDIAN
 # if __BYTE_ORDER == __LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 # endif
 # if __FLOAT_BYTE_ORDER == __LITTLE_ENDIAN
 # if __FLOAT_BYTE_ORDER == __LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_FLOAT true
+#  define UA_BINARY_OVERLAYABLE_FLOAT 1
 # endif
 # endif
 #elif defined(__OpenBSD__) /* OpenBSD */
 #elif defined(__OpenBSD__) /* OpenBSD */
 # include <sys/endian.h>
 # include <sys/endian.h>
 # if BYTE_ORDER == LITTLE_ENDIAN
 # if BYTE_ORDER == LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 # endif
 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) /* Other BSD */
 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) /* Other BSD */
 # include <sys/endian.h>
 # include <sys/endian.h>
 # if _BYTE_ORDER == _LITTLE_ENDIAN
 # if _BYTE_ORDER == _LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 # endif
 #elif defined(__APPLE__) /* Apple (MacOS, iOS) */
 #elif defined(__APPLE__) /* Apple (MacOS, iOS) */
 # include <libkern/OSByteOrder.h>
 # include <libkern/OSByteOrder.h>
 # if defined(__LITTLE_ENDIAN__)
 # if defined(__LITTLE_ENDIAN__)
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 # endif
 #elif defined(__QNX__) || defined(__QNXNTO__) /* QNX */
 #elif defined(__QNX__) || defined(__QNXNTO__) /* QNX */
 # include <gulliver.h>
 # include <gulliver.h>
 # if defined(__LITTLEENDIAN__)
 # if defined(__LITTLEENDIAN__)
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 # endif
 #endif
 #endif
 
 
 #ifndef UA_BINARY_OVERLAYABLE_INTEGER
 #ifndef UA_BINARY_OVERLAYABLE_INTEGER
-# define UA_BINARY_OVERLAYABLE_INTEGER false
+# define UA_BINARY_OVERLAYABLE_INTEGER 0
 #endif
 #endif
 
 
 /**
 /**
@@ -232,40 +258,19 @@ typedef uint8_t bool;
  * this cannot be reliable detected with macros for the clang compiler
  * this cannot be reliable detected with macros for the clang compiler
  * (beginning of 2017). Just override if necessary. */
  * (beginning of 2017). Just override if necessary. */
 #if defined(_WIN32)
 #if defined(_WIN32)
-# define UA_BINARY_OVERLAYABLE_FLOAT true
+# define UA_BINARY_OVERLAYABLE_FLOAT 1
 #elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
 #elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
     (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) /* Defined only in GCC */
     (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__) /* Defined only in GCC */
-# define UA_BINARY_OVERLAYABLE_FLOAT true
+# define UA_BINARY_OVERLAYABLE_FLOAT 1
 #elif defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && \
 #elif defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && \
     (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) /* Defined only in GCC */
     (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) /* Defined only in GCC */
-# define UA_BINARY_OVERLAYABLE_FLOAT true
+# define UA_BINARY_OVERLAYABLE_FLOAT 1
+#elif defined(_WRS_KERNEL)
+# define UA_BINARY_OVERLAYABLE_FLOAT 1
 #endif
 #endif
 
 
 #ifndef UA_BINARY_OVERLAYABLE_FLOAT
 #ifndef UA_BINARY_OVERLAYABLE_FLOAT
-# define UA_BINARY_OVERLAYABLE_FLOAT false
-#endif
-
-/**
- * Static Assert
- * ^^^^^^^^^^^^^
- * Outputs an error message at compile time if the assert fails.
- * Example usage:
- * UA_STATIC_ASSERT(sizeof(long)==7, use_another_compiler_luke)
- * See: https://stackoverflow.com/a/4815532/869402 */
-#if defined(__cplusplus) && __cplusplus >= 201103L /* C++11 or above */
-# define UA_STATIC_ASSERT(cond,msg) static_assert(cond, #msg)
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L /* C11 or above */
-# define UA_STATIC_ASSERT(cond,msg) _Static_assert(cond, #msg)
-#elif defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) /* GCC, Clang, MSC */
-# define UA_CTASTR2(pre,post) pre ## post
-# define UA_CTASTR(pre,post) UA_CTASTR2(pre,post)
-# define UA_STATIC_ASSERT(cond,msg)                             \
-    typedef struct {                                            \
-        int UA_CTASTR(static_assertion_failed_,msg) : !!(cond); \
-    } UA_CTASTR(static_assertion_failed_,__COUNTER__)
-#else /* Everybody else */
-# define UA_STATIC_ASSERT(cond,msg) \
-    typedef char static_assertion_##msg[(cond)?1:-1]
+# define UA_BINARY_OVERLAYABLE_FLOAT 0
 #endif
 #endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 0 - 137
include/ua_connection.h

@@ -1,137 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
-
-#ifndef UA_CONNECTION_H_
-#define UA_CONNECTION_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "ua_types.h"
-
-/**
- * Networking
- * ----------
- * Client-server connection is represented by a `UA_Connection` structure. In
- * order to allow for different operating systems and connection types. For
- * this, `UA_Connection` stores a pointer to user-defined data and
- * function-pointers to interact with the underlying networking implementation.
- *
- * An example networklayer for TCP communication is contained in the plugins
- * folder. The networklayer forwards messages with `UA_Connection` structures to
- * the main open62541 library. The library can then return messages vie TCP
- * without being aware of the underlying transport technology.
- *
- * Connection Config
- * ^^^^^^^^^^^^^^^^^ */
-typedef struct {
-    UA_UInt32 protocolVersion;
-    UA_UInt32 sendBufferSize;
-    UA_UInt32 recvBufferSize;
-    UA_UInt32 maxMessageSize;
-    UA_UInt32 maxChunkCount;
-} UA_ConnectionConfig;
-
-extern const UA_EXPORT UA_ConnectionConfig UA_ConnectionConfig_standard;
-
-/**
- * Connection Structure
- * ^^^^^^^^^^^^^^^^^^^^ */
-typedef enum {
-    UA_CONNECTION_OPENING,     /* The socket is open, but the HEL/ACK handshake
-                                  is not done */
-    UA_CONNECTION_ESTABLISHED, /* The socket is open and the connection
-                                  configured */
-    UA_CONNECTION_CLOSED,      /* The socket has been closed and the connection
-                                  will be deleted */
-} UA_ConnectionState;
-
-/* Forward declarations */
-struct UA_Connection;
-typedef struct UA_Connection UA_Connection;
-
-struct UA_SecureChannel;
-typedef struct UA_SecureChannel UA_SecureChannel;
-
-struct UA_Connection {
-    UA_ConnectionState state;
-    UA_ConnectionConfig localConf;
-    UA_ConnectionConfig remoteConf;
-    UA_SecureChannel *channel;       /* The securechannel that is attached to
-                                        this connection */
-    UA_Int32 sockfd;                 /* Most connectivity solutions run on
-                                        sockets. Having the socket id here
-                                        simplifies the design. */
-    void *handle;                    /* A pointer to internal data */
-    UA_ByteString incompleteMessage; /* A half-received message (TCP is a
-                                        streaming protocol) is stored here */
-
-    /* Get a buffer for sending */
-    UA_StatusCode (*getSendBuffer)(UA_Connection *connection, size_t length,
-                                   UA_ByteString *buf);
-
-    /* Release the send buffer manually */
-    void (*releaseSendBuffer)(UA_Connection *connection, UA_ByteString *buf);
-
-    /* Sends a message over the connection. The message buffer is always freed,
-     * even if sending fails.
-     *
-     * @param connection The connection
-     * @param buf The message buffer
-     * @return Returns an error code or UA_STATUSCODE_GOOD. */
-    UA_StatusCode (*send)(UA_Connection *connection, UA_ByteString *buf);
-
-    /* Receive a message from the remote connection
-     *
-     * @param connection The connection
-     * @param response The response string. It is allocated by the connection
-     *        and needs to be freed with connection->releaseBuffer
-     * @param timeout Timeout of the recv operation in milliseconds
-     * @return Returns UA_STATUSCODE_BADCOMMUNICATIONERROR if the recv operation
-     *         can be repeated, UA_STATUSCODE_GOOD if it succeeded and
-     *         UA_STATUSCODE_BADCONNECTIONCLOSED if the connection was
-     *         closed. */
-    UA_StatusCode (*recv)(UA_Connection *connection, UA_ByteString *response,
-                          UA_UInt32 timeout);
-
-    /* Release the buffer of a received message */
-    void (*releaseRecvBuffer)(UA_Connection *connection, UA_ByteString *buf);
-
-    /* Close the connection */
-    void (*close)(UA_Connection *connection);
-};
-
-void UA_EXPORT UA_Connection_deleteMembers(UA_Connection *connection);
-
-/**
- * EndpointURL Helper
- * ^^^^^^^^^^^^^^^^^^ */
-/* Split the given endpoint url into hostname and port
- * @param endpointUrl The endpoint URL to split up
- * @param hostname the target array for hostname. Has to be at least 256 size.
- *        If an IPv6 address is given, hostname contains e.g.
- *        '[2001:0db8:85a3::8a2e:0370:7334]'
- * @param port set to the port of the url or 0
- * @param path pointing to the end of given endpointUrl or to NULL if no
- *        path given. The starting '/' is NOT included in path
- * @return UA_STATUSCODE_BADOUTOFRANGE if url too long,
- *         UA_STATUSCODE_BADATTRIBUTEIDINVALID if url not starting with
- *         'opc.tcp://', UA_STATUSCODE_GOOD on success
- */
-UA_StatusCode UA_EXPORT
-UA_EndpointUrl_split(const char *endpointUrl, char *hostname,
-                     UA_UInt16 * port, const char ** path);
-
-/* Convert given byte string to a positive number. Returns the number of valid
- * digits. Stops if a non-digit char is found and returns the number of digits
- * up to that point. */
-size_t UA_EXPORT
-UA_readNumber(UA_Byte *buf, size_t buflen, UA_UInt32 *number);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* UA_CONNECTION_H_ */

File diff suppressed because it is too large
+ 1339 - 33
include/ua_constants.h


+ 0 - 47
include/ua_job.h

@@ -1,47 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
-
-
-#ifndef UA_JOB_H_
-#define UA_JOB_H_
-
-#include "ua_connection.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct UA_Server;
-typedef struct UA_Server UA_Server;
-
-typedef void (*UA_ServerCallback)(UA_Server *server, void *data);
-
-/* Jobs describe work that is executed once or repeatedly in the server */
-typedef struct {
-    enum {
-        UA_JOBTYPE_NOTHING,
-        UA_JOBTYPE_DETACHCONNECTION, /* Detach the connection from the secure channel (but don't delete it) */
-        UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER, /* The binary message is memory managed by the networklayer */
-        UA_JOBTYPE_BINARYMESSAGE_ALLOCATED, /* The binary message was relocated away from the networklayer */
-        UA_JOBTYPE_METHODCALL, /* Call the method as soon as possible */
-        UA_JOBTYPE_METHODCALL_DELAYED, /* Call the method as soon as all previous jobs have finished */
-    } type;
-    union {
-        UA_Connection *closeConnection;
-        struct {
-            UA_Connection *connection;
-            UA_ByteString message;
-        } binaryMessage;
-        struct {
-            void *data;
-            UA_ServerCallback method;
-        } methodCall;
-    } job;
-} UA_Job;
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* UA_JOB_H_ */

+ 0 - 136
include/ua_log.h

@@ -1,136 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
-
-#ifndef UA_LOG_H_
-#define UA_LOG_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdarg.h>
-#include "ua_config.h"
-
-/**
- * Logging
- * -------
- *
- * Servers and clients may contain a logger. Every logger needs to implement the
- * `UA_Logger` signature. An example logger that writes to stdout is provided in
- * the plugins folder.
- *
- * Every log-message consists of a log-level, a log-category and a string
- * message content. The timestamp of the log-message is created within the
- * logger.
- */
-
-typedef enum {
-    UA_LOGLEVEL_TRACE,
-    UA_LOGLEVEL_DEBUG,
-    UA_LOGLEVEL_INFO,
-    UA_LOGLEVEL_WARNING,
-    UA_LOGLEVEL_ERROR,
-    UA_LOGLEVEL_FATAL
-} UA_LogLevel;
-
-typedef enum {
-    UA_LOGCATEGORY_NETWORK,
-    UA_LOGCATEGORY_SECURECHANNEL,
-    UA_LOGCATEGORY_SESSION,
-    UA_LOGCATEGORY_SERVER,
-    UA_LOGCATEGORY_CLIENT,
-    UA_LOGCATEGORY_USERLAND
-} UA_LogCategory;
-
-/**
- * The signature of the logger. The msg string and following varargs are
- * formatted according to the rules of the printf command.
- *
- * Do not use the logger directly but make use of the following macros that take
- * the minimum log-level defined in ua_config.h into account. */
-typedef void (*UA_Logger)(UA_LogLevel level, UA_LogCategory category,
-                          const char *msg, va_list args);
-
-static UA_INLINE void
-UA_LOG_TRACE(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
-#if UA_LOGLEVEL <= 100
-    if(logger) {
-        va_list args; va_start(args, msg);
-        logger(UA_LOGLEVEL_TRACE, category, msg, args);
-        va_end(args);
-    }
-#endif
-}
-
-static UA_INLINE void
-UA_LOG_DEBUG(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
-#if UA_LOGLEVEL <= 200
-    if(logger) {
-        va_list args; va_start(args, msg);
-        logger(UA_LOGLEVEL_DEBUG, category, msg, args);
-        va_end(args);
-    }
-#endif
-}
-
-static UA_INLINE void
-UA_LOG_INFO(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
-#if UA_LOGLEVEL <= 300
-    if(logger) {
-        va_list args; va_start(args, msg);
-        logger(UA_LOGLEVEL_INFO, category, msg, args);
-        va_end(args);
-    }
-#endif
-}
-
-static UA_INLINE void
-UA_LOG_WARNING(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
-#if UA_LOGLEVEL <= 400
-    if(logger) {
-        va_list args; va_start(args, msg);
-        logger(UA_LOGLEVEL_WARNING, category, msg, args);
-        va_end(args);
-    }
-#endif
-}
-
-static UA_INLINE void
-UA_LOG_ERROR(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
-#if UA_LOGLEVEL <= 500
-    if(logger) {
-        va_list args; va_start(args, msg);
-        logger(UA_LOGLEVEL_ERROR, category, msg, args);
-        va_end(args);
-    }
-#endif
-}
-
-static UA_INLINE void
-UA_LOG_FATAL(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
-#if UA_LOGLEVEL <= 600
-    if(logger) {
-        va_list args; va_start(args, msg);
-        logger(UA_LOGLEVEL_FATAL, category, msg, args);
-        va_end(args);
-    }
-#endif
-}
-
-/**
- * Convenience macros for complex types
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
-#define UA_PRINTF_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
-#define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \
-        (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \
-        (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7]
-
-#define UA_PRINTF_STRING_FORMAT "\"%.*s\""
-#define UA_PRINTF_STRING_DATA(STRING) (STRING).length, (STRING).data
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#endif /* UA_LOG_H_ */

+ 74 - 0
include/ua_plugin_access_control.h

@@ -0,0 +1,74 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UA_PLUGIN_ACCESS_CONTROL_H_
+#define UA_PLUGIN_ACCESS_CONTROL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_types.h"
+
+/**
+ * Access Control Plugin API
+ * =========================
+ * The access control callback is used to authenticate sessions and grant access
+ * rights accordingly. */
+
+typedef struct {
+    /* These booleans are used to create endpoints for the possible
+     * authentication methods */
+    UA_Boolean enableAnonymousLogin;
+    UA_Boolean enableUsernamePasswordLogin;
+
+    /* Authenticate a session. The session context is attached to the session and
+     * later passed into the node-based access control callbacks. */
+    UA_StatusCode (*activateSession)(const UA_NodeId *sessionId,
+                                     const UA_ExtensionObject *userIdentityToken,
+                                     void **sessionContext);
+
+    /* Deauthenticate a session and cleanup */
+    void (*closeSession)(const UA_NodeId *sessionId, void *sessionContext);
+
+    /* Access control for all nodes*/
+    UA_UInt32 (*getUserRightsMask)(const UA_NodeId *sessionId, void *sessionContext,
+                                   const UA_NodeId *nodeId, void *nodeContext);
+
+    /* Additional access control for variable nodes */
+    UA_Byte (*getUserAccessLevel)(const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *nodeId, void *nodeContext);
+
+    /* Additional access control for method nodes */
+    UA_Boolean (*getUserExecutable)(const UA_NodeId *sessionId, void *sessionContext,
+                                    const UA_NodeId *methodId, void *methodContext);
+
+    /* Additional access control for calling a method node in the context of a
+     * specific object */
+    UA_Boolean (*getUserExecutableOnObject)(const UA_NodeId *sessionId, void *sessionContext,
+                                            const UA_NodeId *methodId, void *methodContext,
+                                            const UA_NodeId *objectId, void *objectContext);
+
+    /* Allow adding a node */
+    UA_Boolean (*allowAddNode)(const UA_NodeId *sessionId, void *sessionContext,
+                               const UA_AddNodesItem *item);
+
+    /* Allow adding a reference */
+    UA_Boolean (*allowAddReference)(const UA_NodeId *sessionId, void *sessionContext,
+                                    const UA_AddReferencesItem *item);
+
+    /* Allow deleting a node */
+    UA_Boolean (*allowDeleteNode)(const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_DeleteNodesItem *item);
+
+    /* Allow deleting a reference */
+    UA_Boolean (*allowDeleteReference)(const UA_NodeId *sessionId, void *sessionContext,
+                                       const UA_DeleteReferencesItem *item);
+} UA_AccessControl;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_PLUGIN_ACCESS_CONTROL_H_ */

+ 121 - 0
include/ua_plugin_log.h

@@ -0,0 +1,121 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this 
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UA_PLUGIN_LOG_H_
+#define UA_PLUGIN_LOG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+#include "ua_config.h"
+
+/**
+ * Logging Plugin API
+ * ==================
+ *
+ * Servers and clients must define a logger in their configuration. The logger
+ * is just a function pointer. Every log-message consists of a log-level, a
+ * log-category and a string message content. The timestamp of the log-message
+ * is created within the logger. */
+
+typedef enum {
+    UA_LOGLEVEL_TRACE,
+    UA_LOGLEVEL_DEBUG,
+    UA_LOGLEVEL_INFO,
+    UA_LOGLEVEL_WARNING,
+    UA_LOGLEVEL_ERROR,
+    UA_LOGLEVEL_FATAL
+} UA_LogLevel;
+
+typedef enum {
+    UA_LOGCATEGORY_NETWORK,
+    UA_LOGCATEGORY_SECURECHANNEL,
+    UA_LOGCATEGORY_SESSION,
+    UA_LOGCATEGORY_SERVER,
+    UA_LOGCATEGORY_CLIENT,
+    UA_LOGCATEGORY_USERLAND,
+    UA_LOGCATEGORY_SECURITYPOLICY
+} UA_LogCategory;
+
+/**
+ * The message string and following varargs are formatted according to the rules
+ * of the printf command. Do not call the logger directly. Instead, make use of
+ * the convenience macros that take the minimum log-level defined in ua_config.h
+ * into account. */
+
+typedef void (*UA_Logger)(UA_LogLevel level, UA_LogCategory category,
+                          const char *msg, va_list args);
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_TRACE(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 100
+    va_list args; va_start(args, msg);
+    logger(UA_LOGLEVEL_TRACE, category, msg, args);
+    va_end(args);
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_DEBUG(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 200
+    va_list args; va_start(args, msg);
+    logger(UA_LOGLEVEL_DEBUG, category, msg, args);
+    va_end(args);
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_INFO(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 300
+    va_list args; va_start(args, msg);
+    logger(UA_LOGLEVEL_INFO, category, msg, args);
+    va_end(args);
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_WARNING(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 400
+    va_list args; va_start(args, msg);
+    logger(UA_LOGLEVEL_WARNING, category, msg, args);
+    va_end(args);
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_ERROR(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 500
+    va_list args; va_start(args, msg);
+    logger(UA_LOGLEVEL_ERROR, category, msg, args);
+    va_end(args);
+#endif
+}
+
+static UA_INLINE UA_FORMAT(3,4) void
+UA_LOG_FATAL(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
+#if UA_LOGLEVEL <= 600
+    va_list args; va_start(args, msg);
+    logger(UA_LOGLEVEL_FATAL, category, msg, args);
+    va_end(args);
+#endif
+}
+
+/**
+ * Convenience macros for complex types
+ * ------------------------------------ */
+#define UA_PRINTF_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+#define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \
+        (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \
+        (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7]
+
+#define UA_PRINTF_STRING_FORMAT "\"%.*s\""
+#define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* UA_PLUGIN_LOG_H_ */

+ 223 - 0
include/ua_plugin_network.h

@@ -0,0 +1,223 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UA_PLUGIN_NETWORK_H_
+#define UA_PLUGIN_NETWORK_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_server.h"
+
+/* Forward declarations */
+struct UA_Connection;
+typedef struct UA_Connection UA_Connection;
+
+struct UA_SecureChannel;
+typedef struct UA_SecureChannel UA_SecureChannel;
+
+struct UA_ServerNetworkLayer;
+typedef struct UA_ServerNetworkLayer UA_ServerNetworkLayer;
+
+/**
+ * .. _networking:
+ * 
+ * Networking Plugin API
+ * =====================
+ *
+ * Connection
+ * ----------
+ * Client-server connections are represented by a `UA_Connection`. The
+ * connection is stateful and stores partially received messages, and so on. In
+ * addition, the connection contains function pointers to the underlying
+ * networking implementation. An example for this is the `send` function. So the
+ * connection encapsulates all the required networking functionality. This lets
+ * users on embedded (or otherwise exotic) systems implement their own
+ * networking plugins with a clear interface to the main open62541 library. */
+
+typedef struct {
+    UA_UInt32 protocolVersion;
+    UA_UInt32 sendBufferSize;
+    UA_UInt32 recvBufferSize;
+    UA_UInt32 maxMessageSize;
+    UA_UInt32 maxChunkCount;
+} UA_ConnectionConfig;
+
+typedef enum {
+    UA_CONNECTION_OPENING,     /* The socket is open, but the HEL/ACK handshake
+                                * is not done */
+    UA_CONNECTION_ESTABLISHED, /* The socket is open and the connection
+                                * configured */
+    UA_CONNECTION_CLOSED       /* The socket has been closed and the connection
+                                * will be deleted */
+} UA_ConnectionState;
+
+struct UA_Connection {
+    UA_ConnectionState state;
+    UA_ConnectionConfig localConf;
+    UA_ConnectionConfig remoteConf;
+    UA_SecureChannel *channel;       /* The securechannel that is attached to
+                                      * this connection */
+    UA_Int32 sockfd;                 /* Most connectivity solutions run on
+                                      * sockets. Having the socket id here
+                                      * simplifies the design. */
+    void *handle;                    /* A pointer to internal data */
+    UA_ByteString incompleteMessage; /* A half-received message (TCP is a
+                                      * streaming protocol) is stored here */
+
+    /* Get a buffer for sending */
+    UA_StatusCode (*getSendBuffer)(UA_Connection *connection, size_t length,
+                                   UA_ByteString *buf);
+
+    /* Release the send buffer manually */
+    void (*releaseSendBuffer)(UA_Connection *connection, UA_ByteString *buf);
+
+    /* Sends a message over the connection. The message buffer is always freed,
+     * even if sending fails.
+     *
+     * @param connection The connection
+     * @param buf The message buffer
+     * @return Returns an error code or UA_STATUSCODE_GOOD. */
+    UA_StatusCode (*send)(UA_Connection *connection, UA_ByteString *buf);
+
+    /* Receive a message from the remote connection
+     *
+     * @param connection The connection
+     * @param response The response string. It is allocated by the connection
+     *        and needs to be freed with connection->releaseBuffer
+     * @param timeout Timeout of the recv operation in milliseconds
+     * @return Returns UA_STATUSCODE_BADCOMMUNICATIONERROR if the recv operation
+     *         can be repeated, UA_STATUSCODE_GOOD if it succeeded and
+     *         UA_STATUSCODE_BADCONNECTIONCLOSED if the connection was
+     *         closed. */
+    UA_StatusCode (*recv)(UA_Connection *connection, UA_ByteString *response,
+                          UA_UInt32 timeout);
+
+    /* Release the buffer of a received message */
+    void (*releaseRecvBuffer)(UA_Connection *connection, UA_ByteString *buf);
+
+    /* Close the connection. The network layer closes the socket. This is picked
+     * up during the next 'listen' and the connection is freed in the network
+     * layer. */
+    void (*close)(UA_Connection *connection);
+
+    /* To be called only from within the server (and not the network layer).
+     * Frees up the connection's memory. */
+    void (*free)(UA_Connection *connection);
+};
+
+/* Cleans up half-received messages, and so on. Called from connection->free. */
+void UA_EXPORT
+UA_Connection_deleteMembers(UA_Connection *connection);
+
+/**
+ * Server Network Layer
+ * --------------------
+ * The server exposes two functions to interact with remote clients:
+ * `processBinaryMessage` and `removeConnection`. These functions are called by
+ * the server network layer.
+ *
+ * It is the job of the server network layer to listen on a TCP socket, to
+ * accept new connections, to call the server with received messages and to
+ * signal closed connections to the server.
+ *
+ * The network layer is part of the server config. So users can provide a custom
+ * implementation if the provided example does not fit their architecture. The
+ * network layer is invoked only from the server's main loop. So the network
+ * layer does not need to be thread-safe. If the networklayer receives a
+ * positive duration for blocking listening, the server's main loop will block
+ * until a message is received or the duration times out. */
+
+/* Process a binary message (TCP packet). The message can contain partial
+ * chunks. (TCP is a streaming protocol and packets may be split/merge during
+ * transport.) After processing, the message is freed with
+ * connection->releaseRecvBuffer. */
+void UA_EXPORT
+UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection,
+                               UA_ByteString *message);
+
+/* The server internally cleans up the connection and then calls
+ * connection->free. */
+void UA_EXPORT
+UA_Server_removeConnection(UA_Server *server, UA_Connection *connection);
+
+struct UA_ServerNetworkLayer {
+    void *handle; /* Internal data */
+    UA_String discoveryUrl;
+
+    /* Start listening on the networklayer.
+     *
+     * @param nl The network layer
+     * @return Returns UA_STATUSCODE_GOOD or an error code. */
+    UA_StatusCode (*start)(UA_ServerNetworkLayer *nl);
+
+    /* Listen for new and closed connections and arriving packets. Calls
+     * UA_Server_processBinaryMessage for the arriving packets. Closed
+     * connections are picked up here and forwarded to
+     * UA_Server_removeConnection where they are cleaned up and freed.
+     *
+     * @param nl The network layer
+     * @param server The server for processing the incoming packets and for
+     *               closing connections. 
+     * @param timeout The timeout during which an event must arrive in
+     *                milliseconds
+     * @return A statuscode for the status of the network layer. */
+    UA_StatusCode (*listen)(UA_ServerNetworkLayer *nl, UA_Server *server,
+                            UA_UInt16 timeout);
+
+    /* Close the network socket and all open connections. Afterwards, the
+     * network layer can be safely deleted.
+     *
+     * @param nl The network layer
+     * @param server The server that processes the incoming packets and for
+     *               closing connections before deleting them.
+     * @return A statuscode for the status of the closing operation. */
+    void (*stop)(UA_ServerNetworkLayer *nl, UA_Server *server);
+
+    /* Deletes the network layer context. Call only after stopping. */
+    void (*deleteMembers)(UA_ServerNetworkLayer *nl);
+};
+
+/**
+ * Client Network Layer
+ * --------------------
+ * The client has only a single connection used for sending and receiving binary
+ * messages. */
+
+/* @param localConf the connection config for this client
+ * @param endpointUrl to where to connect
+ * @param timeout in ms until the connection try times out if remote not reachable */
+typedef UA_Connection
+(*UA_ConnectClientConnection)(UA_ConnectionConfig localConf, const char *endpointUrl,
+                              const UA_UInt32 timeout);
+
+/**
+ * Endpoint URL Parser
+ * -------------------
+ * The endpoint URL parser is generally useful for the implementation of network
+ * layer plugins. */
+
+/* Split the given endpoint url into hostname, port and path. All arguments must
+ * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port
+ * and path may be omitted (together with the prefix colon and slash).
+ *
+ * @param endpointUrl The endpoint URL.
+ * @param outHostname Set to the parsed hostname. The string points into the
+ *        original endpointUrl, so no memory is allocated. If an IPv6 address is
+ *        given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]'
+ * @param outPort Set to the port of the url or left unchanged.
+ * @param outPath Set to the path if one is present in the endpointUrl.
+ *        Starting or trailing '/' are NOT included in the path. The string
+ *        points into the original endpointUrl, so no memory is allocated.
+ * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */
+UA_StatusCode UA_EXPORT
+UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
+                    UA_UInt16 *outPort, UA_String *outPath);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* UA_PLUGIN_NETWORK_H_ */

+ 142 - 22
src/server/ua_nodes.h

@@ -1,9 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
-#ifndef UA_NODES_H_
-#define UA_NODES_H_
+#ifndef UA_SERVER_NODES_H_
+#define UA_SERVER_NODES_H_
+
+/* !!! Warning !!!
+ *
+ * If you are not developing a nodestore plugin, then you should not work with
+ * the definitions from this file directly. The underlying node structures are
+ * not meant to be used directly by end users. Please use the public server API
+ * / OPC UA services to interact with the information model. */
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -32,10 +39,11 @@ extern "C" {
  * section on :ref:`ReferenceTypes <referencetypenode>` for more details on
  * section on :ref:`ReferenceTypes <referencetypenode>` for more details on
  * possible references and their semantics.
  * possible references and their semantics.
  *
  *
- * The structures defined in this section are *not user-facing*. The interaction
- * with the information model is possible only via the OPC UA :ref:`services`.
- * Still, we reproduce how nodes are represented internally so that users may
- * have a clear mental model.
+ * **Warning!!** The structures defined in this section are only relevant for
+ * the developers of custom Nodestores. The interaction with the information
+ * model is possible only via the OPC UA :ref:`services`. So the following
+ * sections are purely informational so that users may have a clear mental
+ * model of the underlying representation.
  *
  *
  * Base Node Attributes
  * Base Node Attributes
  * --------------------
  * --------------------
@@ -48,6 +56,15 @@ extern "C" {
  * Internally, open62541 uses ``UA_Node`` in places where the exact node type is
  * Internally, open62541 uses ``UA_Node`` in places where the exact node type is
  * not known or not important. The ``nodeClass`` attribute is used to ensure the
  * not known or not important. The ``nodeClass`` attribute is used to ensure the
  * correctness of casting from ``UA_Node`` to a specific node type. */
  * correctness of casting from ``UA_Node`` to a specific node type. */
+
+/* List of reference targets with the same reference type and direction */
+typedef struct {
+    UA_NodeId referenceTypeId;
+    UA_Boolean isInverse;
+    size_t targetIdsSize;
+    UA_ExpandedNodeId *targetIds;
+} UA_NodeReferenceKind;
+
 #define UA_NODE_BASEATTRIBUTES                  \
 #define UA_NODE_BASEATTRIBUTES                  \
     UA_NodeId nodeId;                           \
     UA_NodeId nodeId;                           \
     UA_NodeClass nodeClass;                     \
     UA_NodeClass nodeClass;                     \
@@ -55,9 +72,11 @@ extern "C" {
     UA_LocalizedText displayName;               \
     UA_LocalizedText displayName;               \
     UA_LocalizedText description;               \
     UA_LocalizedText description;               \
     UA_UInt32 writeMask;                        \
     UA_UInt32 writeMask;                        \
-    UA_UInt32 userWriteMask;                    \
     size_t referencesSize;                      \
     size_t referencesSize;                      \
-    UA_ReferenceNode *references;
+    UA_NodeReferenceKind *references;           \
+                                                \
+    /* Members specific to open62541 */         \
+    void *context;
 
 
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
@@ -128,6 +147,7 @@ typedef struct {
  *
  *
  * Consistency between the array dimensions attribute in the variable and its
  * Consistency between the array dimensions attribute in the variable and its
  * :ref:`variabletypenode` is ensured. */
  * :ref:`variabletypenode` is ensured. */
+
 /* Indicates whether a variable contains data inline or whether it points to an
 /* Indicates whether a variable contains data inline or whether it points to an
  * external data source */
  * external data source */
 typedef enum {
 typedef enum {
@@ -156,7 +176,6 @@ typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
     UA_Byte accessLevel;
     UA_Byte accessLevel;
-    UA_Byte userAccessLevel;
     UA_Double minimumSamplingInterval;
     UA_Double minimumSamplingInterval;
     UA_Boolean historizing; /* currently unsupported */
     UA_Boolean historizing; /* currently unsupported */
 } UA_VariableNode;
 } UA_VariableNode;
@@ -173,10 +192,14 @@ typedef struct {
  * variable type may provide semantic information. For example, an instance from
  * variable type may provide semantic information. For example, an instance from
  * ``MotorTemperatureVariableType`` is more meaningful than a float variable
  * ``MotorTemperatureVariableType`` is more meaningful than a float variable
  * instantiated from ``BaseDataVariable``. */
  * instantiated from ``BaseDataVariable``. */
+
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
+
+    /* Members specific to open62541 */
+    UA_NodeTypeLifecycle lifecycle;
 } UA_VariableTypeNode;
 } UA_VariableTypeNode;
 
 
 /**
 /**
@@ -195,16 +218,14 @@ typedef struct {
  *
  *
  * Note that the same MethodNode may be referenced from several objects (and
  * Note that the same MethodNode may be referenced from several objects (and
  * object types). For this, the NodeId of the method *and of the object
  * object types). For this, the NodeId of the method *and of the object
- * providing context* is part of a Call request message.
- */
+ * providing context* is part of a Call request message. */
+
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_Boolean executable;
     UA_Boolean executable;
-    UA_Boolean userExecutable;
 
 
     /* Members specific to open62541 */
     /* Members specific to open62541 */
-    void *methodHandle;
-    UA_MethodCallback attachedMethod;
+    UA_MethodCallback method;
 } UA_MethodNode;
 } UA_MethodNode;
 
 
 /**
 /**
@@ -215,12 +236,10 @@ typedef struct {
  * and software objects. Objects are instances of an :ref:`object
  * and software objects. Objects are instances of an :ref:`object
  * type<objecttypenode>` and may contain variables, methods and further
  * type<objecttypenode>` and may contain variables, methods and further
  * objects. */
  * objects. */
+
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_Byte eventNotifier;
     UA_Byte eventNotifier;
-
-    /* Members specific to open62541 */
-    void *instanceHandle;
 } UA_ObjectNode;
 } UA_ObjectNode;
 
 
 /**
 /**
@@ -230,14 +249,15 @@ typedef struct {
  * --------------
  * --------------
  *
  *
  * ObjectTypes provide definitions for Objects. Abstract objects cannot be
  * ObjectTypes provide definitions for Objects. Abstract objects cannot be
- * instantiated. See :ref:`object-lifecycle` for the use of constructor and
+ * instantiated. See :ref:`node-lifecycle` for the use of constructor and
  * destructor callbacks. */
  * destructor callbacks. */
+
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
 
 
     /* Members specific to open62541 */
     /* Members specific to open62541 */
-    UA_ObjectLifecycleManagement lifecycleManagement;
+    UA_NodeTypeLifecycle lifecycle;
 } UA_ObjectTypeNode;
 } UA_ObjectTypeNode;
 
 
 /**
 /**
@@ -342,6 +362,7 @@ typedef struct {
  * electrical and information related connections. A client can then learn the
  * electrical and information related connections. A client can then learn the
  * layout of a (physical) system represented in an OPC UA information model
  * layout of a (physical) system represented in an OPC UA information model
  * based on a common understanding of just two custom reference types. */
  * based on a common understanding of just two custom reference types. */
+
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
@@ -363,6 +384,7 @@ typedef struct {
  * Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values.
  * Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values.
  * They are used to constrain values to possible child DataTypes (e.g.
  * They are used to constrain values to possible child DataTypes (e.g.
  * ``UInt32``). */
  * ``UInt32``). */
+
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
@@ -377,14 +399,112 @@ typedef struct {
  * references only. ViewNodes can be created and be interacted with. But their
  * references only. ViewNodes can be created and be interacted with. But their
  * use in the :ref:`Browse<view-services>` service is currently unsupported in
  * use in the :ref:`Browse<view-services>` service is currently unsupported in
  * open62541. */
  * open62541. */
+
 typedef struct {
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_BASEATTRIBUTES
     UA_Byte eventNotifier;
     UA_Byte eventNotifier;
     UA_Boolean containsNoLoops;
     UA_Boolean containsNoLoops;
 } UA_ViewNode;
 } UA_ViewNode;
 
 
+/**
+ * Nodestore Plugin API
+ * --------------------
+ * The following definitions are used for implementing custom node storage
+ * backends. **Most users will want to use the default nodestore and don't need
+ * to work with the nodestore API**.
+ *
+ * Outside of custom nodestore implementations, users should not manually edit
+ * nodes. Please use the OPC UA services for that. Otherwise, all consistency
+ * checks are omitted. This can crash the application eventually. */
+
+typedef void (*UA_NodestoreVisitor)(void *visitorContext, const UA_Node *node);
+
+typedef struct {
+    /* Nodestore context and lifecycle */
+    void *context;
+    void (*deleteNodestore)(void *nodestoreContext);
+
+    /* For non-multithreaded access, some nodestores allow that nodes are edited
+     * without a copy/replace. This is not possible when the node is only an
+     * intermediate representation and stored e.g. in a database backend. */
+    UA_Boolean inPlaceEditAllowed;
+
+    /* The following definitions are used to create empty nodes of the different
+     * node types. The memory is managed by the nodestore. Therefore, the node
+     * has to be removed via a special deleteNode function. (If the new node is
+     * not added to the nodestore.) */
+    UA_Node * (*newNode)(void *nodestoreContext, UA_NodeClass nodeClass);
+
+    void (*deleteNode)(void *nodestoreContext, UA_Node *node);
+
+    /* ``Get`` returns a pointer to an immutable node. ``Release`` indicates
+     * that the pointer is no longer accessed afterwards. */
+
+    const UA_Node * (*getNode)(void *nodestoreContext, const UA_NodeId *nodeId);
+
+    void (*releaseNode)(void *nodestoreContext, const UA_Node *node);
+
+    /* Returns an editable copy of a node (needs to be deleted with the
+     * deleteNode function or inserted / replaced into the nodestore). */
+    UA_StatusCode (*getNodeCopy)(void *nodestoreContext, const UA_NodeId *nodeId,
+                                 UA_Node **outNode);
+
+    /* Inserts a new node into the nodestore. If the NodeId is zero, then a
+     * fresh numeric NodeId is assigned. If insertion fails, the node is
+     * deleted. */
+    UA_StatusCode (*insertNode)(void *nodestoreContext, UA_Node *node,
+                                UA_NodeId *addedNodeId);
+
+    /* To replace a node, get an editable copy of the node, edit and replace
+     * with this function. If the node was already replaced since the copy was
+     * made, UA_STATUSCODE_BADINTERNALERROR is returned. If the NodeId is not
+     * found, UA_STATUSCODE_BADNODEIDUNKNOWN is returned. In both error cases,
+     * the editable node is deleted. */
+    UA_StatusCode (*replaceNode)(void *nodestoreContext, UA_Node *node);
+
+    /* Removes a node from the nodestore. */
+    UA_StatusCode (*removeNode)(void *nodestoreContext, const UA_NodeId *nodeId);
+
+    /* Execute a callback for every node in the nodestore. */
+    void (*iterate)(void *nodestoreContext, void* visitorContext,
+                    UA_NodestoreVisitor visitor);
+} UA_Nodestore;
+
+/**
+ * The following methods specialize internally for the different node classes
+ * (distinguished by the nodeClass member) */
+
+/* Attributes must be of a matching type (VariableAttributes, ObjectAttributes,
+ * and so on). The attributes are copied. Note that the attributes structs do
+ * not contain NodeId, NodeClass and BrowseName. The NodeClass of the node needs
+ * to be correctly set before calling this method. UA_Node_deleteMembers is
+ * called on the node when an error occurs internally. */
+UA_StatusCode UA_EXPORT
+UA_Node_setAttributes(UA_Node *node, const void *attributes,
+                      const UA_DataType *attributeType);
+
+/* Reset the destination node and copy the content of the source */
+UA_StatusCode UA_EXPORT
+UA_Node_copy(const UA_Node *src, UA_Node *dst);
+
+/* Add a single reference to the node */
+UA_StatusCode UA_EXPORT
+UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item);
+
+/* Delete a single reference from the node */
+UA_StatusCode UA_EXPORT
+UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item);
+
+/* Delete all references of the node */
+void UA_EXPORT
+UA_Node_deleteReferences(UA_Node *node);
+
+/* Remove all malloc'ed members of the node */
+void UA_EXPORT
+UA_Node_deleteMembers(UA_Node *node);
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"
 #endif
 #endif
 
 
-#endif /* UA_NODES_H_ */
+#endif /* UA_SERVER_NODES_H_ */

+ 309 - 0
include/ua_plugin_securitypolicy.h

@@ -0,0 +1,309 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UA_PLUGIN_SECURITYPOLICY_H_
+#define UA_PLUGIN_SECURITYPOLICY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_types.h"
+#include "ua_types_generated.h"
+#include "ua_plugin_log.h"
+
+extern const UA_ByteString UA_SECURITY_POLICY_NONE_URI;
+
+struct UA_SecurityPolicy;
+typedef struct UA_SecurityPolicy UA_SecurityPolicy;
+
+typedef struct {
+    UA_String signatureAlgorithmUri;
+
+    /* Verifies the signature of the message using the provided keys in the context.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext that contains the key to verify
+     *                       the supplied message with.
+     * @param message the message to which the signature is supposed to belong.
+     * @param signature the signature of the message, that should be verified. */
+    UA_StatusCode (*verify)(const UA_SecurityPolicy *securityPolicy,
+                            const void *channelContext, const UA_ByteString *message,
+                            const UA_ByteString *signature) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Signs the given message using this policys signing algorithm and the
+     * provided keys in the context.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext that contains the key to sign
+     *                       the supplied message with.
+     * @param message the message to sign.
+     * @param signature an output buffer to which the signature is written. The
+     *                  buffer needs to be allocated by the caller. The
+     *                  necessary size can be acquired with the signatureSize
+     *                  attribute of this module. */
+    UA_StatusCode (*sign)(const UA_SecurityPolicy *securityPolicy,
+                          const void *channelContext, const UA_ByteString *message,
+                          UA_ByteString *signature) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Gets the signature size that depends on the local (private) key.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext that contains the
+     *                       certificate/key.
+     * @return the size of the local signature. Returns 0 if no local
+     *         certificate was set. */
+    size_t (*getLocalSignatureSize)(const UA_SecurityPolicy *securityPolicy,
+                                    const void *channelContext);
+
+    /* Gets the signature size that depends on the remote (public) key.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the context to retrieve data from.
+     * @return the size of the remote signature. Returns 0 if no
+     *         remote certificate was set previousely. */
+    size_t (*getRemoteSignatureSize)(const UA_SecurityPolicy *securityPolicy,
+                                     const void *channelContext);
+
+    UA_String encryptionAlgorithmUri;
+
+    /* Encrypt the given data in place using an asymmetric algorithm and keys.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext which contains information about
+     *                       the keys to encrypt data.
+     * @param data the data that is encrypted. The encrypted data will overwrite
+     *             the data that was supplied. */
+    UA_StatusCode(*encrypt)(const UA_SecurityPolicy *securityPolicy,
+                            const void *channelContext,
+                            UA_ByteString *data) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Decrypts the given ciphertext in place using an asymmetric algorithm and
+     * key.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the channelContext which contains information about
+     *                       the keys needed to decrypt the message.
+     * @param data the data to decrypt. The decryption is done in place. */
+    UA_StatusCode(*decrypt)(const UA_SecurityPolicy *securityPolicy,
+                            const void *channelContext,
+                            UA_ByteString *data) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Returns the length of the key used locally to encrypt messages in bits
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the context to retrieve data from.
+     * @return the length of the local key. Returns 0 if no
+     *         key length is known. */
+    size_t (*getLocalEncryptionKeyLength)(const UA_SecurityPolicy *securityPolicy,
+                                          const void *channelContext);
+
+    /* Returns the length of the key used remotely to encrypt messages in bits
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param channelContext the context to retrieve data from.
+     * @return the length of the remote key. Returns 0 if no
+     *         key length is known. */
+    size_t (*getRemoteEncryptionKeyLength)(const UA_SecurityPolicy *securityPolicy,
+                                           const void *channelContext);
+} UA_SecurityPolicyCryptoModule;
+
+typedef struct {
+    /* Generates a thumprint for the specified certificate.
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param certificate the certificate to make a thumbprint of.
+     * @param thumbprint an output buffer for the resulting thumbprint. Always
+     *                   has the length specified in the thumprintLenght in the
+     *                   asymmetricModule. */
+    UA_StatusCode (*makeCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy,
+                                               const UA_ByteString *certificate,
+                                               UA_ByteString *thumbprint)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Compares the supplied certificate with the certificate in the endpoit context.
+     *
+     * @param securityPolicy the policy data that contains the certificate
+     *                       to compare to.
+     * @param certificateThumbprint the certificate thumbprint to compare to the
+     *                              one stored in the context.
+     * @return if the thumbprints match UA_STATUSCODE_GOOD is returned. If they
+     *         don't match or an error occured an error code is returned. */
+    UA_StatusCode (*compareCertificateThumbprint)(const UA_SecurityPolicy *securityPolicy,
+                                                  const UA_ByteString *certificateThumbprint)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    UA_SecurityPolicyCryptoModule cryptoModule;
+} UA_SecurityPolicyAsymmetricModule;
+
+typedef struct {
+    /* Pseudo random function that is used to generate the symmetric keys.
+     *
+     * For information on what parameters this function receives in what situation,
+     * refer to the OPC UA specification 1.03 Part6 Table 33
+     *
+     * @param securityPolicy the securityPolicy the function is invoked on.
+     * @param secret
+     * @param seed
+     * @param out an output to write the data to. The length defines the maximum
+     *            number of output bytes that are produced. */
+    UA_StatusCode (*generateKey)(const UA_SecurityPolicy *securityPolicy,
+                                 const UA_ByteString *secret,
+                                 const UA_ByteString *seed, UA_ByteString *out)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+    /* Random generator for generating nonces.
+     *
+     * @param securityPolicy the securityPolicy this function is invoked on.
+     *                       Example: myPolicy->generateNonce(myPolicy,
+     *                       &outBuff);
+     * @param out pointer to a buffer to store the nonce in. Needs to be
+     *            allocated by the caller. The buffer is filled with random
+     *            data. */
+    UA_StatusCode (*generateNonce)(const UA_SecurityPolicy *securityPolicy,
+                                   UA_ByteString *out)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    UA_SecurityPolicyCryptoModule cryptoModule;
+    size_t encryptionBlockSize;
+    size_t signingKeyLength;
+} UA_SecurityPolicySymmetricModule;
+
+typedef struct {
+    /* This method creates a new context data object.
+     *
+     * The caller needs to call delete on the recieved object to free allocated
+     * memory. Memory is only allocated if the function succeeds so there is no
+     * need to manually free the memory pointed to by *channelContext or to
+     * call delete in case of failure.
+     *
+     * @param securityPolicy the policy context of the endpoint that is connected
+     *                       to. It will be stored in the channelContext for
+     *                       further access by the policy.
+     * @param remoteCertificate the remote certificate contains the remote
+     *                          asymmetric key. The certificate will be verified
+     *                          and then stored in the context so that its
+     *                          details may be accessed.
+     * @param channelContext the initialized channelContext that is passed to
+     *                       functions that work on a context. */
+    UA_StatusCode (*newContext)(const UA_SecurityPolicy *securityPolicy,
+                                const UA_ByteString *remoteCertificate,
+                                void **channelContext)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Deletes the the security context. */
+    void (*deleteContext)(void *channelContext);
+
+    /* Sets the local encrypting key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the local encrypting key to store in the context. */
+    UA_StatusCode (*setLocalSymEncryptingKey)(void *channelContext,
+                                              const UA_ByteString *key)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Sets the local signing key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the local signing key to store in the context. */
+    UA_StatusCode (*setLocalSymSigningKey)(void *channelContext,
+                                           const UA_ByteString *key)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Sets the local initialization vector in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param iv the local initialization vector to store in the context. */
+    UA_StatusCode (*setLocalSymIv)(void *channelContext,
+                                   const UA_ByteString *iv)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Sets the remote encrypting key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the remote encrypting key to store in the context. */
+    UA_StatusCode (*setRemoteSymEncryptingKey)(void *channelContext,
+                                               const UA_ByteString *key)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Sets the remote signing key in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param key the remote signing key to store in the context. */
+    UA_StatusCode (*setRemoteSymSigningKey)(void *channelContext,
+                                            const UA_ByteString *key)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Sets the remote initialization vector in the supplied context.
+     *
+     * @param channelContext the context to work on.
+     * @param iv the remote initialization vector to store in the context. */
+    UA_StatusCode (*setRemoteSymIv)(void *channelContext,
+                                    const UA_ByteString *iv)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Compares the supplied certificate with the certificate in the channel
+     * context.
+     *
+     * @param channelContext the channel context data that contains the
+     *                       certificate to compare to.
+     * @param certificate the certificate to compare to the one stored in the context.
+     * @return if the certificates match UA_STATUSCODE_GOOD is returned. If they
+     *         don't match or an errror occured an error code is returned. */
+    UA_StatusCode (*compareCertificate)(const void *channelContext,
+                                        const UA_ByteString *certificate)
+        UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+
+    /* Gets the plaintext block size that depends on the remote public key.
+     *
+     * @param channelContext the context to retrieve data from.
+     * @return the size of the plain text block size when encrypting with the
+     *         remote public key. Returns 0 as long as no remote certificate was
+     *         set previousely. */
+    size_t (*getRemoteAsymPlainTextBlockSize)(const void *channelContext);
+
+    /* Gets the number of bytes that are needed by the encryption function in
+     * addition to the length of the plaintext message. This is needed, since
+     * most RSA encryption methods have their own padding mechanism included.
+     * This makes the encrypted message larger than the plainText, so we need to
+     * have enough room in the buffer for the overhead.
+     *
+     * @param channelContext the retrieve data from.
+     * @param maxEncryptionLength the maximum number of bytes that the data to
+     *                            encrypt can be. */
+    size_t (*getRemoteAsymEncryptionBufferLengthOverhead)(const void *channelContext,
+                                                          size_t maxEncryptionLength);
+} UA_SecurityPolicyChannelModule;
+
+struct UA_SecurityPolicy {
+    /* Additional data */
+    void *policyContext;
+
+    /* The policy uri that identifies the implemented algorithms */
+    UA_ByteString policyUri;
+
+    /* The local certificate is specific for each SecurityPolicy since it
+     * depends on the used key length. */
+    UA_ByteString localCertificate;
+
+    /* Function pointers grouped into modules */
+    UA_SecurityPolicyAsymmetricModule asymmetricModule;
+    UA_SecurityPolicySymmetricModule symmetricModule;
+    UA_SecurityPolicyChannelModule channelModule;
+
+    UA_Logger logger;
+
+    /* Deletes the dynamic content of the policy */
+    void (*deleteMembers)(UA_SecurityPolicy *policy);
+};
+
+typedef struct {
+    UA_SecurityPolicy securityPolicy;
+    UA_EndpointDescription endpointDescription;
+} UA_Endpoint;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_PLUGIN_SECURITYPOLICY_H_ */

+ 428 - 274
include/ua_server.h

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef UA_SERVER_H_
 #ifndef UA_SERVER_H_
 #define UA_SERVER_H_
 #define UA_SERVER_H_
@@ -9,14 +9,15 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#include "ua_config.h"
 #include "ua_types.h"
 #include "ua_types.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated_handling.h"
 #include "ua_types_generated_handling.h"
-#include "ua_nodeids.h"
-#include "ua_log.h"
-#include "ua_job.h"
-#include "ua_connection.h"
+
+struct UA_ServerConfig;
+typedef struct UA_ServerConfig UA_ServerConfig;
+
+struct UA_Server;
+typedef struct UA_Server UA_Server;
 
 
 /**
 /**
  * .. _server:
  * .. _server:
@@ -24,123 +25,16 @@ extern "C" {
  * Server
  * Server
  * ======
  * ======
  *
  *
- * Network Layer
- * -------------
- * Interface to the binary network layers. The functions in the network layer
- * are never called in parallel but only sequentially from the server's main
- * loop. So the network layer does not need to be thread-safe. */
-struct UA_ServerNetworkLayer;
-typedef struct UA_ServerNetworkLayer UA_ServerNetworkLayer;
-
-struct UA_ServerNetworkLayer {
-    void *handle; // pointer to internal data
-    UA_String discoveryUrl;
-
-    /* Starts listening on the the networklayer.
-     *
-     * @param nl The network layer
-     * @param logger The logger
-     * @return Returns UA_STATUSCODE_GOOD or an error code. */
-    UA_StatusCode (*start)(UA_ServerNetworkLayer *nl, UA_Logger logger);
-
-    /* Gets called from the main server loop and returns the jobs (accumulated
-     * messages and close events) for dispatch.
-     *
-     * @param nl The network layer
-     * @param jobs When the returned integer is >0, *jobs points to an array of
-     *        UA_Job of the returned size.
-     * @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)(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 network layer can be safely deleted.
-     *
-     * @param nl The network layer
-     * @param jobs When the returned integer is >0, jobs points to an array of
-     *        UA_Job of the returned size.
-     * @return The size of the jobs array. If the result is negative,
-     *         an error has occurred. */
-    size_t (*stop)(UA_ServerNetworkLayer *nl, UA_Job **jobs);
-
-    /** Deletes the network content. Call only after stopping. */
-    void (*deleteMembers)(UA_ServerNetworkLayer *nl);
-};
-
-/**
- * Server Configuration
- * --------------------
- * The following structure is passed to a new server for configuration. */
-typedef struct {
-    UA_String username;
-    UA_String password;
-} UA_UsernamePasswordLogin;
-
-typedef struct {
-    UA_UInt32 min;
-    UA_UInt32 max;
-} UA_UInt32Range;
-
-typedef struct {
-    UA_Double min;
-    UA_Double max;
-} UA_DoubleRange;
-
-typedef struct {
-    UA_UInt16 nThreads; /* only if multithreading is enabled */
-    UA_Logger logger;
-
-    /* Server Description */
-    UA_BuildInfo buildInfo;
-    UA_ApplicationDescription applicationDescription;
-    UA_ByteString serverCertificate;
-
-    /* Networking */
-    size_t networkLayersSize;
-    UA_ServerNetworkLayer *networkLayers;
-
-    /* Login */
-    UA_Boolean enableAnonymousLogin;
-    UA_Boolean enableUsernamePasswordLogin;
-    size_t usernamePasswordLoginsSize;
-    UA_UsernamePasswordLogin* usernamePasswordLogins;
-
-    /* Limits for SecureChannels */
-    UA_UInt16 maxSecureChannels;
-    UA_UInt32 maxSecurityTokenLifetime; /* in ms */
-
-    /* Limits for Sessions */
-    UA_UInt16 maxSessions;
-    UA_Double maxSessionTimeout; /* in ms */
-
-    /* Limits for Subscriptions */
-    UA_DoubleRange publishingIntervalLimits;
-    UA_UInt32Range lifeTimeCountLimits;
-    UA_UInt32Range keepAliveCountLimits;
-    UA_UInt32 maxNotificationsPerPublish;
-    UA_UInt32 maxRetransmissionQueueSize; /* 0 -> unlimited size */
-
-    /* Limits for MonitoredItems */
-    UA_DoubleRange samplingIntervalLimits;
-    UA_UInt32Range queueSizeLimits; /* Negotiated with the client */
-} UA_ServerConfig;
-
-/* 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);
-
-/**
  * .. _server-lifecycle:
  * .. _server-lifecycle:
  *
  *
  * Server Lifecycle
  * Server Lifecycle
  * ---------------- */
  * ---------------- */
-UA_Server UA_EXPORT * UA_Server_new(const UA_ServerConfig config);
+
+UA_Server UA_EXPORT * UA_Server_new(const UA_ServerConfig *config);
 void UA_EXPORT UA_Server_delete(UA_Server *server);
 void UA_EXPORT UA_Server_delete(UA_Server *server);
 
 
 /* Runs the main loop of the server. In each iteration, this calls into the
 /* Runs the main loop of the server. In each iteration, this calls into the
- * networklayers to see if jobs have arrived and checks if repeated jobs need to
- * be triggered.
+ * networklayers to see if messages have arrived.
  *
  *
  * @param server The server object.
  * @param server The server object.
  * @param running The loop is run as long as *running is true.
  * @param running The loop is run as long as *running is true.
@@ -151,7 +45,8 @@ UA_Server_run(UA_Server *server, volatile UA_Boolean *running);
 
 
 /* The prologue part of UA_Server_run (no need to use if you call
 /* The prologue part of UA_Server_run (no need to use if you call
  * UA_Server_run) */
  * UA_Server_run) */
-UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server);
+UA_StatusCode UA_EXPORT
+UA_Server_run_startup(UA_Server *server);
 
 
 /* Executes a single iteration of the server's main loop.
 /* Executes a single iteration of the server's main loop.
  *
  *
@@ -160,40 +55,47 @@ UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server);
  *        Otherwise, the timouts for the networklayers are set to zero.
  *        Otherwise, the timouts for the networklayers are set to zero.
  *        The default max wait time is 50millisec.
  *        The default max wait time is 50millisec.
  * @return Returns how long we can wait until the next scheduled
  * @return Returns how long we can wait until the next scheduled
- *         job (in millisec) */
+ *         callback (in ms) */
 UA_UInt16 UA_EXPORT
 UA_UInt16 UA_EXPORT
 UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal);
 UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal);
 
 
 /* The epilogue part of UA_Server_run (no need to use if you call
 /* The epilogue part of UA_Server_run (no need to use if you call
  * UA_Server_run) */
  * UA_Server_run) */
-UA_StatusCode UA_EXPORT UA_Server_run_shutdown(UA_Server *server);
+UA_StatusCode UA_EXPORT
+UA_Server_run_shutdown(UA_Server *server);
 
 
 /**
 /**
- * Repeated jobs
- * ------------- */
-/* Add a job for cyclic repetition to the server.
+ * Repeated Callbacks
+ * ------------------ */
+typedef void (*UA_ServerCallback)(UA_Server *server, void *data);
+
+/* Add a callback for cyclic repetition to the server.
  *
  *
  * @param server The server object.
  * @param server The server object.
- * @param job The job that shall be added.
- * @param interval The job shall be repeatedly executed with the given interval
+ * @param callback The callback that shall be added.
+ * @param interval The callback shall be repeatedly executed with the given interval
  *        (in ms). The interval must be larger than 5ms. The first execution
  *        (in ms). The interval must be larger than 5ms. The first execution
  *        occurs at now() + interval at the latest.
  *        occurs at now() + interval at the latest.
- * @param jobId Set to the guid of the repeated job. This can be used to cancel
- *        the job later on. If the pointer is null, the guid is not set.
+ * @param callbackId Set to the identifier of the repeated callback . This can be used to cancel
+ *        the callback later on. If the pointer is null, the identifier is not set.
  * @return Upon success, UA_STATUSCODE_GOOD is returned.
  * @return Upon success, UA_STATUSCODE_GOOD is returned.
  *         An error code otherwise. */
  *         An error code otherwise. */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
-                         UA_UInt32 interval, UA_Guid *jobId);
+UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
+                              void *data, UA_UInt32 interval, UA_UInt64 *callbackId);
+
+UA_StatusCode UA_EXPORT
+UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
+                                         UA_UInt32 interval);
 
 
-/* Remove repeated job.
+/* Remove a repeated callback.
  *
  *
  * @param server The server object.
  * @param server The server object.
- * @param jobId The id of the job that shall be removed.
+ * @param callbackId The id of the callback that shall be removed.
  * @return Upon sucess, UA_STATUSCODE_GOOD is returned.
  * @return Upon sucess, UA_STATUSCODE_GOOD is returned.
  *         An error code otherwise. */
  *         An error code otherwise. */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId);
+UA_Server_removeRepeatedCallback(UA_Server *server, UA_UInt64 callbackId);
 
 
 /**
 /**
  * Reading and Writing Node Attributes
  * Reading and Writing Node Attributes
@@ -370,13 +272,14 @@ UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId,
  * - ContainsNoLoop
  * - ContainsNoLoop
  *
  *
  * The following attributes cannot be written from the server, as they are
  * The following attributes cannot be written from the server, as they are
- * specific to the different users:
+ * specific to the different users and set by the access control callback:
  *
  *
  * - UserWriteMask
  * - UserWriteMask
  * - UserAccessLevel
  * - UserAccessLevel
  * - UserExecutable
  * - UserExecutable
  *
  *
  * Historizing is currently unsupported */
  * Historizing is currently unsupported */
+
 /* Overwrite an attribute of a node. The specialized functions below provide a
 /* Overwrite an attribute of a node. The specialized functions below provide a
  * more concise syntax.
  * more concise syntax.
  *
  *
@@ -525,36 +428,205 @@ UA_StatusCode UA_EXPORT
 UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
 UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
                                UA_NodeIteratorCallback callback, void *handle);
                                UA_NodeIteratorCallback callback, void *handle);
 
 
+#ifdef UA_ENABLE_DISCOVERY
+
 /**
 /**
- * Method Call
- * ----------- */
-#ifdef UA_ENABLE_METHODCALLS
-UA_CallMethodResult UA_EXPORT
-UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
-#endif
+ * Discovery
+ * --------- */
+/* Register the given server instance at the discovery server.
+ * This should be called periodically.
+ * The semaphoreFilePath is optional. If the given file is deleted,
+ * the server will automatically be unregistered. This could be
+ * for example a pid file which is deleted if the server crashes.
+ *
+ * When the server shuts down you need to call unregister.
+ *
+ * @param server
+ * @param discoveryServerUrl if set to NULL, the default value
+ *        'opc.tcp://localhost:4840' will be used
+ * @param semaphoreFilePath optional parameter pointing to semaphore file. */
+UA_StatusCode UA_EXPORT
+UA_Server_register_discovery(UA_Server *server, const char* discoveryServerUrl,
+                             const char* semaphoreFilePath);
+
+/* Unregister the given server instance from the discovery server.
+ * This should only be called when the server is shutting down.
+ * @param server
+ * @param discoveryServerUrl if set to NULL, the default value
+ *        'opc.tcp://localhost:4840' will be used */
+UA_StatusCode UA_EXPORT
+UA_Server_unregister_discovery(UA_Server *server, const char* discoveryServerUrl);
+
+ /* Adds a periodic callback to register the server with the LDS (local discovery server)
+  * periodically. The interval between each register call is given as second parameter.
+  * It should be 10 minutes by default (= 10*60*1000).
+  *
+  * The delayFirstRegisterMs parameter indicates the delay for the first register call.
+  * If it is 0, the first register call will be after intervalMs milliseconds,
+  * otherwise the server's first register will be after delayFirstRegisterMs.
+  *
+  * When you manually unregister the server, you also need to cancel the
+  * periodic callback, otherwise it will be automatically be registered again.
+  *
+  * If you call this method multiple times for the same discoveryServerUrl, the older
+  * periodic callback will be removed.
+  *
+  * @param server
+  * @param discoveryServerUrl if set to NULL, the default value
+  *        'opc.tcp://localhost:4840' will be used
+  * @param intervalMs
+  * @param delayFirstRegisterMs
+  * @param periodicCallbackId */
+UA_StatusCode UA_EXPORT
+UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, const char* discoveryServerUrl,
+                                            UA_UInt32 intervalMs,
+                                            UA_UInt32 delayFirstRegisterMs,
+                                            UA_UInt64 *periodicCallbackId);
+
+/* Callback for RegisterServer. Data is passed from the register call */
+typedef void (*UA_Server_registerServerCallback)(const UA_RegisteredServer *registeredServer,
+                                                 void* data);
+
+/* Set the callback which is called if another server registeres or unregisters
+ * with this instance. If called multiple times, previous data will be
+ * overwritten.
+ *
+ * @param server
+ * @param cb the callback
+ * @param data data passed to the callback
+ * @return UA_STATUSCODE_SUCCESS on success */
+void UA_EXPORT
+UA_Server_setRegisterServerCallback(UA_Server *server, UA_Server_registerServerCallback cb,
+                                    void* data);
+
+#ifdef UA_ENABLE_DISCOVERY_MULTICAST
+
+/* Callback for server detected through mDNS. Data is passed from the register
+ * call
+ *
+ * @param isServerAnnounce indicates if the server has just been detected. If
+ *        set to false, this means the server is shutting down.
+ * @param isTxtReceived indicates if we already received the corresponding TXT
+ *        record with the path and caps data */
+typedef void (*UA_Server_serverOnNetworkCallback)(const UA_ServerOnNetwork *serverOnNetwork,
+                                                  UA_Boolean isServerAnnounce,
+                                                  UA_Boolean isTxtReceived, void* data);
+
+/* Set the callback which is called if another server is found through mDNS or
+ * deleted. It will be called for any mDNS message from the remote server, thus
+ * it may be called multiple times for the same instance. Also the SRV and TXT
+ * records may arrive later, therefore for the first call the server
+ * capabilities may not be set yet. If called multiple times, previous data will
+ * be overwritten.
+ *
+ * @param server
+ * @param cb the callback
+ * @param data data passed to the callback
+ * @return UA_STATUSCODE_SUCCESS on success */
+void UA_EXPORT
+UA_Server_setServerOnNetworkCallback(UA_Server *server,
+                                     UA_Server_serverOnNetworkCallback cb,
+                                     void* data);
+
+#endif /* UA_ENABLE_DISCOVERY_MULTICAST */
+
+#endif /* UA_ENABLE_DISCOVERY */
 
 
 /**
 /**
- * Node Management
- * ---------------
- *
- * Callback Mechanisms
- * ^^^^^^^^^^^^^^^^^^^
- * There are four mechanisms for callbacks from the node-based information model
- * into userspace:
- *
- * - Datasources for variable nodes, where the variable content is managed
- *   externally
- * - Value-callbacks for variable nodes, where userspace is notified when a
- *   read/write occurs
- * - Object lifecycle management, where a user-defined constructor and
- *   destructor is added to an object type
- * - Method callbacks, where a user-defined method is exposed in the information
- *   model
+ * Information Model Callbacks
+ * ---------------------------
+ *
+ * There are three places where a callback from an information model to
+ * user-defined code can happen.
+ *
+ * - Custom node constructors and destructors
+ * - Linking VariableNodes with an external data source
+ * - MethodNode callbacks
+ *
+ * .. _node-lifecycle:
+ *
+ * Node Lifecycle: Constructors, Destructors and Node Contexts
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * To finalize the instantiation of a node, a (user-defined) constructor
+ * callback is executed. There can be both a global constructor for all nodes
+ * and node-type constructor specific to the TypeDefinition of the new node
+ * (attached to an ObjectTypeNode or VariableTypeNode).
+ *
+ * In the hierarchy of ObjectTypes and VariableTypes, only the constructor of
+ * the (lowest) type defined for the new node is executed. Note that every
+ * Object and Variable can have only one ``isTypeOf`` reference. But type-nodes
+ * can technically have several ``hasSubType`` references to implement multiple
+ * inheritance. Issues of (multiple) inheritance in the constructor need to be
+ * solved by the user.
+ *
+ * When a node is destroyed, the node-type destructor is called before the
+ * global destructor. So the overall node lifecycle is as follows:
+ *
+ * 1. Global Constructor (set in the server config)
+ * 2. Node-Type Constructor (for VariableType or ObjectTypes)
+ * 3. (Usage-period of the Node)
+ * 4. Node-Type Destructor
+ * 5. Global Destructor
  *
  *
+ * The constructor and destructor callbacks can be set to ``NULL`` and are not
+ * used in that case. If the node-type constructor fails, the global destructor
+ * will be called before removing the node. The destructors are assumed to never
+ * fail.
+ *
+ * Every node carries a user-context and a constructor-context pointer. The
+ * user-context is used to attach custom data to a node. But the (user-defined)
+ * constructors and destructors may replace the user-context pointer if they
+ * wish to do so. The initial value for the constructor-context is ``NULL``.
+ * When the ``AddNodes`` service is used over the network, the user-context
+ * pointer of the new node is also initially set to ``NULL``. */
+
+/* To be set in the server config. */
+typedef struct {
+    /* Can be NULL. May replace the nodeContext */
+    UA_StatusCode (*constructor)(UA_Server *server,
+                                 const UA_NodeId *sessionId, void *sessionContext,
+                                 const UA_NodeId *nodeId, void **nodeContext);
+
+    /* Can be NULL. The context cannot be replaced since the node is destroyed
+     * immediately afterwards anyway. */
+    void (*destructor)(UA_Server *server,
+                       const UA_NodeId *sessionId, void *sessionContext,
+                       const UA_NodeId *nodeId, void *nodeContext);
+} UA_GlobalNodeLifecycle;
+
+typedef struct {
+    /* Can be NULL. May replace the nodeContext */
+    UA_StatusCode (*constructor)(UA_Server *server,
+                                 const UA_NodeId *sessionId, void *sessionContext,
+                                 const UA_NodeId *typeNodeId, void *typeNodeContext,
+                                 const UA_NodeId *nodeId, void **nodeContext);
+
+    /* Can be NULL. May replace the nodeContext. */
+    void (*destructor)(UA_Server *server,
+                       const UA_NodeId *sessionId, void *sessionContext,
+                       const UA_NodeId *typeNodeId, void *typeNodeContext,
+                       const UA_NodeId *nodeId, void **nodeContext);
+} UA_NodeTypeLifecycle;
+
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
+                               UA_NodeTypeLifecycle lifecycle);
+
+UA_StatusCode UA_EXPORT
+UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void **nodeContext);
+
+/* Careful! The user has to ensure that the destructor callbacks still work. */
+UA_StatusCode UA_EXPORT
+UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void *nodeContext);
+
+/**
  * .. _datasource:
  * .. _datasource:
  *
  *
  * Data Source Callback
  * Data Source Callback
- * ~~~~~~~~~~~~~~~~~~~~
+ * ^^^^^^^^^^^^^^^^^^^^
  *
  *
  * The server has a unique way of dealing with the content of variables. Instead
  * The server has a unique way of dealing with the content of variables. Instead
  * of storing a variant attached to the variable node, the node can point to a
  * of storing a variant attached to the variable node, the node can point to a
@@ -565,8 +637,6 @@ UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
  * It is expected that the read callback is implemented. The write callback can
  * It is expected that the read callback is implemented. The write callback can
  * be set to a null-pointer. */
  * be set to a null-pointer. */
 typedef struct {
 typedef struct {
-    void *handle; /* A custom pointer to reuse the same datasource functions for
-                     multiple sources */
     /* Copies the data from the source into the provided value.
     /* Copies the data from the source into the provided value.
      *
      *
      * @param handle An optional pointer to user-defined data for the
      * @param handle An optional pointer to user-defined data for the
@@ -584,8 +654,9 @@ typedef struct {
      * @return Returns a status code for logging. Error codes intended for the
      * @return Returns a status code for logging. Error codes intended for the
      *         original caller are set in the value. If an error is returned,
      *         original caller are set in the value. If an error is returned,
      *         then no releasing of the value is done. */
      *         then no releasing of the value is done. */
-    UA_StatusCode (*read)(void *handle, const UA_NodeId nodeid,
-                          UA_Boolean includeSourceTimeStamp,
+    UA_StatusCode (*read)(UA_Server *server, const UA_NodeId *sessionId,
+                          void *sessionContext, const UA_NodeId *nodeId,
+                          void *nodeContext, UA_Boolean includeSourceTimeStamp,
                           const UA_NumericRange *range, UA_DataValue *value);
                           const UA_NumericRange *range, UA_DataValue *value);
 
 
     /* Write into a data source. The write member of UA_DataSource can be empty
     /* Write into a data source. The write member of UA_DataSource can be empty
@@ -597,10 +668,11 @@ typedef struct {
      * @param data The data to be written into the data source
      * @param data The data to be written into the data source
      * @param range An optional data range. If the data source is scalar or does
      * @param range An optional data range. If the data source is scalar or does
      *        not support writing of ranges, then an error code is returned.
      *        not support writing of ranges, then an error code is returned.
-     * @return Returns a status code that is returned to the user
-     */
-    UA_StatusCode (*write)(void *handle, const UA_NodeId nodeid,
-                           const UA_Variant *data, const UA_NumericRange *range);
+     * @return Returns a status code that is returned to the user */
+    UA_StatusCode (*write)(UA_Server *server, const UA_NodeId *sessionId,
+                           void *sessionContext, const UA_NodeId *nodeId,
+                           void *nodeContext, const UA_NumericRange *range,
+                           const UA_DataValue *value);
 } UA_DataSource;
 } UA_DataSource;
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
@@ -611,13 +683,10 @@ UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  * .. _value-callback:
  * .. _value-callback:
  *
  *
  * Value Callback
  * Value Callback
- * ~~~~~~~~~~~~~~
+ * ^^^^^^^^^^^^^^
  * Value Callbacks can be attached to variable and variable type nodes. If
  * Value Callbacks can be attached to variable and variable type nodes. If
- * not-null, they are called before reading and after writing respectively. */
+ * not ``NULL``, they are called before reading and after writing respectively. */
 typedef struct {
 typedef struct {
-    /* Pointer to user-provided data for the callback */
-    void *handle;
-
     /* Called before the value attribute is read. It is possible to write into the
     /* Called before the value attribute is read. It is possible to write into the
      * value attribute during onRead (using the write service). The node is
      * value attribute during onRead (using the write service). The node is
      * re-opened afterwards so that changes are considered in the following read
      * re-opened afterwards so that changes are considered in the following read
@@ -628,102 +697,116 @@ typedef struct {
      * @param data Points to the current node value.
      * @param data Points to the current node value.
      * @param range Points to the numeric range the client wants to read from
      * @param range Points to the numeric range the client wants to read from
      *        (or NULL). */
      *        (or NULL). */
-    void (*onRead)(void *handle, const UA_NodeId nodeid,
-                   const UA_Variant *data, const UA_NumericRange *range);
+    void (*onRead)(UA_Server *server, const UA_NodeId *sessionId,
+                   void *sessionContext, const UA_NodeId *nodeid,
+                   void *nodeContext, const UA_NumericRange *range,
+                   const UA_DataValue *value);
 
 
     /* Called after writing the value attribute. The node is re-opened after
     /* Called after writing the value attribute. The node is re-opened after
      * writing so that the new value is visible in the callback.
      * writing so that the new value is visible in the callback.
      *
      *
-     * @param handle Points to user-provided data for the callback.
+     * @param server The server executing the callback
+     * @sessionId The identifier of the session
+     * @sessionContext Additional data attached to the session
+     *                 in the access control layer
      * @param nodeid The identifier of the node.
      * @param nodeid The identifier of the node.
-     * @param data Points to the current node value (after writing).
+     * @param nodeUserContext Additional data attached to the node by
+     *        the user.
+     * @param nodeConstructorContext Additional data attached to the node
+     *        by the type constructor(s).
      * @param range Points to the numeric range the client wants to write to (or
      * @param range Points to the numeric range the client wants to write to (or
      *        NULL). */
      *        NULL). */
-    void (*onWrite)(void *handle, const UA_NodeId nodeid,
-                    const UA_Variant *data, const UA_NumericRange *range);
+    void (*onWrite)(UA_Server *server, const UA_NodeId *sessionId,
+                    void *sessionContext, const UA_NodeId *nodeId,
+                    void *nodeContext, const UA_NumericRange *range,
+                    const UA_DataValue *data);
 } UA_ValueCallback;
 } UA_ValueCallback;
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
+UA_Server_setVariableNode_valueCallback(UA_Server *server,
+                                        const UA_NodeId nodeId,
                                         const UA_ValueCallback callback);
                                         const UA_ValueCallback callback);
 
 
-/**
- * .. _object-lifecycle:
- *
- * Object Lifecycle Management Callbacks
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * Lifecycle management adds constructor and destructor callbacks to
- * object types. */
-typedef struct {
-    /* Returns the instance handle that is then attached to the node */
-    void * (*constructor)(const UA_NodeId instance);
-    void (*destructor)(const UA_NodeId instance, void *instanceHandle);
-} UA_ObjectLifecycleManagement;
-
-UA_StatusCode UA_EXPORT
-UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server,
-                                                UA_NodeId nodeId,
-                                                UA_ObjectLifecycleManagement olm);
-
 /**
 /**
  * Method Callbacks
  * Method Callbacks
- * ~~~~~~~~~~~~~~~~ */
+ * ^^^^^^^^^^^^^^^^
+ * Method callbacks are set to `NULL` (not executable) when a method node is added
+ * over the network. In theory, it is possible to add a callback via
+ * ``UA_Server_setMethodNode_callback`` within the global constructor when adding
+ * methods over the network is really wanted. */
+
 typedef UA_StatusCode
 typedef UA_StatusCode
-(*UA_MethodCallback)(void *methodHandle, const UA_NodeId objectId,
-                     size_t inputSize, const UA_Variant *input,
-                     size_t outputSize, UA_Variant *output);
+(*UA_MethodCallback)(UA_Server *server, const UA_NodeId *sessionId,
+                     void *sessionContext, const UA_NodeId *methodId,
+                     void *methodContext, const UA_NodeId *objectId,
+                     void *objectContext, size_t inputSize,
+                     const UA_Variant *input, size_t outputSize,
+                     UA_Variant *output);
 
 
 #ifdef UA_ENABLE_METHODCALLS
 #ifdef UA_ENABLE_METHODCALLS
+
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_setMethodNode_callback(UA_Server *server, const UA_NodeId methodNodeId,
-                                 UA_MethodCallback method, void *handle);
+UA_Server_setMethodNode_callback(UA_Server *server,
+                                 const UA_NodeId methodNodeId,
+                                 UA_MethodCallback methodCallback);
+UA_CallMethodResult UA_EXPORT
+UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
+
 #endif
 #endif
 
 
 /**
 /**
  * .. _addnodes:
  * .. _addnodes:
  *
  *
  * Node Addition and Deletion
  * Node Addition and Deletion
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- *
+ * --------------------------
  * When creating dynamic node instances at runtime, chances are that you will
  * When creating dynamic node instances at runtime, chances are that you will
  * not care about the specific NodeId of the new node, as long as you can
  * not care about the specific NodeId of the new node, as long as you can
  * reference it later. When passing numeric NodeIds with a numeric identifier 0,
  * reference it later. When passing numeric NodeIds with a numeric identifier 0,
  * the stack evaluates this as "select a random unassigned numeric NodeId in
  * the stack evaluates this as "select a random unassigned numeric NodeId in
  * that namespace". To find out which NodeId was actually assigned to the new
  * that namespace". To find out which NodeId was actually assigned to the new
  * node, you may pass a pointer `outNewNodeId`, which will (after a successfull
  * node, you may pass a pointer `outNewNodeId`, which will (after a successfull
- * node insertion) contain the nodeId of the new node. You may also pass NULL
- * pointer if this result is not relevant. The namespace index for nodes you
- * create should never be 0, as that index is reserved for OPC UA's
- * self-description (namespace * 0).
+ * node insertion) contain the nodeId of the new node. You may also pass a
+ * ``NULL`` pointer if this result is not needed.
+ *
+ * See the Section :ref:`node-lifecycle` on constructors and on attaching
+ * user-defined data to nodes.
  *
  *
  * The methods for node addition and deletion take mostly const arguments that
  * The methods for node addition and deletion take mostly const arguments that
  * are not modified. When creating a node, a deep copy of the node identifier,
  * are not modified. When creating a node, a deep copy of the node identifier,
  * node attributes, etc. is created. Therefore, it is possible to call for
  * node attributes, etc. is created. Therefore, it is possible to call for
- * example `UA_Server_addVariablenode` with a value attribute (a :ref:`variant`)
- * pointing to a memory location on the stack. If you need changes to a variable
- * value to manifest at a specific memory location, please use a
- * :ref:`datasource` or a :ref:`value-callback`. */
-/* The instantiation callback is used to track the addition of new nodes. It is
- * also called for all sub-nodes contained in an object or variable type node
- * that is instantiated. */
-typedef struct {
-  UA_StatusCode (*method)(const UA_NodeId objectId,
-                          const UA_NodeId typeDefinitionId, void *handle);
-  void *handle;
-} UA_InstantiationCallback;
+ * example ``UA_Server_addVariablenode`` with a value attribute (a
+ * :ref:`variant`) pointing to a memory location on the stack. If you need
+ * changes to a variable value to manifest at a specific memory location, please
+ * use a :ref:`datasource` or a :ref:`value-callback`. */
+
+/* Protect against redundant definitions for server/client */
+#ifndef UA_DEFAULT_ATTRIBUTES_DEFINED
+#define UA_DEFAULT_ATTRIBUTES_DEFINED
+/* The default for variables is "BaseDataType" for the datatype, -2 for the
+ * valuerank and a read-accesslevel. */
+UA_EXPORT extern const UA_VariableAttributes UA_VariableAttributes_default;
+UA_EXPORT extern const UA_VariableTypeAttributes UA_VariableTypeAttributes_default;
+/* Methods are executable by default */
+UA_EXPORT extern const UA_MethodAttributes UA_MethodAttributes_default;
+/* The remaining attribute definitions are currently all zeroed out */
+UA_EXPORT extern const UA_ObjectAttributes UA_ObjectAttributes_default;
+UA_EXPORT extern const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default;
+UA_EXPORT extern const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default;
+UA_EXPORT extern const UA_DataTypeAttributes UA_DataTypeAttributes_default;
+UA_EXPORT extern const UA_ViewAttributes UA_ViewAttributes_default;
+#endif
 
 
 /* Don't use this function. There are typed versions as inline functions. */
 /* Don't use this function. There are typed versions as inline functions. */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
 __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
-                    const UA_NodeId requestedNewNodeId,
-                    const UA_NodeId parentNodeId,
-                    const UA_NodeId referenceTypeId,
+                    const UA_NodeId *requestedNewNodeId,
+                    const UA_NodeId *parentNodeId,
+                    const UA_NodeId *referenceTypeId,
                     const UA_QualifiedName browseName,
                     const UA_QualifiedName browseName,
-                    const UA_NodeId typeDefinition,
+                    const UA_NodeId *typeDefinition,
                     const UA_NodeAttributes *attr,
                     const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType,
                     const UA_DataType *attributeType,
-                    UA_InstantiationCallback *instantiationCallback,
-                    UA_NodeId *outNewNodeId);
+                    void *nodeContext, UA_NodeId *outNewNodeId);
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
@@ -732,13 +815,12 @@ UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_QualifiedName browseName,
                           const UA_QualifiedName browseName,
                           const UA_NodeId typeDefinition,
                           const UA_NodeId typeDefinition,
                           const UA_VariableAttributes attr,
                           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,
+                          void *nodeContext, 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],
                                &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
@@ -749,14 +831,13 @@ UA_Server_addVariableTypeNode(UA_Server *server,
                               const UA_QualifiedName browseName,
                               const UA_QualifiedName browseName,
                               const UA_NodeId typeDefinition,
                               const UA_NodeId typeDefinition,
                               const UA_VariableTypeAttributes attr,
                               const UA_VariableTypeAttributes attr,
-                              UA_InstantiationCallback *instantiationCallback,
-                              UA_NodeId *outNewNodeId) {
+                              void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE,
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE,
-                               requestedNewNodeId, parentNodeId, referenceTypeId,
-                               browseName, typeDefinition,
+                               &requestedNewNodeId, &parentNodeId, &referenceTypeId,
+                               browseName, &typeDefinition,
                                (const UA_NodeAttributes*)&attr,
                                (const UA_NodeAttributes*)&attr,
                                &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
                                &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
@@ -766,13 +847,12 @@ UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_QualifiedName browseName,
                         const UA_QualifiedName browseName,
                         const UA_NodeId typeDefinition,
                         const UA_NodeId typeDefinition,
                         const UA_ObjectAttributes attr,
                         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,
+                        void *nodeContext, 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],
                                &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
@@ -781,13 +861,12 @@ UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeI
                             const UA_NodeId referenceTypeId,
                             const UA_NodeId referenceTypeId,
                             const UA_QualifiedName browseName,
                             const UA_QualifiedName browseName,
                             const UA_ObjectTypeAttributes attr,
                             const UA_ObjectTypeAttributes attr,
-                            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,
+                            void *nodeContext, 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],
                                &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
@@ -796,13 +875,12 @@ UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                       const UA_NodeId referenceTypeId,
                       const UA_NodeId referenceTypeId,
                       const UA_QualifiedName browseName,
                       const UA_QualifiedName browseName,
                       const UA_ViewAttributes attr,
                       const UA_ViewAttributes attr,
-                      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,
+                      void *nodeContext, 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],
                                &UA_TYPES[UA_TYPES_VIEWATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
@@ -812,14 +890,13 @@ UA_Server_addReferenceTypeNode(UA_Server *server,
                                const UA_NodeId referenceTypeId,
                                const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName,
                                const UA_QualifiedName browseName,
                                const UA_ReferenceTypeAttributes attr,
                                const UA_ReferenceTypeAttributes attr,
-                               UA_InstantiationCallback *instantiationCallback,
-                               UA_NodeId *outNewNodeId) {
+                               void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE,
     return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE,
-                               requestedNewNodeId, parentNodeId, referenceTypeId,
-                               browseName, UA_NODEID_NULL,
+                               &requestedNewNodeId, &parentNodeId, &referenceTypeId,
+                               browseName, &UA_NODEID_NULL,
                                (const UA_NodeAttributes*)&attr,
                                (const UA_NodeAttributes*)&attr,
                                &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
                                &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
@@ -829,13 +906,12 @@ UA_Server_addDataTypeNode(UA_Server *server,
                           const UA_NodeId referenceTypeId,
                           const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName,
                           const UA_QualifiedName browseName,
                           const UA_DataTypeAttributes attr,
                           const UA_DataTypeAttributes attr,
-                          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,
+                          void *nodeContext, 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],
                                &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 }
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
@@ -847,23 +923,53 @@ UA_Server_addDataSourceVariableNode(UA_Server *server,
                                     const UA_NodeId typeDefinition,
                                     const UA_NodeId typeDefinition,
                                     const UA_VariableAttributes attr,
                                     const UA_VariableAttributes attr,
                                     const UA_DataSource dataSource,
                                     const UA_DataSource dataSource,
-                                    UA_NodeId *outNewNodeId);
+                                    void *nodeContext, UA_NodeId *outNewNodeId);
 
 
-#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId,
                         const UA_NodeId parentNodeId,
                         const UA_NodeId referenceTypeId,
                         const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName,
                         const UA_QualifiedName browseName,
-                        const UA_MethodAttributes attr,
-                        UA_MethodCallback method, void *handle,
-                        size_t inputArgumentsSize,
-                        const UA_Argument* inputArguments, 
-                        size_t outputArgumentsSize,
-                        const UA_Argument* outputArguments,
-                        UA_NodeId *outNewNodeId);
-#endif
+                        const UA_MethodAttributes attr, UA_MethodCallback method,
+                        size_t inputArgumentsSize, const UA_Argument* inputArguments, 
+                        size_t outputArgumentsSize, const UA_Argument* outputArguments,
+                        void *nodeContext, UA_NodeId *outNewNodeId);
+
+
+/**
+ * The method pair UA_Server_addNode_begin and _finish splits the AddNodes
+ * service in two parts. This is useful if the node shall be modified before
+ * finish the instantiation. For example to add children with specific NodeIds.
+ * Otherwise, mandatory children (e.g. of an ObjectType) are added with
+ * pseudo-random unique NodeIds. Existing children are detected during the
+ * _finish part via their matching BrowseName.
+ *
+ * The _begin method prepares the node and adds it to the nodestore. It may copy
+ * some unassigned attributes from the TypeDefinition node internally. The
+ * _finish method adds the references to the parent (and the TypeDefinition if
+ * applicable), copies mandatory children, performs type-checking of variables
+ * and calls the node constructor(s) at the end. The _finish method may remove
+ * the node if it encounters an error. */
+
+/* The ``attr`` argument must have a type according to the NodeClass.
+ * ``VariableAttributes`` for variables, ``ObjectAttributes`` for objects, and
+ * so on. Missing attributes are taken from the TypeDefinition node if
+ * applicable. */
+UA_StatusCode UA_EXPORT
+UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
+                        const UA_NodeId requestedNewNodeId,
+                        const UA_QualifiedName browseName,
+                        const UA_NodeId typeDefinition,
+                        const void *attr, const UA_DataType *attributeType,
+                        void *nodeContext, UA_NodeId *outNewNodeId);
 
 
+UA_StatusCode UA_EXPORT
+UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
+                         const UA_NodeId parentNodeId,
+                         const UA_NodeId referenceTypeId,
+                         const UA_NodeId typeDefinitionId);
+
+/* Deletes a node and optionally all references leading to the node. */
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
 UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
                      UA_Boolean deleteReferences);
                      UA_Boolean deleteReferences);
@@ -882,6 +988,54 @@ UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                           const UA_ExpandedNodeId targetNodeId,
                           const UA_ExpandedNodeId targetNodeId,
                           UA_Boolean deleteBidirectional);
                           UA_Boolean deleteBidirectional);
 
 
+/**
+ * Utility Functions
+ * ----------------- */
+/* 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);
+
+/**
+ * Deprecated Server API
+ * ---------------------
+ * This file contains outdated API definitions that are kept for backwards
+ * compatibility. Please switch to the new API, as the following definitions
+ * will be removed eventually.
+ *
+ * UA_Job API
+ * ^^^^^^^^^^
+ * UA_Job was replaced since it unneccessarily exposed server internals to the
+ * end-user. Please use plain UA_ServerCallbacks instead. The following UA_Job
+ * definition contains just the fraction of the original struct that was useful
+ * to end-users. */
+
+typedef enum {
+    UA_JOBTYPE_METHODCALL
+} UA_JobType;
+
+typedef struct {
+    UA_JobType type;
+    union {
+        struct {
+            void *data;
+            UA_ServerCallback method;
+        } methodCall;
+    } job;
+} UA_Job;
+
+UA_DEPRECATED static UA_INLINE UA_StatusCode
+UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
+                         UA_UInt32 interval, UA_Guid *jobId) {
+    return UA_Server_addRepeatedCallback(server, job.job.methodCall.method,
+                                         job.job.methodCall.data, interval,
+                                         (UA_UInt64*)(uintptr_t)jobId);
+}
+
+UA_DEPRECATED static UA_INLINE UA_StatusCode
+UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId) {
+    return UA_Server_removeRepeatedCallback(server,
+                                            *(UA_UInt64*)(uintptr_t)&jobId);
+}
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }
 #endif
 #endif

+ 104 - 0
include/ua_server_config.h

@@ -0,0 +1,104 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef UA_SERVER_CONFIG_H_
+#define UA_SERVER_CONFIG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_server.h"
+#include "ua_plugin_log.h"
+#include "ua_plugin_network.h"
+#include "ua_plugin_access_control.h"
+#include "ua_plugin_securitypolicy.h"
+#include "ua_plugin_nodestore.h"
+
+/**
+ * Server Configuration
+ * ====================
+ * The configuration structure is passed to the server during initialization. */
+
+typedef struct {
+    UA_UInt32 min;
+    UA_UInt32 max;
+} UA_UInt32Range;
+
+typedef struct {
+    UA_Duration min;
+    UA_Duration max;
+} UA_DurationRange;
+
+struct UA_ServerConfig {
+    UA_UInt16 nThreads; /* only if multithreading is enabled */
+    UA_Logger logger;
+
+    /* Server Description */
+    UA_BuildInfo buildInfo;
+    UA_ApplicationDescription applicationDescription;
+    UA_ByteString serverCertificate;
+#ifdef UA_ENABLE_DISCOVERY
+    UA_String mdnsServerName;
+    size_t serverCapabilitiesSize;
+    UA_String *serverCapabilities;
+#endif
+
+    /* Custom DataTypes */
+    size_t customDataTypesSize;
+    UA_DataType *customDataTypes;
+
+    /* Nodestore */
+    UA_Nodestore nodestore;
+
+    /* Networking */
+    size_t networkLayersSize;
+    UA_ServerNetworkLayer *networkLayers;
+
+    /* Available endpoints */
+    size_t endpointsSize;
+    UA_Endpoint *endpoints;
+
+    /* Global Node Lifecycle */
+    UA_GlobalNodeLifecycle nodeLifecycle;
+
+    /* Access Control */
+    UA_AccessControl accessControl;
+
+    /* Limits for SecureChannels */
+    UA_UInt16 maxSecureChannels;
+    UA_UInt32 maxSecurityTokenLifetime; /* in ms */
+
+    /* Limits for Sessions */
+    UA_UInt16 maxSessions;
+    UA_Double maxSessionTimeout; /* in ms */
+
+    /* Limits for Subscriptions */
+    UA_DurationRange publishingIntervalLimits;
+    UA_UInt32Range lifeTimeCountLimits;
+    UA_UInt32Range keepAliveCountLimits;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_UInt32 maxRetransmissionQueueSize; /* 0 -> unlimited size */
+
+    /* Limits for MonitoredItems */
+    UA_DurationRange samplingIntervalLimits;
+    UA_UInt32Range queueSizeLimits; /* Negotiated with the client */
+
+    /* Discovery */
+#ifdef UA_ENABLE_DISCOVERY
+    /* Timeout in seconds when to automatically remove a registered server from
+     * the list, if it doesn't re-register within the given time frame. A value
+     * of 0 disables automatic removal. Default is 60 Minutes (60*60). Must be
+     * bigger than 10 seconds, because cleanup is only triggered approximately
+     * ervery 10 seconds. The server will still be removed depending on the
+     * state of the semaphore file. */
+    UA_UInt32 discoveryCleanupTimeout;
+#endif
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_SERVER_CONFIG_H_ */

+ 57 - 33
include/ua_types.h

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef UA_TYPES_H_
 #ifndef UA_TYPES_H_
 #define UA_TYPES_H_
 #define UA_TYPES_H_
@@ -12,6 +12,8 @@ extern "C" {
 #include "ua_config.h"
 #include "ua_config.h"
 #include "ua_constants.h"
 #include "ua_constants.h"
 
 
+#define UA_BUILTIN_TYPES_COUNT 25U
+
 /**
 /**
  * .. _types:
  * .. _types:
  *
  *
@@ -20,7 +22,7 @@ extern "C" {
  *
  *
  * The OPC UA protocol defines 25 builtin data types and three ways of combining
  * The OPC UA protocol defines 25 builtin data types and three ways of combining
  * them into higher-order types: arrays, structures and unions. In open62541,
  * them into higher-order types: arrays, structures and unions. In open62541,
- * the builtin data types are defined manually. All other data types are
+ * only the builtin data types are defined manually. All other data types are
  * generated from standard XML definitions. Their exact definitions can be
  * generated from standard XML definitions. Their exact definitions can be
  * looked up at https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml.
  * looked up at https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml.
  *
  *
@@ -29,11 +31,8 @@ extern "C" {
  * implementation details.
  * implementation details.
  *
  *
  * Builtin Types
  * Builtin Types
- * ------------- */
-
-#define UA_BUILTIN_TYPES_COUNT 25U
-
-/**
+ * -------------
+ *
  * Boolean
  * Boolean
  * ^^^^^^^
  * ^^^^^^^
  * A two-state logical value (true or false). */
  * A two-state logical value (true or false). */
@@ -128,26 +127,13 @@ typedef double UA_Double;
  * specific code. */
  * specific code. */
 typedef uint32_t UA_StatusCode;
 typedef uint32_t UA_StatusCode;
 
 
-typedef struct {
-    UA_StatusCode code;      /* The numeric value of the StatusCode */
-    const char* name;        /* The symbolic name */
-    const char* explanation; /* Short message explaining the StatusCode */
-} UA_StatusCodeDescription;
-
-/* Returns the description of the StatusCode. Never returns NULL, but a generic
- * description for invalid StatusCodes instead. */
-UA_EXPORT const UA_StatusCodeDescription *
-UA_StatusCode_description(UA_StatusCode code);
-
-static UA_INLINE const char *
-UA_StatusCode_name(UA_StatusCode code) {
-    return UA_StatusCode_description(code)->name;
-}
-
-static UA_INLINE const char *
-UA_StatusCode_explanation(UA_StatusCode code) {
-    return UA_StatusCode_description(code)->explanation;
-}
+/* Returns the human-readable name of the StatusCode. If no matching StatusCode
+ * is found, a default string for "Unknown" is returned. This feature might be
+ * disabled to create a smaller binary with the
+ * UA_ENABLE_STATUSCODE_DESCRIPTIONS build-flag. Then the function returns an
+ * empty string for every StatusCode. */
+UA_EXPORT const char *
+UA_StatusCode_name(UA_StatusCode code);
 
 
 /**
 /**
  * String
  * String
@@ -166,7 +152,7 @@ UA_Boolean UA_EXPORT UA_String_equal(const UA_String *s1, const UA_String *s2);
 UA_EXPORT extern const UA_String UA_STRING_NULL;
 UA_EXPORT extern const UA_String UA_STRING_NULL;
 
 
 /**
 /**
- * ``UA_STRING`` returns a string pointing to the preallocated char-array.
+ * ``UA_STRING`` returns a string pointing to the original char-array.
  * ``UA_STRING_ALLOC`` is shorthand for ``UA_String_fromChars`` and makes a copy
  * ``UA_STRING_ALLOC`` is shorthand for ``UA_String_fromChars`` and makes a copy
  * of the char-array. */
  * of the char-array. */
 static UA_INLINE UA_String
 static UA_INLINE UA_String
@@ -191,6 +177,9 @@ typedef int64_t UA_DateTime;
 #define UA_USEC_TO_DATETIME 10LL
 #define UA_USEC_TO_DATETIME 10LL
 #define UA_MSEC_TO_DATETIME (UA_USEC_TO_DATETIME * 1000LL)
 #define UA_MSEC_TO_DATETIME (UA_USEC_TO_DATETIME * 1000LL)
 #define UA_SEC_TO_DATETIME (UA_MSEC_TO_DATETIME * 1000LL)
 #define UA_SEC_TO_DATETIME (UA_MSEC_TO_DATETIME * 1000LL)
+#define UA_DATETIME_TO_USEC (1/10.0)
+#define UA_DATETIME_TO_MSEC (UA_DATETIME_TO_USEC / 1000.0)
+#define UA_DATETIME_TO_SEC (UA_DATETIME_TO_MSEC / 1000.0)
 
 
 /* Datetime of 1 Jan 1970 00:00 UTC */
 /* Datetime of 1 Jan 1970 00:00 UTC */
 #define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_SEC_TO_DATETIME)
 #define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_SEC_TO_DATETIME)
@@ -359,6 +348,8 @@ typedef struct {
     UA_UInt32 serverIndex;
     UA_UInt32 serverIndex;
 } UA_ExpandedNodeId;
 } UA_ExpandedNodeId;
 
 
+UA_EXPORT extern const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL;
+
 /** The following functions are shorthand for creating ExpandedNodeIds. */
 /** The following functions are shorthand for creating ExpandedNodeIds. */
 static UA_INLINE UA_ExpandedNodeId
 static UA_INLINE UA_ExpandedNodeId
 UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier) {
 UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier) {
@@ -509,7 +500,7 @@ typedef struct UA_DataType UA_DataType;
 typedef enum {
 typedef enum {
     UA_VARIANT_DATA,          /* The data has the same lifecycle as the
     UA_VARIANT_DATA,          /* The data has the same lifecycle as the
                                  variant */
                                  variant */
-    UA_VARIANT_DATA_NODELETE, /* The data is "borrowed" by the variant and
+    UA_VARIANT_DATA_NODELETE /* The data is "borrowed" by the variant and
                                  shall not be deleted at the end of the
                                  shall not be deleted at the end of the
                                  variant's lifecycle. */
                                  variant's lifecycle. */
 } UA_VariantStorageType;
 } UA_VariantStorageType;
@@ -743,8 +734,7 @@ typedef struct UA_DiagnosticInfo {
  *   memory for the data type itself.
  *   memory for the data type itself.
  *
  *
  * Specializations, such as ``UA_Int32_new()`` are derived from the generic
  * Specializations, such as ``UA_Int32_new()`` are derived from the generic
- * type operations as static inline functions.
- */
+ * type operations as static inline functions. */
 
 
 typedef struct {
 typedef struct {
 #ifdef UA_ENABLE_TYPENAMES
 #ifdef UA_ENABLE_TYPENAMES
@@ -775,8 +765,8 @@ struct UA_DataType {
     UA_Byte    membersSize;      /* How many members does the type have? */
     UA_Byte    membersSize;      /* How many members does the type have? */
     UA_Boolean builtin      : 1; /* The type is "builtin" and has dedicated de-
     UA_Boolean builtin      : 1; /* The type is "builtin" and has dedicated de-
                                     and encoding functions */
                                     and encoding functions */
-    UA_Boolean fixedSize    : 1; /* The type (and its members) contains no
-                                    pointers */
+    UA_Boolean pointerFree  : 1; /* The type (and its members) contains no
+                                    pointers that need to be freed */
     UA_Boolean overlayable  : 1; /* The type has the identical memory layout in
     UA_Boolean overlayable  : 1; /* The type has the identical memory layout in
                                     memory and on the binary stream. */
                                     memory and on the binary stream. */
     UA_UInt16  binaryEncodingId; /* NodeId of datatype when encoded as binary */
     UA_UInt16  binaryEncodingId; /* NodeId of datatype when encoded as binary */
@@ -784,10 +774,19 @@ struct UA_DataType {
     UA_DataTypeMember *members;
     UA_DataTypeMember *members;
 };
 };
 
 
+/* The following is used to exclude type names in the definition of UA_DataType
+ * structures if the feature is disabled. */
+#ifdef UA_ENABLE_TYPENAMES
+# define UA_TYPENAME(name) name,
+#else
+# define UA_TYPENAME(name)
+#endif
+
 /**
 /**
  * Builtin data types can be accessed as UA_TYPES[UA_TYPES_XXX], where XXX is
  * Builtin data types can be accessed as UA_TYPES[UA_TYPES_XXX], where XXX is
  * the name of the data type. If only the NodeId of a type is known, use the
  * the name of the data type. If only the NodeId of a type is known, use the
  * following method to retrieve the data type description. */
  * following method to retrieve the data type description. */
+
 /* Returns the data type description for the type's identifier or NULL if no
 /* Returns the data type description for the type's identifier or NULL if no
  * matching data type was found. */
  * matching data type was found. */
 const UA_DataType UA_EXPORT *
 const UA_DataType UA_EXPORT *
@@ -896,6 +895,31 @@ UA_Guid UA_EXPORT UA_Guid_random(void);     /* no cryptographic entropy */
  * .. toctree::
  * .. toctree::
  *
  *
  *    types_generated */
  *    types_generated */
+
+/**
+ * Deprecated Data Types API
+ * -------------------------
+ * The following definitions are deprecated and will be removed in future
+ * releases of open62541. */
+
+typedef struct {
+    UA_StatusCode code;      /* The numeric value of the StatusCode */
+    const char* name;        /* The symbolic name */
+    const char* explanation; /* Short message explaining the StatusCode */
+} UA_StatusCodeDescription;
+
+UA_EXPORT extern const UA_StatusCodeDescription statusCodeExplanation_default;
+
+UA_DEPRECATED static UA_INLINE const UA_StatusCodeDescription *
+UA_StatusCode_description(UA_StatusCode code) {
+    return &statusCodeExplanation_default;
+}
+
+UA_DEPRECATED static UA_INLINE const char *
+UA_StatusCode_explanation(UA_StatusCode code) {
+    return statusCodeExplanation_default.name;
+}
+
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"
 #endif
 #endif

+ 13 - 4
open62541.spec

@@ -1,12 +1,12 @@
 Name:     open62541
 Name:     open62541
-Version:  0.2
+Version:  0.3
 Release:  1%{?dist}
 Release:  1%{?dist}
 Summary:  OPC UA implementation
 Summary:  OPC UA implementation
 License:  MPLv2.0
 License:  MPLv2.0
 URL:      http://open62541.org
 URL:      http://open62541.org
 Source0:  https://github.com/open62541/open62541/archive/%{name}-%{version}.tar.gz
 Source0:  https://github.com/open62541/open62541/archive/%{name}-%{version}.tar.gz
 
 
-BuildRequires: cmake, python
+BuildRequires: cmake3, python
 
 
 %description
 %description
 open62541 is a C-based library (linking with C++ projects is possible)
 open62541 is a C-based library (linking with C++ projects is possible)
@@ -25,7 +25,7 @@ developing applications that use %{name}.
 %setup -q -n %{name}-%{name}-%{version} # double-name prefix by GitHub
 %setup -q -n %{name}-%{name}-%{version} # double-name prefix by GitHub
 
 
 %build
 %build
-%cmake -DUA_ENABLE_AMALGAMATION=ON .
+%cmake3 -DUA_ENABLE_AMALGAMATION=ON .
 make
 make
 
 
 %install
 %install
@@ -46,11 +46,20 @@ rm examples/CMakeLists.txt
 %files devel
 %files devel
 %license LICENSE LICENSE-CC0
 %license LICENSE LICENSE-CC0
 %{_libdir}/libopen62541.so
 %{_libdir}/libopen62541.so
-%{_includedir}/open62541.h
+%{_libdir}/pkgconfig/open62541.pc
+%dir %{_includedir}/open62541
+%{_includedir}/open62541/*
+%{_libdir}/cmake3/open62541*
+%dir %{_exec_prefix}/share/open62541
+%{_exec_prefix}/share/open62541/*
+
 %doc FEATURES.md
 %doc FEATURES.md
 %doc examples/
 %doc examples/
 
 
 %changelog
 %changelog
+* Tue Sep 05 2017 Jens Reimann <jreimann@redhat.com> - 0.3-1
+- New version of open62541
+- Adapt for cmake3
 * Thu Aug 31 2017 Jens Reimann <jreimann@redhat.com> - 0.2-1
 * Thu Aug 31 2017 Jens Reimann <jreimann@redhat.com> - 0.2-1
 - Initial version of the package
 - Initial version of the package
 
 

+ 141 - 0
plugins/ua_accesscontrol_default.c

@@ -0,0 +1,141 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include "ua_accesscontrol_default.h"
+
+/* Example access control management. Anonymous and username / password login.
+ * The access rights are maximally permissive. */
+
+#define ANONYMOUS_POLICY "open62541-anonymous-policy"
+#define USERNAME_POLICY "open62541-username-policy"
+
+// TODO: There should be one definition of these strings in the endpoint.
+// Put the endpoint definition in the access control struct?
+#define UA_STRING_STATIC(s) {sizeof(s)-1, (UA_Byte*)s}
+const UA_String anonymous_policy = UA_STRING_STATIC(ANONYMOUS_POLICY);
+const UA_String username_policy = UA_STRING_STATIC(USERNAME_POLICY);
+
+typedef struct {
+    UA_String username;
+    UA_String password;
+} UA_UsernamePasswordLogin;
+
+const size_t usernamePasswordsSize = 2;
+UA_UsernamePasswordLogin usernamePasswords[2] = {
+    { UA_STRING_STATIC("user1"), UA_STRING_STATIC("password") },
+    { UA_STRING_STATIC("user2"), UA_STRING_STATIC("password1") } };
+
+UA_StatusCode
+activateSession_default(const UA_NodeId *sessionId,
+                        const UA_ExtensionObject *userIdentityToken,
+                        void **sessionContext) {
+    /* Could the token be decoded? */
+    if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED)
+        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+
+    /* Anonymous login */
+    if(userIdentityToken->content.decoded.type ==
+       &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
+        const UA_AnonymousIdentityToken *token =
+            (UA_AnonymousIdentityToken*)userIdentityToken->content.decoded.data;
+
+        /* Compatibility notice: Siemens OPC Scout v10 provides an empty
+         * policyId. This is not compliant. For compatibility, assume that empty
+         * policyId == ANONYMOUS_POLICY */
+        if(token->policyId.data &&
+           !UA_String_equal(&token->policyId, &anonymous_policy))
+            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+
+        /* No userdata atm */
+        *sessionContext = NULL;
+        return UA_STATUSCODE_GOOD;
+    }
+
+    /* Username and password */
+    if(userIdentityToken->content.decoded.type ==
+       &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
+        const UA_UserNameIdentityToken *token =
+            (UA_UserNameIdentityToken*)userIdentityToken->content.decoded.data;
+        if(!UA_String_equal(&token->policyId, &username_policy) || token->encryptionAlgorithm.length > 0)
+            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+
+        /* Empty username and password */
+        if(token->userName.length == 0 && token->password.length == 0)
+            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+
+        /* Try to match username/pw */
+        UA_Boolean match = false;
+        for(size_t i = 0; i < usernamePasswordsSize; i++) {
+            const UA_String *user = &usernamePasswords[i].username;
+            const UA_String *pw = &usernamePasswords[i].password;
+            if(UA_String_equal(&token->userName, user) &&
+               UA_String_equal(&token->password, pw)) {
+                match = true;
+                break;
+            }
+        }
+        if(!match)
+            return UA_STATUSCODE_BADUSERACCESSDENIED;
+
+        /* No userdata atm */
+        *sessionContext = NULL;
+        return UA_STATUSCODE_GOOD;
+    }
+
+    /* Unsupported token type */
+    return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+}
+
+void
+closeSession_default(const UA_NodeId *sessionId, void *sessionContext) {
+    /* no context to clean up */
+}
+
+UA_UInt32
+getUserRightsMask_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *nodeId, void *nodeContext) {
+    return 0xFFFFFFFF;
+}
+
+UA_Byte
+getUserAccessLevel_default(const UA_NodeId *sessionId, void *sessionContext,
+                           const UA_NodeId *nodeId, void *nodeContext) {
+    return 0xFF;
+}
+
+UA_Boolean
+getUserExecutable_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *methodId, void *methodContext) {
+    return true;
+}
+
+UA_Boolean
+getUserExecutableOnObject_default(const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *methodId, void *methodContext,
+                                  const UA_NodeId *objectId, void *objectContext) {
+    return true;
+}
+
+UA_Boolean
+allowAddNode_default(const UA_NodeId *sessionId, void *sessionContext,
+                     const UA_AddNodesItem *item) {
+    return true;
+}
+
+UA_Boolean
+allowAddReference_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_AddReferencesItem *item) {
+    return true;
+}
+
+UA_Boolean
+allowDeleteNode_default(const UA_NodeId *sessionId, void *sessionContext,
+                        const UA_DeleteNodesItem *item) {
+    return true;
+}
+      
+UA_Boolean
+allowDeleteReference_default(const UA_NodeId *sessionId, void *sessionContext,
+                             const UA_DeleteReferencesItem *item) {
+    return true;
+}

+ 58 - 0
plugins/ua_accesscontrol_default.h

@@ -0,0 +1,58 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#ifndef UA_ACCESSCONTROL_DEFAULT_H_
+#define UA_ACCESSCONTROL_DEFAULT_H_
+
+#include "ua_server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UA_StatusCode UA_EXPORT
+activateSession_default(const UA_NodeId *sessionId,
+                        const UA_ExtensionObject *userIdentityToken,
+                        void **sessionContext);
+
+void UA_EXPORT
+closeSession_default(const UA_NodeId *sessionId, void *sessionContext);
+
+UA_UInt32 UA_EXPORT
+getUserRightsMask_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *nodeId, void *nodeContext);
+
+UA_Byte UA_EXPORT
+getUserAccessLevel_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *nodeId, void *nodeContext);
+
+UA_Boolean UA_EXPORT
+getUserExecutable_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *methodId, void *methodContext);
+
+UA_Boolean UA_EXPORT
+getUserExecutableOnObject_default(const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *methodId, void *methodContext,
+                                  const UA_NodeId *objectId, void *objectContext);
+
+UA_Boolean UA_EXPORT
+allowAddNode_default(const UA_NodeId *sessionId, void *sessionContext,
+                     const UA_AddNodesItem *item);
+
+UA_Boolean UA_EXPORT
+allowAddReference_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_AddReferencesItem *item);
+
+UA_Boolean UA_EXPORT
+allowDeleteNode_default(const UA_NodeId *sessionId, void *sessionContext,
+                        const UA_DeleteNodesItem *item);
+
+UA_Boolean UA_EXPORT
+allowDeleteReference_default(const UA_NodeId *sessionId, void *sessionContext,
+                             const UA_DeleteReferencesItem *item);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_ACCESSCONTROL_DEFAULT_H_ */

+ 24 - 2
plugins/ua_clock.c

@@ -1,14 +1,34 @@
 /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 
-#include "ua_types.h"
+/* Enable POSIX features */
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE 600
+#endif
+#ifndef _DEFAULT_SOURCE
+# define _DEFAULT_SOURCE
+#endif
+/* On older systems we need to define _BSD_SOURCE.
+ * _DEFAULT_SOURCE is an alias for that. */
+#ifndef _BSD_SOURCE
+# define _BSD_SOURCE
+#endif
 
 
 #include <time.h>
 #include <time.h>
 #ifdef _WIN32
 #ifdef _WIN32
+/* Backup definition of SLIST_ENTRY on mingw winnt.h */
 # ifdef SLIST_ENTRY
 # ifdef SLIST_ENTRY
-#  undef SLIST_ENTRY /* Fix redefinition of SLIST_ENTRY on mingw winnt.h */
+#  pragma push_macro("SLIST_ENTRY")
+#  undef SLIST_ENTRY
+#  define POP_SLIST_ENTRY
 # endif
 # endif
 # include <windows.h>
 # include <windows.h>
+/* restore definition */
+# ifdef POP_SLIST_ENTRY
+#  undef SLIST_ENTRY
+#  undef POP_SLIST_ENTRY
+#  pragma pop_macro("SLIST_ENTRY")
+# endif
 #else
 #else
 # include <sys/time.h>
 # include <sys/time.h>
 #endif
 #endif
@@ -18,6 +38,8 @@
 # include <mach/mach.h>
 # include <mach/mach.h>
 #endif
 #endif
 
 
+#include "ua_types.h"
+
 UA_DateTime UA_DateTime_now(void) {
 UA_DateTime UA_DateTime_now(void) {
 #if defined(_WIN32)
 #if defined(_WIN32)
     /* Windows filetime has the same definition as UA_DateTime */
     /* Windows filetime has the same definition as UA_DateTime */

+ 311 - 0
plugins/ua_config_default.c

@@ -0,0 +1,311 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include "ua_config_default.h"
+#include "ua_log_stdout.h"
+#include "ua_network_tcp.h"
+#include "ua_accesscontrol_default.h"
+#include "ua_nodestore_default.h"
+#include "ua_types_generated.h"
+#include "ua_securitypolicy_none.h"
+#include "ua_types.h"
+#include "ua_types_generated_handling.h"
+#include "ua_client_highlevel.h"
+
+#define ANONYMOUS_POLICY "open62541-anonymous-policy"
+#define USERNAME_POLICY "open62541-username-policy"
+
+/* Struct initialization works across ANSI C/C99/C++ if it is done when the
+ * variable is first declared. Assigning values to existing structs is
+ * heterogeneous across the three. */
+static UA_INLINE UA_UInt32Range
+UA_UINT32RANGE(UA_UInt32 min, UA_UInt32 max) {
+    UA_UInt32Range range = {min, max};
+    return range;
+}
+
+static UA_INLINE UA_DurationRange
+UA_DURATIONRANGE(UA_Double min, UA_Double max) {
+    UA_DurationRange range = {min, max};
+    return range;
+}
+
+/*******************************/
+/* Default Connection Settings */
+/*******************************/
+
+const UA_ConnectionConfig UA_ConnectionConfig_default = {
+    0, /* .protocolVersion */
+    65535, /* .sendBufferSize, 64k per chunk */
+    65535, /* .recvBufferSize, 64k per chunk */
+    0, /* .maxMessageSize, 0 -> unlimited */
+    0 /* .maxChunkCount, 0 -> unlimited */
+};
+
+/***************************/
+/* Default Server Settings */
+/***************************/
+
+#define MANUFACTURER_NAME "open62541"
+#define PRODUCT_NAME "open62541 OPC UA Server"
+#define PRODUCT_URI "http://open62541.org"
+#define APPLICATION_NAME "open62541-based OPC UA Application"
+#define APPLICATION_URI "urn:unconfigured:application"
+
+#define STRINGIFY(arg) #arg
+#define VERSION(MAJOR, MINOR, PATCH, LABEL) \
+    STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(PATCH) LABEL
+
+static UA_StatusCode
+createSecurityPolicyNoneEndpoint(UA_ServerConfig *conf, UA_Endpoint *endpoint,
+                                 const UA_ByteString localCertificate) {
+    UA_EndpointDescription_init(&endpoint->endpointDescription);
+
+    UA_SecurityPolicy_None(&endpoint->securityPolicy, localCertificate, conf->logger);
+    endpoint->endpointDescription.securityMode = UA_MESSAGESECURITYMODE_NONE;
+    endpoint->endpointDescription.securityPolicyUri =
+        UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
+    endpoint->endpointDescription.transportProfileUri =
+        UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
+
+    /* enable anonymous and username/password */
+    size_t policies = 2;
+    endpoint->endpointDescription.userIdentityTokens = (UA_UserTokenPolicy*)
+        UA_Array_new(policies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
+    if(!endpoint->endpointDescription.userIdentityTokens)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    endpoint->endpointDescription.userIdentityTokensSize = policies;
+
+    endpoint->endpointDescription.userIdentityTokens[0].tokenType =
+        UA_USERTOKENTYPE_ANONYMOUS;
+    endpoint->endpointDescription.userIdentityTokens[0].policyId =
+        UA_STRING_ALLOC(ANONYMOUS_POLICY);
+
+    endpoint->endpointDescription.userIdentityTokens[1].tokenType =
+        UA_USERTOKENTYPE_USERNAME;
+    endpoint->endpointDescription.userIdentityTokens[1].policyId =
+        UA_STRING_ALLOC(USERNAME_POLICY);
+
+    UA_String_copy(&localCertificate, &endpoint->endpointDescription.serverCertificate);
+
+    UA_ApplicationDescription_copy(&conf->applicationDescription,
+                                   &endpoint->endpointDescription.server);
+
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_ServerConfig *
+UA_ServerConfig_new_minimal(UA_UInt16 portNumber,
+                            const UA_ByteString *certificate) {
+    UA_ServerConfig *conf = (UA_ServerConfig*)UA_malloc(sizeof(UA_ServerConfig));
+    if(!conf)
+        return NULL;
+
+    /* Zero out.. All members have a valid initial value */
+    memset(conf, 0, sizeof(UA_ServerConfig));
+
+    /* --> Start setting the default static config <-- */
+    conf->nThreads = 1;
+    conf->logger = UA_Log_Stdout;
+
+    /* Server Description */
+    conf->buildInfo.productUri = UA_STRING_ALLOC(PRODUCT_URI);
+    conf->buildInfo.manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME);
+    conf->buildInfo.productName = UA_STRING_ALLOC(PRODUCT_NAME);
+    conf->buildInfo.softwareVersion =
+        UA_STRING_ALLOC(VERSION(UA_OPEN62541_VER_MAJOR, UA_OPEN62541_VER_MINOR,
+                                UA_OPEN62541_VER_PATCH, UA_OPEN62541_VER_LABEL));
+    conf->buildInfo.buildNumber = UA_STRING_ALLOC(__DATE__ " " __TIME__);
+    conf->buildInfo.buildDate = 0;
+
+    conf->applicationDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI);
+    conf->applicationDescription.productUri = UA_STRING_ALLOC(PRODUCT_URI);
+    conf->applicationDescription.applicationName = 
+        UA_LOCALIZEDTEXT_ALLOC("en", APPLICATION_NAME);
+    conf->applicationDescription.applicationType = UA_APPLICATIONTYPE_SERVER;
+    /* conf->applicationDescription.gatewayServerUri = UA_STRING_NULL; */
+    /* conf->applicationDescription.discoveryProfileUri = UA_STRING_NULL; */
+    /* conf->applicationDescription.discoveryUrlsSize = 0; */
+    /* conf->applicationDescription.discoveryUrls = NULL; */
+
+#ifdef UA_ENABLE_DISCOVERY
+    /* conf->mdnsServerName = UA_STRING_NULL; */
+    /* conf->serverCapabilitiesSize = 0; */
+    /* conf->serverCapabilities = NULL; */
+#endif
+
+    /* Custom DataTypes */
+    /* conf->customDataTypesSize = 0; */
+    /* conf->customDataTypes = NULL; */
+
+    /* Networking */
+    /* conf->networkLayersSize = 0; */
+    /* conf->networkLayers = NULL; */
+
+    /* Endpoints */
+    /* conf->endpoints = {0, NULL}; */
+
+    /* Global Node Lifecycle */
+    conf->nodeLifecycle.constructor = NULL;
+    conf->nodeLifecycle.destructor = NULL;
+
+    /* Access Control */
+    conf->accessControl.enableAnonymousLogin = true;
+    conf->accessControl.enableUsernamePasswordLogin = true;
+    conf->accessControl.activateSession = activateSession_default;
+    conf->accessControl.closeSession = closeSession_default;
+    conf->accessControl.getUserRightsMask = getUserRightsMask_default;
+    conf->accessControl.getUserAccessLevel = getUserAccessLevel_default;
+    conf->accessControl.getUserExecutable = getUserExecutable_default;
+    conf->accessControl.getUserExecutableOnObject = getUserExecutableOnObject_default;
+    conf->accessControl.allowAddNode = allowAddNode_default;
+    conf->accessControl.allowAddReference = allowAddReference_default;
+    conf->accessControl.allowDeleteNode = allowDeleteNode_default;
+    conf->accessControl.allowDeleteReference = allowDeleteReference_default;
+
+    /* Limits for SecureChannels */
+    conf->maxSecureChannels = 40;
+    conf->maxSecurityTokenLifetime = 10 * 60 * 1000; /* 10 minutes */
+
+    /* Limits for Sessions */
+    conf->maxSessions = 100;
+    conf->maxSessionTimeout = 60.0 * 60.0 * 1000.0; /* 1h */
+
+    /* Limits for Subscriptions */
+    conf->publishingIntervalLimits = UA_DURATIONRANGE(100.0, 3600.0 * 1000.0);
+    conf->lifeTimeCountLimits = UA_UINT32RANGE(3, 15000);
+    conf->keepAliveCountLimits = UA_UINT32RANGE(1, 100);
+    conf->maxNotificationsPerPublish = 1000;
+    conf->maxRetransmissionQueueSize = 0; /* unlimited */
+
+    /* Limits for MonitoredItems */
+    conf->samplingIntervalLimits = UA_DURATIONRANGE(50.0, 24.0 * 3600.0 * 1000.0);
+    conf->queueSizeLimits = UA_UINT32RANGE(1, 100);
+
+#ifdef UA_ENABLE_DISCOVERY
+    conf->discoveryCleanupTimeout = 60 * 60;
+#endif
+
+    /* --> Finish setting the default static config <-- */
+
+    UA_StatusCode retval = UA_Nodestore_default_new(&conf->nodestore);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ServerConfig_delete(conf);
+        return NULL;
+    }
+
+    /* Add a network layer */
+    conf->networkLayers = (UA_ServerNetworkLayer*)
+        UA_malloc(sizeof(UA_ServerNetworkLayer));
+    if(!conf->networkLayers) {
+        UA_ServerConfig_delete(conf);
+        return NULL;
+    }
+    conf->networkLayers[0] =
+        UA_ServerNetworkLayerTCP(UA_ConnectionConfig_default, portNumber);
+    conf->networkLayersSize = 1;
+
+    /* Allocate the endpoint */
+    conf->endpointsSize = 1;
+    conf->endpoints = (UA_Endpoint*)UA_malloc(sizeof(UA_Endpoint));
+    if(!conf->endpoints) {
+        UA_ServerConfig_delete(conf);
+        return NULL;
+    }
+
+    /* Populate the endpoint */
+    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
+    if(certificate)
+        localCertificate = *certificate;
+    retval =
+        createSecurityPolicyNoneEndpoint(conf, &conf->endpoints[0], localCertificate);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ServerConfig_delete(conf);
+        return NULL;
+    }
+
+    return conf;
+}
+
+void
+UA_ServerConfig_delete(UA_ServerConfig *config) {
+    if(!config)
+        return;
+
+    /* Server Description */
+    UA_BuildInfo_deleteMembers(&config->buildInfo);
+    UA_ApplicationDescription_deleteMembers(&config->applicationDescription);
+#ifdef UA_ENABLE_DISCOVERY
+    UA_String_deleteMembers(&config->mdnsServerName);
+    UA_Array_delete(config->serverCapabilities, config->serverCapabilitiesSize,
+                    &UA_TYPES[UA_TYPES_STRING]);
+    config->serverCapabilities = NULL;
+    config->serverCapabilitiesSize = 0;
+#endif
+
+    /* Nodestore */
+    if(config->nodestore.deleteNodestore)
+        config->nodestore.deleteNodestore(config->nodestore.context);
+
+    /* Custom DataTypes */
+    for(size_t i = 0; i < config->customDataTypesSize; ++i)
+        UA_free(config->customDataTypes[i].members);
+    UA_free(config->customDataTypes);
+    config->customDataTypes = NULL;
+    config->customDataTypesSize = 0;
+
+    /* Networking */
+    for(size_t i = 0; i < config->networkLayersSize; ++i)
+        config->networkLayers[i].deleteMembers(&config->networkLayers[i]);
+    UA_free(config->networkLayers);
+    config->networkLayers = NULL;
+    config->networkLayersSize = 0;
+
+    for(size_t i = 0; i < config->endpointsSize; ++i) {
+        UA_SecurityPolicy *policy = &config->endpoints[i].securityPolicy;
+        policy->deleteMembers(policy);
+        UA_EndpointDescription_deleteMembers(&config->endpoints[i].endpointDescription);
+    }
+    UA_free(config->endpoints);
+    config->endpoints = NULL;
+    config->endpointsSize = 0;
+
+    UA_free(config);
+}
+
+/***************************/
+/* Default Client Settings */
+/***************************/
+
+const UA_ClientConfig UA_ClientConfig_default = {
+    5000, /* .timeout, 5 seconds */
+    10 * 60 * 1000, /* .secureChannelLifeTime, 10 minutes */
+    UA_Log_Stdout, /* .logger */
+    /* .localConnectionConfig */
+    {0, /* .protocolVersion */
+        65535, /* .sendBufferSize, 64k per chunk */
+        65535, /* .recvBufferSize, 64k per chunk */
+        0, /* .maxMessageSize, 0 -> unlimited */
+        0}, /* .maxChunkCount, 0 -> unlimited */
+    UA_ClientConnectionTCP, /* .connectionFunc */
+
+    0, /* .customDataTypesSize */
+    NULL /*.customDataTypes */
+};
+
+/****************************************/
+/* Default Client Subscription Settings */
+/****************************************/
+
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+
+const UA_SubscriptionSettings UA_SubscriptionSettings_default = {
+    500.0, /* .requestedPublishingInterval */
+    10000, /* .requestedLifetimeCount */
+    1, /* .requestedMaxKeepAliveCount */
+    10, /* .maxNotificationsPerPublish */
+    true, /* .publishingEnabled */
+    0 /* .priority */
+};
+
+#endif

+ 59 - 0
plugins/ua_config_default.h

@@ -0,0 +1,59 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#ifndef UA_CONFIG_DEFAULT_H_
+#define UA_CONFIG_DEFAULT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_server.h"
+#include "ua_server_config.h"
+#include "ua_client.h"
+
+/**********************/
+/* Default Connection */
+/**********************/
+
+extern const UA_EXPORT UA_ConnectionConfig UA_ConnectionConfig_default;
+
+/*************************/
+/* Default Server Config */
+/*************************/
+
+/* Creates a new server config with one endpoint.
+ * 
+ * The config will set the tcp network layer to the given port and adds a single
+ * endpoint with the security policy ``SecurityPolicy#None`` to the server. A
+ * server certificate may be supplied but is optional.
+ *
+ * @param portNumber The port number for the tcp network layer
+ * @param certificate Optional certificate for the server endpoint. Can be
+ *        ``NULL``. */
+UA_EXPORT UA_ServerConfig *
+UA_ServerConfig_new_minimal(UA_UInt16 portNumber,
+                            const UA_ByteString *certificate);
+
+/* Creates a server config on the default port 4840 with no server
+ * certificate. */
+static UA_INLINE UA_ServerConfig *
+UA_ServerConfig_new_default(void) {
+    return UA_ServerConfig_new_minimal(4840, NULL);
+}
+
+/* Frees allocated memory in the server config */
+UA_EXPORT void
+UA_ServerConfig_delete(UA_ServerConfig *config);
+
+/*************************/
+/* Default Client Config */
+/*************************/
+
+extern const UA_EXPORT UA_ClientConfig UA_ClientConfig_default;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_CONFIG_DEFAULT_H_ */

+ 0 - 130
plugins/ua_config_standard.c

@@ -1,130 +0,0 @@
-/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
- * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
-
-#include "ua_config_standard.h"
-#include "ua_log_stdout.h"
-#include "ua_network_tcp.h"
-
-/*******************************/
-/* Default Connection Settings */
-/*******************************/
-
-const UA_EXPORT UA_ConnectionConfig UA_ConnectionConfig_standard = {
-    .protocolVersion = 0,
-    .sendBufferSize = 65535, /* 64k per chunk */
-    .recvBufferSize = 65535, /* 64k per chunk */
-    .maxMessageSize = 0, /* 0 -> unlimited */
-    .maxChunkCount = 0 /* 0 -> unlimited */
-};
-
-/***************************/
-/* Default Server Settings */
-/***************************/
-
-#define MANUFACTURER_NAME "open62541"
-#define PRODUCT_NAME "open62541 OPC UA Server"
-#define PRODUCT_URI "http://open62541.org"
-#define APPLICATION_NAME "open62541-based OPC UA Application"
-#define APPLICATION_URI "urn:unconfigured:application"
-
-#define UA_STRING_STATIC(s) {sizeof(s)-1, (UA_Byte*)s}
-#define UA_STRING_STATIC_NULL {0, NULL}
-
-#define STRINGIFY(arg) #arg
-#define VERSION(MAJOR, MINOR, PATCH, LABEL) \
-    STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(PATCH) LABEL
-
-UA_UsernamePasswordLogin usernamePasswords[2] = {
-    { UA_STRING_STATIC("user1"), UA_STRING_STATIC("password") },
-    { UA_STRING_STATIC("user2"), UA_STRING_STATIC("password1") } };
-
-const UA_EXPORT UA_ServerConfig UA_ServerConfig_standard = {
-    .nThreads = 1,
-    .logger = UA_Log_Stdout,
-
-    /* Server Description */
-    .buildInfo = {
-        .productUri = UA_STRING_STATIC(PRODUCT_URI),
-        .manufacturerName = UA_STRING_STATIC(MANUFACTURER_NAME),
-        .productName = UA_STRING_STATIC(PRODUCT_NAME),
-        .softwareVersion = UA_STRING_STATIC(VERSION(UA_OPEN62541_VER_MAJOR,
-                                                    UA_OPEN62541_VER_MINOR,
-                                                    UA_OPEN62541_VER_PATCH,
-                                                    UA_OPEN62541_VER_LABEL)),
-        .buildNumber = UA_STRING_STATIC(__DATE__ " " __TIME__),
-        .buildDate = 0 },
-    .applicationDescription = {
-        .applicationUri = UA_STRING_STATIC(APPLICATION_URI),
-        .productUri = UA_STRING_STATIC(PRODUCT_URI),
-        .applicationName = { .locale = UA_STRING_STATIC("en"),
-                             .text = UA_STRING_STATIC(APPLICATION_NAME) },
-        .applicationType = UA_APPLICATIONTYPE_SERVER,
-        .gatewayServerUri = UA_STRING_STATIC_NULL,
-        .discoveryProfileUri = UA_STRING_STATIC_NULL,
-        .discoveryUrlsSize = 0,
-        .discoveryUrls = NULL },
-    .serverCertificate = UA_STRING_STATIC_NULL,
-
-    /* Networking */
-    .networkLayersSize = 0,
-    .networkLayers = NULL,
-
-    /* Login */
-    .enableAnonymousLogin = true,
-    .enableUsernamePasswordLogin = true,
-    .usernamePasswordLogins = usernamePasswords,
-    .usernamePasswordLoginsSize = 2,
-
-    /* Limits for SecureChannels */
-    .maxSecureChannels = 40,
-    .maxSecurityTokenLifetime = 10 * 60 * 1000, /* 10 minutes */
-
-    /* Limits for Sessions */
-    .maxSessions = 100,
-    .maxSessionTimeout = 60.0 * 60.0 * 1000.0, /* 1h */
-
-    /* Limits for Subscriptions */
-    .publishingIntervalLimits = { .min = 100.0, .max = 3600.0 * 1000.0 },
-    .lifeTimeCountLimits = { .max = 15000, .min = 3 },
-    .keepAliveCountLimits = { .max = 100, .min = 1 },
-    .maxNotificationsPerPublish = 1000,
-    .maxRetransmissionQueueSize = 0, /* unlimited */
-
-    /* Limits for MonitoredItems */
-    .samplingIntervalLimits = { .min = 50.0, .max = 24.0 * 3600.0 * 1000.0 },
-    .queueSizeLimits = { .max = 100, .min = 1 }
-};
-
-/***************************/
-/* Default Client Settings */
-/***************************/
-
-const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard = {
-    .timeout = 5000, /* 5 seconds */
-    .secureChannelLifeTime = 10 * 60 * 1000, /* 10 minutes */
-    .logger = UA_Log_Stdout,
-    .localConnectionConfig = {
-        .protocolVersion = 0,
-        .sendBufferSize = 65535, /* 64k per chunk */
-        .recvBufferSize  = 65535, /* 64k per chunk */
-        .maxMessageSize = 0, /* 0 -> unlimited */
-        .maxChunkCount = 0 /* 0 -> unlimited */
-    },
-    .connectionFunc = UA_ClientConnectionTCP
-};
-/****************************************/
-/* Default Client Subscription Settings */
-/****************************************/
-
-#ifdef UA_ENABLE_SUBSCRIPTIONS
-
-const UA_SubscriptionSettings UA_SubscriptionSettings_standard = {
-    .requestedPublishingInterval = 500.0,
-    .requestedLifetimeCount = 10000,
-    .requestedMaxKeepAliveCount = 1,
-    .maxNotificationsPerPublish = 10,
-    .publishingEnabled = true,
-    .priority = 0
-};
-
-#endif

+ 0 - 22
plugins/ua_config_standard.h

@@ -1,22 +0,0 @@
-/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
- * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
-
-#ifndef UA_CONFIG_STANDARD_H_
-#define UA_CONFIG_STANDARD_H_
-
-#include "ua_server.h"
-#include "ua_client.h"
-#include "ua_client_highlevel.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-extern UA_EXPORT const UA_ServerConfig UA_ServerConfig_standard;
-extern UA_EXPORT const UA_ClientConfig UA_ClientConfig_standard;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* UA_CONFIG_STANDARD_H_ */

+ 36 - 0
plugins/ua_debug_dump_pkgs.c

@@ -0,0 +1,36 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include "ua_util.h"
+
+#include <ctype.h>
+#include <stdio.h>
+void UA_dump_hex_pkg(UA_Byte* buffer, size_t bufferLen) {
+    printf("--------------- HEX Package Start ---------------\n");
+    char ascii[17];
+    memset(ascii,0,17);
+    for (size_t i = 0; i < bufferLen; i++)
+    {
+        if (i == 0)
+            printf("%08zx ", i);
+        else if (i%16 == 0)
+            printf(" |%s|\n%08zx ", ascii, i);
+        if (isprint((int)(buffer[i])))
+            ascii[i%16] = (char)buffer[i];
+        else
+            ascii[i%16] = '.';
+        if (i%8==0)
+            printf(" ");
+        printf("%02X ", (unsigned char)buffer[i]);
+
+    }
+    size_t fillPos = bufferLen %16;
+    ascii[fillPos] = 0;
+    for (size_t i=fillPos; i<16; i++) {
+        if (i%8==0)
+            printf(" ");
+        printf("   ");
+    }
+    printf(" |%s|\n%08zx\n", ascii, bufferLen);
+    printf("--------------- HEX Package END ---------------\n");
+}

+ 6 - 13
plugins/ua_log_stdout.c

@@ -12,15 +12,13 @@
 static pthread_mutex_t printf_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t printf_mutex = PTHREAD_MUTEX_INITIALIZER;
 #endif
 #endif
 
 
-const char *LogLevelNames[6] = {"trace", "debug", "info", "warning", "error", "fatal"};
-const char *LogCategoryNames[6] = {"network", "channel", "session", "server", "client", "userland"};
+const char *logLevelNames[6] = {"trace", "debug", "info", "warn", "error", "fatal"};
+const char *logCategoryNames[7] = {"network", "channel", "session", "server",
+                                   "client", "userland", "securitypolicy"};
 
 
-#if (defined(__GNUC__) && defined(__GNUC_MINOR__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6) || \
-    defined(__clang__)
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#ifdef __clang__
+__attribute__((__format__(__printf__, 3 , 0)))
 #endif
 #endif
-
 void
 void
 UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
 UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
               const char *msg, va_list args) {
               const char *msg, va_list args) {
@@ -28,7 +26,7 @@ UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
     pthread_mutex_lock(&printf_mutex);
     pthread_mutex_lock(&printf_mutex);
 #endif
 #endif
-    printf("[%.23s] %s/%s\t", t.data, LogLevelNames[level], LogCategoryNames[category]);
+    printf("[%.23s] %s/%s\t", t.data, logLevelNames[level], logCategoryNames[category]);
     vprintf(msg, args);
     vprintf(msg, args);
     printf("\n");
     printf("\n");
     fflush(stdout);
     fflush(stdout);
@@ -37,8 +35,3 @@ UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
 #endif
 #endif
     UA_ByteString_deleteMembers(&t);
     UA_ByteString_deleteMembers(&t);
 }
 }
-
-#if (defined(__GNUC__) && defined(__GNUC_MINOR__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6) || \
-    defined(__clang__)
-# pragma GCC diagnostic pop
-#endif

+ 2 - 3
plugins/ua_log_stdout.h

@@ -4,14 +4,13 @@
 #ifndef UA_LOG_STDOUT_H_
 #ifndef UA_LOG_STDOUT_H_
 #define UA_LOG_STDOUT_H_
 #define UA_LOG_STDOUT_H_
 
 
-#include "ua_types.h"
-#include "ua_log.h"
+#include "ua_plugin_log.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-UA_EXPORT void
+void UA_EXPORT
 UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
 UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
               const char *msg, va_list args);
               const char *msg, va_list args);
 
 

File diff suppressed because it is too large
+ 517 - 438
plugins/ua_network_tcp.c


+ 1 - 1
plugins/ua_network_tcp.h

@@ -15,7 +15,7 @@ UA_ServerNetworkLayer UA_EXPORT
 UA_ServerNetworkLayerTCP(UA_ConnectionConfig conf, UA_UInt16 port);
 UA_ServerNetworkLayerTCP(UA_ConnectionConfig conf, UA_UInt16 port);
 
 
 UA_Connection UA_EXPORT
 UA_Connection UA_EXPORT
-UA_ClientConnectionTCP(UA_ConnectionConfig conf, const char *endpointUrl, UA_Logger logger);
+UA_ClientConnectionTCP(UA_ConnectionConfig conf, const char *endpointUrl, const UA_UInt32 timeout);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"

+ 20 - 15
plugins/ua_network_udp.c

@@ -2,7 +2,6 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 
 #include "ua_network_udp.h"
 #include "ua_network_udp.h"
-#include <stdlib.h> // malloc, free
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h> // memset
 #include <string.h> // memset
 
 
@@ -14,7 +13,11 @@
 # include <errno.h> // errno, EINTR
 # include <errno.h> // errno, EINTR
 # include <fcntl.h> // fcntl
 # include <fcntl.h> // fcntl
 # include <strings.h> //bzero
 # include <strings.h> //bzero
-# include <sys/select.h>
+# ifndef _WRS_KERNEL
+#  include <sys/select.h>
+# else
+# include <selectLib.h>
+# endif
 # include <netinet/in.h>
 # include <netinet/in.h>
 # include <netinet/tcp.h>
 # include <netinet/tcp.h>
 # include <sys/socketvar.h>
 # include <sys/socketvar.h>
@@ -121,20 +124,22 @@ static void setFDSet(ServerNetworkLayerUDP *layer) {
 }
 }
 
 
 static void closeConnectionUDP(UA_Connection *handle) {
 static void closeConnectionUDP(UA_Connection *handle) {
-    free(handle);
+    UA_free(handle);
 }
 }
 
 
 static UA_StatusCode ServerNetworkLayerUDP_start(UA_ServerNetworkLayer *nl, UA_Logger logger) {
 static UA_StatusCode ServerNetworkLayerUDP_start(UA_ServerNetworkLayer *nl, UA_Logger logger) {
     ServerNetworkLayerUDP *layer = nl->handle;
     ServerNetworkLayerUDP *layer = nl->handle;
     layer->logger = logger;
     layer->logger = logger;
-    layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0);
+    layer->serversockfd = socket(AF_INET6, SOCK_DGRAM, 0);
     if(layer->serversockfd < 0) {
     if(layer->serversockfd < 0) {
         UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
         UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
-    const struct sockaddr_in serv_addr =
-        {.sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY,
-         .sin_port = htons(layer->port), .sin_zero = {0}};
+    struct sockaddr_in6 serv_addr;
+    memset(&serv_addr, 0, sizeof(serv_addr));
+    serv_addr.sin6_family = AF_INET6;
+    serv_addr.sin6_port = htons(layer->port);
+    serv_addr.sin6_addr = in6addr_any;
     int optval = 1;
     int optval = 1;
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
                   SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
@@ -164,12 +169,12 @@ static size_t ServerNetworkLayerUDP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **
         *jobs = items;
         *jobs = items;
         return 0;
         return 0;
     }
     }
-    items = malloc(sizeof(UA_Job)*(unsigned long)resultsize);
+    items = UA_malloc(sizeof(UA_Job)*(unsigned long)resultsize);
     // read from established sockets
     // read from established sockets
     size_t j = 0;
     size_t j = 0;
     UA_ByteString buf = {0, NULL};
     UA_ByteString buf = {0, NULL};
     if(!buf.data) {
     if(!buf.data) {
-        buf.data = malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
+        buf.data = UA_malloc(sizeof(UA_Byte) * layer->conf.recvBufferSize);
         if(!buf.data)
         if(!buf.data)
             UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "malloc failed");
             UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "malloc failed");
     }
     }
@@ -179,9 +184,9 @@ static size_t ServerNetworkLayerUDP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **
     ssize_t rec_result = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
     ssize_t rec_result = recvfrom(layer->serversockfd, buf.data, layer->conf.recvBufferSize, 0, &sender, &sendsize);
     if (rec_result > 0) {
     if (rec_result > 0) {
         buf.length = (size_t)rec_result;
         buf.length = (size_t)rec_result;
-        UDPConnection *c = malloc(sizeof(UDPConnection));
+        UDPConnection *c = UA_malloc(sizeof(UDPConnection));
         if(!c){
         if(!c){
-                free(items);
+                UA_free(items);
             return UA_STATUSCODE_BADINTERNALERROR;
             return UA_STATUSCODE_BADINTERNALERROR;
         }
         }
         UA_Connection_init(&c->connection);
         UA_Connection_init(&c->connection);
@@ -204,11 +209,11 @@ static size_t ServerNetworkLayerUDP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **
         j++;
         j++;
         *jobs = items;
         *jobs = items;
     } else {
     } else {
-        free(items);
+        UA_free(items);
         *jobs = NULL;
         *jobs = NULL;
     }
     }
     if(buf.data)
     if(buf.data)
-        free(buf.data);
+        UA_free(buf.data);
     return j;
     return j;
 }
 }
 
 
@@ -222,7 +227,7 @@ static size_t ServerNetworkLayerUDP_stop(UA_ServerNetworkLayer *nl, UA_Job **job
 
 
 static void ServerNetworkLayerUDP_deleteMembers(UA_ServerNetworkLayer *nl) {
 static void ServerNetworkLayerUDP_deleteMembers(UA_ServerNetworkLayer *nl) {
     ServerNetworkLayerUDP *layer = nl->handle;
     ServerNetworkLayerUDP *layer = nl->handle;
-    free(layer);
+    UA_free(layer);
     UA_String_deleteMembers(&nl->discoveryUrl);
     UA_String_deleteMembers(&nl->discoveryUrl);
 }
 }
 
 
@@ -231,7 +236,7 @@ UA_ServerNetworkLayerUDP(UA_ConnectionConfig conf, UA_UInt16 port) {
     UA_ServerNetworkLayer nl;
     UA_ServerNetworkLayer nl;
     memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
     memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
 
 
-    ServerNetworkLayerUDP *layer = malloc(sizeof(ServerNetworkLayerUDP));
+    ServerNetworkLayerUDP *layer = UA_malloc(sizeof(ServerNetworkLayerUDP));
     if(!layer)
     if(!layer)
         return nl;
         return nl;
     memset(layer, 0, sizeof(ServerNetworkLayerUDP));
     memset(layer, 0, sizeof(ServerNetworkLayerUDP));

+ 468 - 0
plugins/ua_nodestore_default.c

@@ -0,0 +1,468 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include "ua_nodestore_default.h"
+
+/* container_of */
+#define container_of(ptr, type, member) \
+    (type *)((uintptr_t)ptr - offsetof(type,member))
+
+#ifdef UA_ENABLE_MULTITHREADING
+#include <pthread.h>
+#define BEGIN_CRITSECT(NODEMAP) pthread_mutex_lock(&(NODEMAP)->mutex)
+#define END_CRITSECT(NODEMAP) pthread_mutex_unlock(&(NODEMAP)->mutex)
+#else
+#define BEGIN_CRITSECT(NODEMAP)
+#define END_CRITSECT(NODEMAP)
+#endif
+
+/* The default Nodestore is simply a hash-map from NodeIds to Nodes. To find an
+ * entry, iterate over candidate positions according to the NodeId hash.
+ *
+ * - Tombstone or non-matching NodeId: continue searching
+ * - Matching NodeId: Return the entry
+ * - NULL: Abort the search */
+
+typedef struct UA_NodeMapEntry {
+    struct UA_NodeMapEntry *orig; /* the version this is a copy from (or NULL) */
+    UA_UInt16 refCount; /* How many consumers have a reference to the node? */
+    UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */
+    UA_Node node;
+} UA_NodeMapEntry;
+
+#define UA_NODEMAP_MINSIZE 64
+#define UA_NODEMAP_TOMBSTONE ((UA_NodeMapEntry*)0x01)
+
+typedef struct {
+    UA_NodeMapEntry **entries;
+    UA_UInt32 size;
+    UA_UInt32 count;
+    UA_UInt32 sizePrimeIndex;
+#ifdef UA_ENABLE_MULTITHREADING
+    pthread_mutex_t mutex; /* Protect access */
+#endif
+} UA_NodeMap;
+
+/*********************/
+/* HashMap Utilities */
+/*********************/
+
+/* The size of the hash-map is always a prime number. They are chosen to be
+ * close to the next power of 2. So the size ca. doubles with each prime. */
+static UA_UInt32 const primes[] = {
+    7,         13,         31,         61,         127,         251,
+    509,       1021,       2039,       4093,       8191,        16381,
+    32749,     65521,      131071,     262139,     524287,      1048573,
+    2097143,   4194301,    8388593,    16777213,   33554393,    67108859,
+    134217689, 268435399,  536870909,  1073741789, 2147483647,  4294967291
+};
+
+static UA_UInt32 mod(UA_UInt32 h, UA_UInt32 size) { return h % size; }
+static UA_UInt32 mod2(UA_UInt32 h, UA_UInt32 size) { return 1 + (h % (size - 2)); }
+
+static UA_UInt16
+higher_prime_index(UA_UInt32 n) {
+    UA_UInt16 low  = 0;
+    UA_UInt16 high = (UA_UInt16)(sizeof(primes) / sizeof(UA_UInt32));
+    while(low != high) {
+        UA_UInt16 mid = (UA_UInt16)(low + ((high - low) / 2));
+        if(n > primes[mid])
+            low = (UA_UInt16)(mid + 1);
+        else
+            high = mid;
+    }
+    return low;
+}
+
+/* returns an empty slot or null if the nodeid exists */
+static UA_NodeMapEntry **
+findFreeSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) {
+    UA_UInt32 h = UA_NodeId_hash(nodeid);
+    UA_UInt32 size = ns->size;
+    UA_UInt32 idx = mod(h, size);
+    UA_UInt32 hash2 = mod2(h, size);
+
+    while(true) {
+        UA_NodeMapEntry *e = ns->entries[idx];
+        if(e > UA_NODEMAP_TOMBSTONE &&
+           UA_NodeId_equal(&e->node.nodeId, nodeid))
+            return NULL;
+        if(ns->entries[idx] <= UA_NODEMAP_TOMBSTONE)
+            return &ns->entries[idx];
+        idx += hash2;
+        if(idx >= size)
+            idx -= size;
+    }
+
+    /* NOTREACHED */
+    return NULL;
+}
+
+/* The occupancy of the table after the call will be about 50% */
+static UA_StatusCode
+expand(UA_NodeMap *ns) {
+    UA_UInt32 osize = ns->size;
+    UA_UInt32 count = ns->count;
+    /* Resize only when table after removal of unused elements is either too
+       full or too empty */
+    if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODEMAP_MINSIZE))
+        return UA_STATUSCODE_GOOD;
+
+    UA_NodeMapEntry **oentries = ns->entries;
+    UA_UInt32 nindex = higher_prime_index(count * 2);
+    UA_UInt32 nsize = primes[nindex];
+    UA_NodeMapEntry **nentries = (UA_NodeMapEntry **)UA_calloc(nsize, sizeof(UA_NodeMapEntry*));
+    if(!nentries)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    ns->entries = nentries;
+    ns->size = nsize;
+    ns->sizePrimeIndex = nindex;
+
+    /* recompute the position of every entry and insert the pointer */
+    for(size_t i = 0, j = 0; i < osize && j < count; ++i) {
+        if(oentries[i] <= UA_NODEMAP_TOMBSTONE)
+            continue;
+        UA_NodeMapEntry **e = findFreeSlot(ns, &oentries[i]->node.nodeId);
+        UA_assert(e);
+        *e = oentries[i];
+        ++j;
+    }
+
+    UA_free(oentries);
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_NodeMapEntry *
+newEntry(UA_NodeClass nodeClass) {
+    size_t size = sizeof(UA_NodeMapEntry) - sizeof(UA_Node);
+    switch(nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        size += sizeof(UA_ObjectNode);
+        break;
+    case UA_NODECLASS_VARIABLE:
+        size += sizeof(UA_VariableNode);
+        break;
+    case UA_NODECLASS_METHOD:
+        size += sizeof(UA_MethodNode);
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        size += sizeof(UA_ObjectTypeNode);
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        size += sizeof(UA_VariableTypeNode);
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        size += sizeof(UA_ReferenceTypeNode);
+        break;
+    case UA_NODECLASS_DATATYPE:
+        size += sizeof(UA_DataTypeNode);
+        break;
+    case UA_NODECLASS_VIEW:
+        size += sizeof(UA_ViewNode);
+        break;
+    default:
+        return NULL;
+    }
+    UA_NodeMapEntry *entry = (UA_NodeMapEntry*)UA_calloc(1, size);
+    if(!entry)
+        return NULL;
+    entry->node.nodeClass = nodeClass;
+    return entry;
+}
+
+static void
+deleteEntry(UA_NodeMapEntry *entry) {
+    UA_Node_deleteMembers(&entry->node);
+    UA_free(entry);
+}
+
+static void
+cleanupEntry(UA_NodeMapEntry *entry) {
+    if(entry->deleted && entry->refCount == 0)
+        deleteEntry(entry);
+}
+
+static UA_StatusCode
+clearSlot(UA_NodeMap *ns, UA_NodeMapEntry **slot) {
+    (*slot)->deleted = true;
+    cleanupEntry(*slot);
+    *slot = UA_NODEMAP_TOMBSTONE;
+    --ns->count;
+    /* Downsize the hashmap if it is very empty */
+    if(ns->count * 8 < ns->size && ns->size > 32)
+        expand(ns); /* Can fail. Just continue with the bigger hashmap. */
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_NodeMapEntry **
+findOccupiedSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) {
+    UA_UInt32 h = UA_NodeId_hash(nodeid);
+    UA_UInt32 size = ns->size;
+    UA_UInt32 idx = mod(h, size);
+    UA_UInt32 hash2 = mod2(h, size);
+
+    while(true) {
+        UA_NodeMapEntry *e = ns->entries[idx];
+        if(!e)
+            return NULL;
+        if(e > UA_NODEMAP_TOMBSTONE &&
+           UA_NodeId_equal(&e->node.nodeId, nodeid))
+            return &ns->entries[idx];
+        idx += hash2;
+        if(idx >= size)
+            idx -= size;
+    }
+
+    /* NOTREACHED */
+    return NULL;
+}
+
+/***********************/
+/* Interface functions */
+/***********************/
+
+static UA_Node *
+UA_NodeMap_newNode(void *context, UA_NodeClass nodeClass) {
+    UA_NodeMapEntry *entry = newEntry(nodeClass);
+    if(!entry)
+        return NULL;
+    return &entry->node;
+}
+
+static void
+UA_NodeMap_deleteNode(void *context, UA_Node *node) {
+#ifdef UA_ENABLE_MULTITHREADING
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+#endif
+    BEGIN_CRITSECT(ns);
+    UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node);
+    UA_assert(&entry->node == node);
+    deleteEntry(entry);
+    END_CRITSECT(ns);
+}
+
+static const UA_Node *
+UA_NodeMap_getNode(void *context, const UA_NodeId *nodeid) {
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+    BEGIN_CRITSECT(ns);
+    UA_NodeMapEntry **entry = findOccupiedSlot(ns, nodeid);
+    if(!entry) {
+        END_CRITSECT(ns);
+        return NULL;
+    }
+    ++(*entry)->refCount;
+    END_CRITSECT(ns);
+    return (const UA_Node*)&(*entry)->node;
+}
+
+static void
+UA_NodeMap_releaseNode(void *context, const UA_Node *node) {
+#ifdef UA_ENABLE_MULTITHREADING
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+#endif
+    BEGIN_CRITSECT(ns);
+    UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node);
+    UA_assert(&entry->node == node);
+    UA_assert(entry->refCount > 0);
+    --entry->refCount;
+    cleanupEntry(entry);
+    END_CRITSECT(ns);
+}
+
+static UA_StatusCode
+UA_NodeMap_getNodeCopy(void *context, const UA_NodeId *nodeid,
+                       UA_Node **outNode) {
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+    BEGIN_CRITSECT(ns);
+    UA_NodeMapEntry **slot = findOccupiedSlot(ns, nodeid);
+    if(!slot) {
+        END_CRITSECT(ns);
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
+    }
+    UA_NodeMapEntry *entry = *slot;
+    UA_NodeMapEntry *newItem = newEntry(entry->node.nodeClass);
+    if(!newItem) {
+        END_CRITSECT(ns);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+    UA_StatusCode retval = UA_Node_copy(&entry->node, &newItem->node);
+    if(retval == UA_STATUSCODE_GOOD) {
+        newItem->orig = entry; // store the pointer to the original
+        *outNode = &newItem->node;
+    } else {
+        deleteEntry(newItem);
+    }
+    END_CRITSECT(ns);
+    return retval;
+}
+
+static UA_StatusCode
+UA_NodeMap_removeNode(void *context, const UA_NodeId *nodeid) {
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+    BEGIN_CRITSECT(ns);
+    UA_NodeMapEntry **slot = findOccupiedSlot(ns, nodeid);
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(slot)
+        retval = clearSlot(ns, slot);
+    else
+        retval = UA_STATUSCODE_BADNODEIDUNKNOWN;
+    END_CRITSECT(ns);
+    return retval;
+}
+
+static UA_StatusCode
+UA_NodeMap_insertNode(void *context, UA_Node *node,
+                      UA_NodeId *addedNodeId) {
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+    BEGIN_CRITSECT(ns);
+    if(ns->size * 3 <= ns->count * 4) {
+        if(expand(ns) != UA_STATUSCODE_GOOD) {
+            END_CRITSECT(ns);
+            return UA_STATUSCODE_BADINTERNALERROR;
+        }
+    }
+
+    UA_NodeId tempNodeid;
+    tempNodeid = node->nodeId;
+    tempNodeid.namespaceIndex = 0;
+    UA_NodeMapEntry **slot;
+    if(tempNodeid.identifierType == UA_NODEIDTYPE_NUMERIC &&
+       tempNodeid.identifier.numeric == 0) {
+        /* create a random nodeid */
+		/* start at least with 50,000 to make sure we don not conflict with nodes from the spec */
+		/* E.g. adding a nodeset will create children while there are still other nodes which need to be created */
+		/* Thus the node id's may collide */
+        UA_UInt32 identifier = 50000 + ns->count+1; // start value
+        UA_UInt32 size = ns->size;
+        UA_UInt32 increase = mod2(ns->count+1, size);
+        while(true) {
+            node->nodeId.identifier.numeric = identifier;
+            slot = findFreeSlot(ns, &node->nodeId);
+            if(slot)
+                break;
+            identifier += increase;
+            if(identifier >= size)
+                identifier -= size;
+        }
+    } else {
+        slot = findFreeSlot(ns, &node->nodeId);
+        if(!slot) {
+            deleteEntry(container_of(node, UA_NodeMapEntry, node));
+            END_CRITSECT(ns);
+            return UA_STATUSCODE_BADNODEIDEXISTS;
+        }
+    }
+
+    *slot = container_of(node, UA_NodeMapEntry, node);
+    ++ns->count;
+    UA_assert(&(*slot)->node == node);
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(addedNodeId) {
+        retval = UA_NodeId_copy(&node->nodeId, addedNodeId);
+        if(retval != UA_STATUSCODE_GOOD)
+            clearSlot(ns, slot);
+    }
+
+    END_CRITSECT(ns);
+    return retval;
+}
+
+static UA_StatusCode
+UA_NodeMap_replaceNode(void *context, UA_Node *node) {
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+    BEGIN_CRITSECT(ns);
+    UA_NodeMapEntry **slot = findOccupiedSlot(ns, &node->nodeId);
+    if(!slot) {
+        END_CRITSECT(ns);
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
+    }
+    UA_NodeMapEntry *newEntryContainer = container_of(node, UA_NodeMapEntry, node);
+    if(*slot != newEntryContainer->orig) {
+        /* The node was updated since the copy was made */
+        deleteEntry(newEntryContainer);
+        END_CRITSECT(ns);
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+    (*slot)->deleted = true;
+    cleanupEntry(*slot);
+    *slot = newEntryContainer;
+    END_CRITSECT(ns);
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+UA_NodeMap_iterate(void *context, void *visitorContext,
+                   UA_NodestoreVisitor visitor) {
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+    BEGIN_CRITSECT(ns);
+    for(UA_UInt32 i = 0; i < ns->size; ++i) {
+        if(ns->entries[i] > UA_NODEMAP_TOMBSTONE) {
+            END_CRITSECT(ns);
+            UA_NodeMapEntry *entry = ns->entries[i];
+            entry->refCount++;
+            visitor(visitorContext, &entry->node);
+            entry->refCount--;
+            cleanupEntry(entry);
+            BEGIN_CRITSECT(ns);
+        }
+    }
+    END_CRITSECT(ns);
+}
+
+static void
+UA_NodeMap_delete(void *context) {
+    UA_NodeMap *ns = (UA_NodeMap*)context;
+#ifdef UA_ENABLE_MULTITHREADING
+    pthread_mutex_destroy(&ns->mutex);
+#endif
+    UA_UInt32 size = ns->size;
+    UA_NodeMapEntry **entries = ns->entries;
+    for(UA_UInt32 i = 0; i < size; ++i) {
+        if(entries[i] > UA_NODEMAP_TOMBSTONE) {
+            /* On debugging builds, check that all nodes were release */
+            UA_assert(entries[i]->refCount == 0);
+            /* Delete the node */
+            deleteEntry(entries[i]);
+        }
+    }
+    UA_free(ns->entries);
+    UA_free(ns);
+}
+
+UA_StatusCode
+UA_Nodestore_default_new(UA_Nodestore *ns) {
+    /* Allocate and initialize the nodemap */
+    UA_NodeMap *nodemap = (UA_NodeMap*)UA_malloc(sizeof(UA_NodeMap));
+    if(!nodemap)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    nodemap->sizePrimeIndex = higher_prime_index(UA_NODEMAP_MINSIZE);
+    nodemap->size = primes[nodemap->sizePrimeIndex];
+    nodemap->count = 0;
+    nodemap->entries = (UA_NodeMapEntry**)
+        UA_calloc(nodemap->size, sizeof(UA_NodeMapEntry*));
+    if(!nodemap->entries) {
+        UA_free(nodemap);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+#ifdef UA_ENABLE_MULTITHREADING
+    pthread_mutex_init(&nodemap->mutex, NULL);
+#endif
+
+    /* Populate the nodestore */
+    ns->context = nodemap;
+    ns->deleteNodestore = UA_NodeMap_delete;
+    ns->inPlaceEditAllowed = true;
+    ns->newNode = UA_NodeMap_newNode;
+    ns->deleteNode = UA_NodeMap_deleteNode;
+    ns->getNode = UA_NodeMap_getNode;
+    ns->releaseNode = UA_NodeMap_releaseNode;
+    ns->getNodeCopy = UA_NodeMap_getNodeCopy;
+    ns->insertNode = UA_NodeMap_insertNode;
+    ns->replaceNode = UA_NodeMap_replaceNode;
+    ns->removeNode = UA_NodeMap_removeNode;
+    ns->iterate = UA_NodeMap_iterate;
+
+    return UA_STATUSCODE_GOOD;
+}

+ 21 - 0
plugins/ua_nodestore_default.h

@@ -0,0 +1,21 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#ifndef UA_NODESTORE_DEFAULT_H_
+#define UA_NODESTORE_DEFAULT_H_
+
+#include "ua_plugin_nodestore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Initializes the nodestore, sets the context and function pointers */
+UA_StatusCode UA_EXPORT
+UA_Nodestore_default_new(UA_Nodestore *ns);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* UA_NODESTORE_DEFAULT_H_ */

+ 163 - 0
plugins/ua_securitypolicy_none.c

@@ -0,0 +1,163 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#include "ua_securitypolicy_none.h"
+#include "ua_types_generated_handling.h"
+
+static UA_StatusCode
+verify_none(const UA_SecurityPolicy *securityPolicy,
+            const void *channelContext,
+            const UA_ByteString *message,
+            const UA_ByteString *signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+sign_none(const UA_SecurityPolicy *securityPolicy,
+          const void *channelContext,
+          const UA_ByteString *message,
+          UA_ByteString *signature) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+length_none(const UA_SecurityPolicy *securityPolicy,
+            const void *channelContext) {
+    return 0;
+}
+
+static UA_StatusCode
+encrypt_none(const UA_SecurityPolicy *securityPolicy,
+             const void *channelContext,
+             UA_ByteString *data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+decrypt_none(const UA_SecurityPolicy *securityPolicy,
+             const void *channelContext,
+             UA_ByteString *data) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+makeThumbprint_none(const UA_SecurityPolicy *securityPolicy,
+                    const UA_ByteString *certificate,
+                    UA_ByteString *thumbprint) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+compareThumbprint_none(const UA_SecurityPolicy *securityPolicy,
+                       const UA_ByteString *certificateThumbprint) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+generateKey_none(const UA_SecurityPolicy *securityPolicy,
+                 const UA_ByteString *secret,
+                 const UA_ByteString *seed,
+                 UA_ByteString *out) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+generateNonce_none(const UA_SecurityPolicy *securityPolicy,
+                   UA_ByteString *out) {
+    out->data = UA_Byte_new();
+    if(!out->data)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    out->length = 1;
+    out->data[0] = 'a';
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+newContext_none(const UA_SecurityPolicy *securityPolicy,
+                const UA_ByteString *remoteCertificate,
+                void **channelContext) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+deleteContext_none(void *channelContext) {
+}
+
+static UA_StatusCode
+setContextValue_none(void *channelContext,
+                     const UA_ByteString *key) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+getRemoteAsymPlainTextBlockSize_none(const void *channelContext) {
+    return 0;
+}
+
+static size_t
+getRemoteAsymEncryptionBufferLengthOverhead_none(const void *channelContext,
+                                                 size_t maxEncryptionLength) {
+    return 0;
+}
+
+static UA_StatusCode
+compareCertificate_none(const void *channelContext,
+                        const UA_ByteString *certificate) {
+    return UA_STATUSCODE_GOOD;
+}
+
+static void
+policy_deletemembers_none(UA_SecurityPolicy *policy) {
+    UA_ByteString_deleteMembers(&policy->localCertificate);
+}
+
+UA_StatusCode
+UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
+                       UA_Logger logger) {
+    policy->policyContext = (void*)(uintptr_t)logger;
+    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
+    policy->logger = logger;
+    UA_ByteString_copy(&localCertificate, &policy->localCertificate);
+
+    policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none;
+    policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none;
+    policy->asymmetricModule.cryptoModule.signatureAlgorithmUri = UA_STRING_NULL;
+    policy->asymmetricModule.cryptoModule.verify = verify_none;
+    policy->asymmetricModule.cryptoModule.sign = sign_none;
+    policy->asymmetricModule.cryptoModule.getLocalSignatureSize = length_none;
+    policy->asymmetricModule.cryptoModule.getRemoteSignatureSize = length_none;
+    policy->asymmetricModule.cryptoModule.encrypt = encrypt_none;
+    policy->asymmetricModule.cryptoModule.decrypt = decrypt_none;
+    policy->asymmetricModule.cryptoModule.getLocalEncryptionKeyLength = length_none;
+    policy->asymmetricModule.cryptoModule.getRemoteEncryptionKeyLength = length_none;
+
+    policy->symmetricModule.generateKey = generateKey_none;
+    policy->symmetricModule.generateNonce = generateNonce_none;
+    policy->symmetricModule.cryptoModule.signatureAlgorithmUri = UA_STRING_NULL;
+    policy->symmetricModule.cryptoModule.verify = verify_none;
+    policy->symmetricModule.cryptoModule.sign = sign_none;
+    policy->symmetricModule.cryptoModule.getLocalSignatureSize = length_none;
+    policy->symmetricModule.cryptoModule.getRemoteSignatureSize = length_none;
+    policy->symmetricModule.cryptoModule.encrypt = encrypt_none;
+    policy->symmetricModule.cryptoModule.decrypt = decrypt_none;
+    policy->symmetricModule.cryptoModule.getLocalEncryptionKeyLength = length_none;
+    policy->symmetricModule.cryptoModule.getRemoteEncryptionKeyLength = length_none;
+    policy->symmetricModule.encryptionBlockSize = 0;
+    policy->symmetricModule.signingKeyLength = 0;
+
+    policy->channelModule.newContext = newContext_none;
+    policy->channelModule.deleteContext = deleteContext_none;
+    policy->channelModule.setLocalSymEncryptingKey = setContextValue_none;
+    policy->channelModule.setLocalSymSigningKey = setContextValue_none;
+    policy->channelModule.setLocalSymIv = setContextValue_none;
+    policy->channelModule.setRemoteSymEncryptingKey = setContextValue_none;
+    policy->channelModule.setRemoteSymSigningKey = setContextValue_none;
+    policy->channelModule.setRemoteSymIv = setContextValue_none;
+    policy->channelModule.compareCertificate = compareCertificate_none;
+    policy->channelModule.getRemoteAsymPlainTextBlockSize = getRemoteAsymPlainTextBlockSize_none;
+    policy->channelModule.getRemoteAsymEncryptionBufferLengthOverhead =
+        getRemoteAsymEncryptionBufferLengthOverhead_none;
+    policy->deleteMembers = policy_deletemembers_none;
+
+    return UA_STATUSCODE_GOOD;
+}

+ 22 - 0
plugins/ua_securitypolicy_none.h

@@ -0,0 +1,22 @@
+/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
+ * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
+
+#ifndef UA_SECURITYPOLICY_NONE_H_
+#define UA_SECURITYPOLICY_NONE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_plugin_securitypolicy.h"
+#include "ua_plugin_log.h"
+
+UA_StatusCode UA_EXPORT
+UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
+                       UA_Logger logger);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_SECURITYPOLICY_NONE_H_ */

File diff suppressed because it is too large
+ 230 - 716
src/client/ua_client.c


+ 499 - 0
src/client/ua_client_connect.c

@@ -0,0 +1,499 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ua_client.h"
+#include "ua_client_internal.h"
+#include "ua_transport_generated.h"
+#include "ua_transport_generated_handling.h"
+#include "ua_transport_generated_encoding_binary.h"
+#include "ua_types_encoding_binary.h"
+#include "ua_types_generated_encoding_binary.h"
+
+#define UA_MINMESSAGESIZE 8192
+
+ /***********************/
+ /* Open the Connection */
+ /***********************/
+
+static UA_StatusCode
+processACKResponse(void *application, UA_Connection *connection, UA_ByteString *chunk) {
+    UA_Client *client = (UA_Client*)application;
+
+    /* Decode the message */
+    size_t offset = 0;
+    UA_StatusCode retval;
+    UA_TcpMessageHeader messageHeader;
+    UA_TcpAcknowledgeMessage ackMessage;
+    retval = UA_TcpMessageHeader_decodeBinary(chunk, &offset, &messageHeader);
+    retval |= UA_TcpAcknowledgeMessage_decodeBinary(chunk, &offset, &ackMessage);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
+                    "Decoding ACK message failed");
+        return retval;
+    }
+
+    /* Store remote connection settings and adjust local configuration to not
+     * exceed the limits */
+    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK, "Received ACK message");
+    connection->remoteConf.maxChunkCount = ackMessage.maxChunkCount; /* may be zero -> unlimited */
+    connection->remoteConf.maxMessageSize = ackMessage.maxMessageSize; /* may be zero -> unlimited */
+    connection->remoteConf.protocolVersion = ackMessage.protocolVersion;
+    connection->remoteConf.sendBufferSize = ackMessage.sendBufferSize;
+    connection->remoteConf.recvBufferSize = ackMessage.receiveBufferSize;
+    if(connection->remoteConf.recvBufferSize < connection->localConf.sendBufferSize)
+        connection->localConf.sendBufferSize = connection->remoteConf.recvBufferSize;
+    if(connection->remoteConf.sendBufferSize < connection->localConf.recvBufferSize)
+        connection->localConf.recvBufferSize = connection->remoteConf.sendBufferSize;
+    connection->state = UA_CONNECTION_ESTABLISHED;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+HelAckHandshake(UA_Client *client) {
+    /* Get a buffer */
+    UA_ByteString message;
+    UA_Connection *conn = &client->connection;
+    UA_StatusCode retval = conn->getSendBuffer(conn, UA_MINMESSAGESIZE, &message);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    /* Prepare the HEL message and encode at offset 8 */
+    UA_TcpHelloMessage hello;
+    UA_String_copy(&client->endpointUrl, &hello.endpointUrl); /* must be less than 4096 bytes */
+    hello.maxChunkCount = conn->localConf.maxChunkCount;
+    hello.maxMessageSize = conn->localConf.maxMessageSize;
+    hello.protocolVersion = conn->localConf.protocolVersion;
+    hello.receiveBufferSize = conn->localConf.recvBufferSize;
+    hello.sendBufferSize = conn->localConf.sendBufferSize;
+
+    UA_Byte *bufPos = &message.data[8]; /* skip the header */
+    const UA_Byte *bufEnd = &message.data[message.length];
+    retval = UA_TcpHelloMessage_encodeBinary(&hello, &bufPos, &bufEnd);
+    UA_TcpHelloMessage_deleteMembers(&hello);
+
+    /* Encode the message header at offset 0 */
+    UA_TcpMessageHeader messageHeader;
+    messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_HEL;
+    messageHeader.messageSize = (UA_UInt32)((uintptr_t)bufPos - (uintptr_t)message.data);
+    bufPos = message.data;
+    retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &bufPos, &bufEnd);
+    if(retval != UA_STATUSCODE_GOOD) {
+        conn->releaseSendBuffer(conn, &message);
+        return retval;
+    }
+
+    /* Send the HEL message */
+    message.length = messageHeader.messageSize;
+    retval = conn->send(conn, &message);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
+                    "Sending HEL failed");
+        return retval;
+    }
+    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_NETWORK,
+                 "Sent HEL message");
+
+    /* Loop until we have a complete chunk */
+    retval = UA_Connection_receiveChunksBlocking(conn, client, processACKResponse,
+                                                 client->config.timeout);
+    if(retval != UA_STATUSCODE_GOOD)
+        UA_LOG_INFO(client->config.logger, UA_LOGCATEGORY_NETWORK,
+                    "Receiving ACK message failed");
+    return retval;
+}
+
+static void
+processDecodedOPNResponse(UA_Client *client, UA_OpenSecureChannelResponse *response) {
+    /* Replace the token */
+    UA_ChannelSecurityToken_deleteMembers(&client->channel.securityToken);
+    client->channel.securityToken = response->securityToken;
+    UA_ChannelSecurityToken_deleteMembers(&response->securityToken);
+
+    /* Replace the nonce */
+    UA_ByteString_deleteMembers(&client->channel.remoteNonce);
+    client->channel.remoteNonce = response->serverNonce;
+    UA_ByteString_deleteMembers(&response->serverNonce);
+
+    if(client->channel.state == UA_SECURECHANNELSTATE_OPEN)
+        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                     "SecureChannel in the server renewed");
+    else
+        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                     "Opened SecureChannel acknowledged by the server");
+
+    /* Response.securityToken.revisedLifetime is UInt32 we need to cast it to
+     * DateTime=Int64 we take 75% of lifetime to start renewing as described in
+     * standard */
+    client->channel.state = UA_SECURECHANNELSTATE_OPEN;
+    client->nextChannelRenewal = UA_DateTime_nowMonotonic() + (UA_DateTime)
+        (response->securityToken.revisedLifetime * (UA_Double)UA_MSEC_TO_DATETIME * 0.75);
+}
+
+static UA_StatusCode
+openSecureChannel(UA_Client *client, UA_Boolean renew) {
+    /* Check if sc is still valid */
+    if(renew && client->nextChannelRenewal - UA_DateTime_nowMonotonic() > 0)
+        return UA_STATUSCODE_GOOD;
+
+    UA_Connection *conn = &client->connection;
+    if(conn->state != UA_CONNECTION_ESTABLISHED)
+        return UA_STATUSCODE_BADSERVERNOTCONNECTED;
+
+    /* Prepare the OpenSecureChannelRequest */
+    UA_OpenSecureChannelRequest opnSecRq;
+    UA_OpenSecureChannelRequest_init(&opnSecRq);
+    opnSecRq.requestHeader.timestamp = UA_DateTime_now();
+    opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
+    if(renew) {
+        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
+        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                     "Requesting to renew the SecureChannel");
+    } else {
+        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
+        UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                     "Requesting to open a SecureChannel");
+    }
+    opnSecRq.securityMode = UA_MESSAGESECURITYMODE_NONE;
+    opnSecRq.clientNonce = client->channel.localNonce;
+    opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
+
+    /* Send the OPN message */
+    UA_UInt32 requestId = ++client->requestId;
+    UA_StatusCode retval =
+        UA_SecureChannel_sendAsymmetricOPNMessage(&client->channel, requestId, &opnSecRq,
+                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
+                     "Sending OPN message failed with error %s", UA_StatusCode_name(retval));
+        UA_Client_disconnect(client);
+        return retval;
+    }
+
+    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_SECURECHANNEL, "OPN message sent");
+
+    /* Receive / decrypt / decode the OPN response. Process async services in
+     * the background until the OPN response arrives. */
+    UA_OpenSecureChannelResponse response;
+    retval = receiveServiceResponse(client, &response,
+                                    &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE],
+                                    UA_DateTime_nowMonotonic() +
+                                    ((UA_DateTime)client->config.timeout * UA_MSEC_TO_DATETIME),
+                                    &requestId);
+                                    
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Client_disconnect(client);
+        return retval;
+    }
+
+    processDecodedOPNResponse(client, &response);
+    UA_OpenSecureChannelResponse_deleteMembers(&response);
+    return retval;
+}
+
+static UA_StatusCode
+activateSession(UA_Client *client) {
+    UA_ActivateSessionRequest request;
+    UA_ActivateSessionRequest_init(&request);
+    request.requestHeader.requestHandle = ++client->requestHandle;
+    request.requestHeader.timestamp = UA_DateTime_now();
+    request.requestHeader.timeoutHint = 600000;
+
+    //manual ExtensionObject encoding of the identityToken
+    if(client->authenticationMethod == UA_CLIENTAUTHENTICATION_NONE) {
+        UA_AnonymousIdentityToken* identityToken = UA_AnonymousIdentityToken_new();
+        UA_AnonymousIdentityToken_init(identityToken);
+        UA_String_copy(&client->token.policyId, &identityToken->policyId);
+        request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED;
+        request.userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN];
+        request.userIdentityToken.content.decoded.data = identityToken;
+    } else {
+        UA_UserNameIdentityToken* identityToken = UA_UserNameIdentityToken_new();
+        UA_UserNameIdentityToken_init(identityToken);
+        UA_String_copy(&client->token.policyId, &identityToken->policyId);
+        UA_String_copy(&client->username, &identityToken->userName);
+        UA_String_copy(&client->password, &identityToken->password);
+        request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED;
+        request.userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN];
+        request.userIdentityToken.content.decoded.data = identityToken;
+    }
+
+    UA_ActivateSessionResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]);
+
+    if(response.responseHeader.serviceResult) {
+        UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                     "ActivateSession failed with error code %s",
+                     UA_StatusCode_name(response.responseHeader.serviceResult));
+    }
+
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    UA_ActivateSessionRequest_deleteMembers(&request);
+    UA_ActivateSessionResponse_deleteMembers(&response);
+    return retval;
+}
+
+/* Gets a list of endpoints. Memory is allocated for endpointDescription array */
+UA_StatusCode
+UA_Client_getEndpointsInternal(UA_Client *client, size_t* endpointDescriptionsSize,
+                               UA_EndpointDescription** endpointDescriptions) {
+    UA_GetEndpointsRequest request;
+    UA_GetEndpointsRequest_init(&request);
+    request.requestHeader.timestamp = UA_DateTime_now();
+    request.requestHeader.timeoutHint = 10000;
+    // assume the endpointurl outlives the service call
+    request.endpointUrl = client->endpointUrl;
+
+    UA_GetEndpointsResponse response;
+    UA_GetEndpointsResponse_init(&response);
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
+
+    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
+        UA_StatusCode retval = response.responseHeader.serviceResult;
+        UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                     "GetEndpointRequest failed with error code %s",
+                     UA_StatusCode_name(retval));
+        UA_GetEndpointsResponse_deleteMembers(&response);
+        return retval;
+    }
+    *endpointDescriptions = response.endpoints;
+    *endpointDescriptionsSize = response.endpointsSize;
+    response.endpoints = NULL;
+    response.endpointsSize = 0;
+    UA_GetEndpointsResponse_deleteMembers(&response);
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+getEndpoints(UA_Client *client) {
+    UA_EndpointDescription* endpointArray = NULL;
+    size_t endpointArraySize = 0;
+    UA_StatusCode retval =
+        UA_Client_getEndpointsInternal(client, &endpointArraySize, &endpointArray);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    UA_Boolean endpointFound = false;
+    UA_Boolean tokenFound = false;
+    UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
+    UA_String binaryTransport = UA_STRING("http://opcfoundation.org/UA-Profile/"
+                                          "Transport/uatcp-uasc-uabinary");
+
+    // TODO: compare endpoint information with client->endpointUri
+    for(size_t i = 0; i < endpointArraySize; ++i) {
+        UA_EndpointDescription* endpoint = &endpointArray[i];
+        /* look out for binary transport endpoints */
+        /* Note: Siemens returns empty ProfileUrl, we will accept it as binary */
+        if(endpoint->transportProfileUri.length != 0 &&
+           !UA_String_equal(&endpoint->transportProfileUri, &binaryTransport))
+            continue;
+        /* look out for an endpoint without security */
+        if(!UA_String_equal(&endpoint->securityPolicyUri, &securityNone))
+            continue;
+
+        /* endpoint with no security found */
+        endpointFound = true;
+
+        /* look for a user token policy with an anonymous token */
+        for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) {
+            UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
+
+            /* Usertokens also have a security policy... */
+            if(userToken->securityPolicyUri.length > 0 &&
+               !UA_String_equal(&userToken->securityPolicyUri, &securityNone))
+                continue;
+
+            /* UA_CLIENTAUTHENTICATION_NONE == UA_USERTOKENTYPE_ANONYMOUS
+             * UA_CLIENTAUTHENTICATION_USERNAME == UA_USERTOKENTYPE_USERNAME
+             * TODO: Check equivalence for other types when adding the support */
+            if((int)client->authenticationMethod != (int)userToken->tokenType)
+                continue;
+
+            /* Endpoint with matching usertokenpolicy found */
+            tokenFound = true;
+            UA_UserTokenPolicy_deleteMembers(&client->token);
+            UA_UserTokenPolicy_copy(userToken, &client->token);
+            break;
+        }
+    }
+
+    UA_Array_delete(endpointArray, endpointArraySize,
+                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
+
+    if(!endpointFound) {
+        UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                     "No suitable endpoint found");
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    } else if(!tokenFound) {
+        UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                     "No suitable UserTokenPolicy found for the possible endpoints");
+        retval = UA_STATUSCODE_BADINTERNALERROR;
+    }
+    return retval;
+}
+
+static UA_StatusCode
+createSession(UA_Client *client) {
+    UA_CreateSessionRequest request;
+    UA_CreateSessionRequest_init(&request);
+
+    request.requestHeader.timestamp = UA_DateTime_now();
+    request.requestHeader.timeoutHint = 10000;
+    UA_ByteString_copy(&client->channel.localNonce, &request.clientNonce);
+    request.requestedSessionTimeout = 1200000;
+    request.maxResponseMessageSize = UA_INT32_MAX;
+    UA_String_copy(&client->endpointUrl, &request.endpointUrl);
+
+    UA_CreateSessionResponse response;
+    UA_CreateSessionResponse_init(&response);
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]);
+
+    UA_NodeId_copy(&response.authenticationToken, &client->authenticationToken);
+
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    UA_CreateSessionRequest_deleteMembers(&request);
+    UA_CreateSessionResponse_deleteMembers(&response);
+    return retval;
+}
+
+UA_StatusCode
+UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
+                          UA_Boolean endpointsHandshake, UA_Boolean createNewSession) {
+    UA_ChannelSecurityToken_init(&client->channel.securityToken);
+    client->channel.state = UA_SECURECHANNELSTATE_FRESH;
+
+    if(client->state >= UA_CLIENTSTATE_CONNECTED)
+        return UA_STATUSCODE_GOOD;
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    client->connection =
+        client->config.connectionFunc(client->config.localConnectionConfig,
+                                      endpointUrl, client->config.timeout);
+    if(client->connection.state != UA_CONNECTION_OPENING) {
+        retval = UA_STATUSCODE_BADCONNECTIONCLOSED;
+        goto cleanup;
+    }
+
+    UA_String_deleteMembers(&client->endpointUrl);
+    client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
+    if(!client->endpointUrl.data) {
+        retval = UA_STATUSCODE_BADOUTOFMEMORY;
+        goto cleanup;
+    }
+
+    /* Open a TCP connection */
+    client->connection.localConf = client->config.localConnectionConfig;
+    retval = HelAckHandshake(client);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto cleanup;
+    client->state = UA_CLIENTSTATE_CONNECTED;
+
+    /* Open a SecureChannel. TODO: Select with endpoint  */
+    client->channel.connection = &client->connection;
+    retval = openSecureChannel(client, false);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto cleanup;
+    client->state = UA_CLIENTSTATE_SECURECHANNEL;
+
+    /* Get Endpoints */
+    if(endpointsHandshake) {
+        retval = getEndpoints(client);
+        if(retval != UA_STATUSCODE_GOOD)
+            goto cleanup;
+    }
+
+    /* Open a Session */
+    if(createNewSession) {
+        retval = createSession(client);
+        if(retval != UA_STATUSCODE_GOOD)
+            goto cleanup;
+        retval = activateSession(client);
+        if(retval != UA_STATUSCODE_GOOD)
+            goto cleanup;
+        client->state = UA_CLIENTSTATE_SESSION;
+    }
+    return retval;
+
+cleanup:
+    UA_Client_disconnect(client);
+    return retval;
+}
+
+UA_StatusCode
+UA_Client_connect(UA_Client *client, const char *endpointUrl) {
+    return UA_Client_connectInternal(client, endpointUrl, UA_TRUE, UA_TRUE);
+}
+
+UA_StatusCode
+UA_Client_connect_username(UA_Client *client, const char *endpointUrl,
+                           const char *username, const char *password) {
+    client->authenticationMethod = UA_CLIENTAUTHENTICATION_USERNAME;
+    client->username = UA_STRING_ALLOC(username);
+    client->password = UA_STRING_ALLOC(password);
+    return UA_Client_connect(client, endpointUrl);
+}
+
+UA_StatusCode
+UA_Client_manuallyRenewSecureChannel(UA_Client *client) {
+    UA_StatusCode retval = openSecureChannel(client, true);
+    if(retval != UA_STATUSCODE_GOOD)
+        client->state = UA_CLIENTSTATE_DISCONNECTED;
+    return retval;
+}
+
+/************************/
+/* Close the Connection */
+/************************/
+
+static void
+sendCloseSession(UA_Client *client) {
+    UA_CloseSessionRequest request;
+    UA_CloseSessionRequest_init(&request);
+
+    request.requestHeader.timestamp = UA_DateTime_now();
+    request.requestHeader.timeoutHint = 10000;
+    request.deleteSubscriptions = true;
+    UA_CloseSessionResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
+    UA_CloseSessionRequest_deleteMembers(&request);
+    UA_CloseSessionResponse_deleteMembers(&response);
+}
+
+static void
+sendCloseSecureChannel(UA_Client *client) {
+    UA_SecureChannel *channel = &client->channel;
+    UA_CloseSecureChannelRequest request;
+    UA_CloseSecureChannelRequest_init(&request);
+    request.requestHeader.requestHandle = ++client->requestHandle;
+    request.requestHeader.timestamp = UA_DateTime_now();
+    request.requestHeader.timeoutHint = 10000;
+    request.requestHeader.authenticationToken = client->authenticationToken;
+    UA_SecureChannel_sendSymmetricMessage(channel, ++client->requestId,
+                                          UA_MESSAGETYPE_CLO, &request,
+                                          &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]);
+    UA_SecureChannel_deleteMembersCleanup(&client->channel);
+}
+
+UA_StatusCode
+UA_Client_disconnect(UA_Client *client) {
+    /* Is a session established? */
+    if(client->state == UA_CLIENTSTATE_SESSION){
+        client->state = UA_CLIENTSTATE_SESSION_DISCONNECTED;
+        sendCloseSession(client);
+    }
+
+    /* Is a secure channel established? */
+    if(client->state >= UA_CLIENTSTATE_SECURECHANNEL)
+        sendCloseSecureChannel(client);
+
+    /* Close the TCP connection */
+    if(client->state >= UA_CLIENTSTATE_CONNECTED)
+        client->connection.close(&client->connection);
+
+    client->state = UA_CLIENTSTATE_DISCONNECTED;
+    return UA_STATUSCODE_GOOD;
+}

+ 133 - 0
src/client/ua_client_discovery.c

@@ -0,0 +1,133 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ua_client.h"
+#include "ua_client_internal.h"
+
+UA_StatusCode
+UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
+                       size_t* endpointDescriptionsSize,
+                       UA_EndpointDescription** endpointDescriptions) {
+    UA_Boolean connected = (client->state > UA_CLIENTSTATE_DISCONNECTED);
+    /* Client is already connected to a different server */
+    if(connected && strncmp((const char*)client->endpointUrl.data, serverUrl,
+                            client->endpointUrl.length) != 0) {
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
+
+    UA_StatusCode retval;
+    if(!connected) {
+        retval = UA_Client_connectInternal(client, serverUrl, UA_FALSE, UA_FALSE);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+    retval = UA_Client_getEndpointsInternal(client, endpointDescriptionsSize, endpointDescriptions);
+
+    if(!connected)
+        UA_Client_disconnect(client);
+    return retval;
+}
+
+UA_StatusCode
+UA_Client_findServers(UA_Client *client, const char *serverUrl,
+                      size_t serverUrisSize, UA_String *serverUris,
+                      size_t localeIdsSize, UA_String *localeIds,
+                      size_t *registeredServersSize,
+                      UA_ApplicationDescription **registeredServers) {
+    UA_Boolean connected = (client->state > UA_CLIENTSTATE_DISCONNECTED);
+    /* Client is already connected to a different server */
+    if(connected && strncmp((const char*)client->endpointUrl.data, serverUrl,
+                            client->endpointUrl.length) != 0) {
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
+
+    if(!connected) {
+        UA_StatusCode retval = UA_Client_connectInternal(client, serverUrl, UA_TRUE, UA_FALSE);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
+    /* Prepare the request */
+    UA_FindServersRequest request;
+    UA_FindServersRequest_init(&request);
+    request.serverUrisSize = serverUrisSize;
+    request.serverUris = serverUris;
+    request.localeIdsSize = localeIdsSize;
+    request.localeIds = localeIds;
+
+    /* Send the request */
+    UA_FindServersResponse response;
+    UA_FindServersResponse_init(&response);
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]);
+
+    /* Process the response */
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval == UA_STATUSCODE_GOOD) {
+        *registeredServersSize = response.serversSize;
+        *registeredServers = response.servers;
+        response.serversSize = 0;
+        response.servers = NULL;
+    } else {
+        *registeredServersSize = 0;
+        *registeredServers = NULL;
+    }
+
+    /* Clean up */
+    UA_FindServersResponse_deleteMembers(&response);
+    if(!connected)
+        UA_Client_disconnect(client);
+    return retval;
+}
+
+UA_StatusCode
+UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl,
+                               UA_UInt32 startingRecordId, UA_UInt32 maxRecordsToReturn,
+                               size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter,
+                               size_t *serverOnNetworkSize, UA_ServerOnNetwork **serverOnNetwork) {
+    UA_Boolean connected = (client->state > UA_CLIENTSTATE_DISCONNECTED);
+    /* Client is already connected to a different server */
+    if(connected && strncmp((const char*)client->endpointUrl.data, serverUrl,
+                            client->endpointUrl.length) != 0) {
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    }
+
+    if(!connected) {
+        UA_StatusCode retval = UA_Client_connectInternal(client, serverUrl, UA_TRUE, UA_FALSE);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
+    /* Prepare the request */
+    UA_FindServersOnNetworkRequest request;
+    UA_FindServersOnNetworkRequest_init(&request);
+    request.startingRecordId = startingRecordId;
+    request.maxRecordsToReturn = maxRecordsToReturn;
+    request.serverCapabilityFilterSize = serverCapabilityFilterSize;
+    request.serverCapabilityFilter = serverCapabilityFilter;
+
+    /* Send the request */
+    UA_FindServersOnNetworkResponse response;
+    UA_FindServersOnNetworkResponse_init(&response);
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]);
+
+    /* Process the response */
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval == UA_STATUSCODE_GOOD) {
+        *serverOnNetworkSize = response.serversSize;
+        *serverOnNetwork = response.servers;
+        response.serversSize = 0;
+        response.servers = NULL;
+    } else {
+        *serverOnNetworkSize = 0;
+        *serverOnNetwork = NULL;
+    }
+
+    /* Clean up */
+    UA_FindServersOnNetworkResponse_deleteMembers(&response);
+    if(!connected)
+        UA_Client_disconnect(client);
+    return retval;
+}

+ 74 - 75
src/client/ua_client_highlevel.c

@@ -1,11 +1,10 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "ua_client.h"
 #include "ua_client.h"
 #include "ua_client_highlevel.h"
 #include "ua_client_highlevel.h"
 #include "ua_util.h"
 #include "ua_util.h"
-#include "ua_nodeids.h"
 
 
 UA_StatusCode
 UA_StatusCode
 UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
 UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
@@ -35,7 +34,7 @@ UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
     }
     }
 
 
     retval = UA_STATUSCODE_BADNOTFOUND;
     retval = UA_STATUSCODE_BADNOTFOUND;
-    UA_String *ns = response.results[0].value.data;
+    UA_String *ns = (UA_String *)response.results[0].value.data;
     for(size_t i = 0; i < response.results[0].value.arrayLength; ++i){
     for(size_t i = 0; i < response.results[0].value.arrayLength; ++i){
         if(UA_String_equal(namespaceUri, &ns[i])) {
         if(UA_String_equal(namespaceUri, &ns[i])) {
             *namespaceIndex = (UA_UInt16)i;
             *namespaceIndex = (UA_UInt16)i;
@@ -51,35 +50,31 @@ UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
 UA_StatusCode
 UA_StatusCode
 UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId,
 UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId,
                                UA_NodeIteratorCallback callback, void *handle) {
                                UA_NodeIteratorCallback callback, void *handle) {
-  UA_BrowseRequest bReq;
-  UA_BrowseRequest_init(&bReq);
-  bReq.requestedMaxReferencesPerNode = 0;
-  bReq.nodesToBrowse = UA_BrowseDescription_new();
-  bReq.nodesToBrowseSize = 1;
-  UA_NodeId_copy(&parentNodeId, &bReq.nodesToBrowse[0].nodeId);
-  bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything
-  bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;
-
-  UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
-
-  UA_StatusCode retval = UA_STATUSCODE_GOOD;
-  if(bResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
-      for (size_t i = 0; i < bResp.resultsSize; ++i) {
-          for (size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
-              UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
-              retval |= callback(ref->nodeId.nodeId, !ref->isForward,
-                                 ref->referenceTypeId, handle);
-          }
-      }
-  }
-  else
-      retval = bResp.responseHeader.serviceResult;
-
-
-  UA_BrowseRequest_deleteMembers(&bReq);
-  UA_BrowseResponse_deleteMembers(&bResp);
-
-  return retval;
+    UA_BrowseRequest bReq;
+    UA_BrowseRequest_init(&bReq);
+    bReq.requestedMaxReferencesPerNode = 0;
+    bReq.nodesToBrowse = UA_BrowseDescription_new();
+    bReq.nodesToBrowseSize = 1;
+    UA_NodeId_copy(&parentNodeId, &bReq.nodesToBrowse[0].nodeId);
+    bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything
+    bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;
+
+    UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
+
+    UA_StatusCode retval = bResp.responseHeader.serviceResult;
+    if(retval == UA_STATUSCODE_GOOD) {
+        for(size_t i = 0; i < bResp.resultsSize; ++i) {
+            for(size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
+                UA_ReferenceDescription *ref = &bResp.results[i].references[j];
+                retval |= callback(ref->nodeId.nodeId, !ref->isForward,
+                                   ref->referenceTypeId, handle);
+            }
+        }
+    }
+
+    UA_BrowseRequest_deleteMembers(&bReq);
+    UA_BrowseResponse_deleteMembers(&bResp);
+    return retval;
 }
 }
 
 
 /*******************/
 /*******************/
@@ -182,7 +177,6 @@ __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
                     const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_AddNodesRequest request;
     UA_AddNodesRequest request;
     UA_AddNodesRequest_init(&request);
     UA_AddNodesRequest_init(&request);
     UA_AddNodesItem item;
     UA_AddNodesItem item;
@@ -199,20 +193,25 @@ __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
     request.nodesToAdd = &item;
     request.nodesToAdd = &item;
     request.nodesToAddSize = 1;
     request.nodesToAddSize = 1;
     UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);
     UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);
-    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
-        retval = response.responseHeader.serviceResult;
+
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_AddNodesResponse_deleteMembers(&response);
         UA_AddNodesResponse_deleteMembers(&response);
         return retval;
         return retval;
     }
     }
+
     if(response.resultsSize != 1) {
     if(response.resultsSize != 1) {
         UA_AddNodesResponse_deleteMembers(&response);
         UA_AddNodesResponse_deleteMembers(&response);
         return UA_STATUSCODE_BADUNEXPECTEDERROR;
         return UA_STATUSCODE_BADUNEXPECTEDERROR;
     }
     }
-    if(outNewNodeId && response.results[0].statusCode == UA_STATUSCODE_GOOD) {
+
+    /* Move the id of the created node */
+    retval = response.results[0].statusCode;
+    if(retval == UA_STATUSCODE_GOOD && outNewNodeId) {
         *outNewNodeId = response.results[0].addedNodeId;
         *outNewNodeId = response.results[0].addedNodeId;
         UA_NodeId_init(&response.results[0].addedNodeId);
         UA_NodeId_init(&response.results[0].addedNodeId);
     }
     }
-    retval = response.results[0].statusCode;
+
     UA_AddNodesResponse_deleteMembers(&response);
     UA_AddNodesResponse_deleteMembers(&response);
     return retval;
     return retval;
 }
 }
@@ -235,7 +234,7 @@ UA_Client_call(UA_Client *client, const UA_NodeId objectId,
     UA_CallMethodRequest_init(&item);
     UA_CallMethodRequest_init(&item);
     item.methodId = methodId;
     item.methodId = methodId;
     item.objectId = objectId;
     item.objectId = objectId;
-    item.inputArguments = (void*)(uintptr_t)input; // cast const...
+    item.inputArguments = (UA_Variant *)(void*)(uintptr_t)input; // cast const...
     item.inputArgumentsSize = inputSize;
     item.inputArgumentsSize = inputSize;
     request.methodsToCall = &item;
     request.methodsToCall = &item;
     request.methodsToCallSize = 1;
     request.methodsToCallSize = 1;
@@ -309,8 +308,8 @@ __UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,
 
 
 UA_StatusCode
 UA_StatusCode
 UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
 UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                        const UA_UInt32 *newArrayDimensions,
-                                        size_t newArrayDimensionsSize) {
+                                        size_t newArrayDimensionsSize,
+                                        const UA_UInt32 *newArrayDimensions) {
     if(!newArrayDimensions)
     if(!newArrayDimensions)
       return UA_STATUSCODE_BADTYPEMISMATCH;
       return UA_STATUSCODE_BADTYPEMISMATCH;
 
 
@@ -400,10 +399,39 @@ __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
     return retval;
     return retval;
 }
 }
 
 
+static UA_StatusCode
+processReadArrayDimensionsResult(UA_ReadResponse *response,
+                                 UA_UInt32 **outArrayDimensions,
+                                 size_t *outArrayDimensionsSize) {
+    UA_StatusCode retval = response->responseHeader.serviceResult;
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    if(response->resultsSize != 1)
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+
+    retval = response->results[0].status;
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    UA_DataValue *res = &response->results[0];
+    if(!res->hasValue ||
+       UA_Variant_isScalar(&res->value) ||
+       res->value.type != &UA_TYPES[UA_TYPES_UINT32])
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+
+    /* Move results */
+    *outArrayDimensions = (UA_UInt32*)res->value.data;
+    *outArrayDimensionsSize = res->value.arrayLength;
+    res->value.data = NULL;
+    res->value.arrayLength = 0;
+    return UA_STATUSCODE_GOOD;
+}
+
 UA_StatusCode
 UA_StatusCode
 UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
 UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                       UA_UInt32 **outArrayDimensions,
-                                       size_t *outArrayDimensionsSize) {
+                                       size_t *outArrayDimensionsSize,
+                                       UA_UInt32 **outArrayDimensions) {
     UA_ReadValueId item;
     UA_ReadValueId item;
     UA_ReadValueId_init(&item);
     UA_ReadValueId_init(&item);
     item.nodeId = nodeId;
     item.nodeId = nodeId;
@@ -412,39 +440,10 @@ UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId
     UA_ReadRequest_init(&request);
     UA_ReadRequest_init(&request);
     request.nodesToRead = &item;
     request.nodesToRead = &item;
     request.nodesToReadSize = 1;
     request.nodesToReadSize = 1;
-    UA_ReadResponse response = UA_Client_Service_read(client, request);
-    UA_StatusCode retval = response.responseHeader.serviceResult;
-    if(retval == UA_STATUSCODE_GOOD) {
-        if(response.resultsSize == 1)
-            retval = response.results[0].status;
-        else
-            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
-    }
-    if(retval != UA_STATUSCODE_GOOD)
-        goto cleanup;
 
 
-    UA_DataValue *res = response.results;
-    if(res->hasStatus != UA_STATUSCODE_GOOD)
-        retval = res->hasStatus;
-    else if(!res->hasValue || UA_Variant_isScalar(&res->value))
-        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
-    if(retval != UA_STATUSCODE_GOOD)
-        goto cleanup;
-
-    if(UA_Variant_isScalar(&res->value) ||
-       res->value.type != &UA_TYPES[UA_TYPES_UINT32]) {
-        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
-        goto cleanup;
-    }
-
-    /* Move data out of the results structure instead of copying */
-    *outArrayDimensions = res->value.data;
-    *outArrayDimensionsSize = res->value.arrayLength;
-    res->value.data = NULL;
-    res->value.arrayLength = 0;
-
- cleanup:
+    UA_ReadResponse response = UA_Client_Service_read(client, request);
+    UA_StatusCode retval = processReadArrayDimensionsResult(&response, outArrayDimensions,
+                                                            outArrayDimensionsSize);
     UA_ReadResponse_deleteMembers(&response);
     UA_ReadResponse_deleteMembers(&response);
     return retval;
     return retval;
-
 }
 }

+ 153 - 56
src/client/ua_client_highlevel_subscriptions.c

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "ua_client_highlevel.h"
 #include "ua_client_highlevel.h"
 #include "ua_client_internal.h"
 #include "ua_client_internal.h"
@@ -22,13 +22,15 @@ UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
 
 
     UA_CreateSubscriptionResponse response = UA_Client_Service_createSubscription(client, request);
     UA_CreateSubscriptionResponse response = UA_Client_Service_createSubscription(client, request);
     UA_StatusCode retval = response.responseHeader.serviceResult;
     UA_StatusCode retval = response.responseHeader.serviceResult;
-    if(retval != UA_STATUSCODE_GOOD)
-        goto cleanup;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_CreateSubscriptionResponse_deleteMembers(&response);
+        return retval;
+    }
 
 
-    UA_Client_Subscription *newSub = UA_malloc(sizeof(UA_Client_Subscription));
+    UA_Client_Subscription *newSub = (UA_Client_Subscription *)UA_malloc(sizeof(UA_Client_Subscription));
     if(!newSub) {
     if(!newSub) {
-        retval = UA_STATUSCODE_BADOUTOFMEMORY;
-        goto cleanup;
+        UA_CreateSubscriptionResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     }
     }
 
 
     LIST_INIT(&newSub->monitoredItems);
     LIST_INIT(&newSub->monitoredItems);
@@ -43,19 +45,24 @@ UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
     if(newSubscriptionId)
     if(newSubscriptionId)
         *newSubscriptionId = newSub->subscriptionID;
         *newSubscriptionId = newSub->subscriptionID;
 
 
- cleanup:
     UA_CreateSubscriptionResponse_deleteMembers(&response);
     UA_CreateSubscriptionResponse_deleteMembers(&response);
-    return retval;
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-/* remove the subscription remotely */
-UA_StatusCode
-UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
-    UA_Client_Subscription *sub;
+static UA_Client_Subscription *findSubscription(const UA_Client *client, UA_UInt32 subscriptionId)
+{
+    UA_Client_Subscription *sub = NULL;
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
     LIST_FOREACH(sub, &client->subscriptions, listEntry) {
         if(sub->subscriptionID == subscriptionId)
         if(sub->subscriptionID == subscriptionId)
             break;
             break;
     }
     }
+    return sub;
+}
+
+/* remove the subscription remotely */
+UA_StatusCode
+UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
+    UA_Client_Subscription *sub = findSubscription(client, subscriptionId);
     if(!sub)
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
 
@@ -104,21 +111,104 @@ UA_Client_Subscriptions_forceDelete(UA_Client *client,
     UA_free(sub);
     UA_free(sub);
 }
 }
 
 
+UA_StatusCode
+UA_Client_Subscriptions_addMonitoredEvent(UA_Client *client, const UA_UInt32 subscriptionId,
+                                         const UA_NodeId nodeId, const UA_UInt32 attributeID,
+                                         UA_SimpleAttributeOperand *selectClause,
+                                         const size_t nSelectClauses,
+                                         UA_ContentFilterElement *whereClause,
+                                         const size_t nWhereClauses,
+                                         const UA_MonitoredEventHandlingFunction hf,
+                                         void *hfContext, UA_UInt32 *newMonitoredItemId) {
+    UA_Client_Subscription *sub = findSubscription(client, subscriptionId);
+    if(!sub)
+        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
+
+    /* Send the request */
+    UA_CreateMonitoredItemsRequest request;
+    UA_CreateMonitoredItemsRequest_init(&request);
+    request.subscriptionId = subscriptionId;
+
+    UA_MonitoredItemCreateRequest item;
+    UA_MonitoredItemCreateRequest_init(&item);
+    item.itemToMonitor.nodeId = nodeId;
+    item.itemToMonitor.attributeId = attributeID;
+    item.monitoringMode = UA_MONITORINGMODE_REPORTING;
+    item.requestedParameters.clientHandle = ++(client->monitoredItemHandles);
+    item.requestedParameters.samplingInterval = 0;
+    item.requestedParameters.discardOldest = false;
+
+    UA_EventFilter *evFilter = UA_EventFilter_new();
+    if(!evFilter) {
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+    UA_EventFilter_init(evFilter);
+    evFilter->selectClausesSize = nSelectClauses;
+    evFilter->selectClauses = selectClause;
+    evFilter->whereClause.elementsSize = nWhereClauses;
+    evFilter->whereClause.elements = whereClause;
+
+    item.requestedParameters.filter.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
+    item.requestedParameters.filter.content.decoded.type = &UA_TYPES[UA_TYPES_EVENTFILTER];
+    item.requestedParameters.filter.content.decoded.data = evFilter;
+
+    request.itemsToCreate = &item;
+    request.itemsToCreateSize = 1;
+    UA_CreateMonitoredItemsResponse response = UA_Client_Service_createMonitoredItems(client, request);
+
+    // slight misuse of retval here to check if the deletion was successfull.
+    UA_StatusCode retval;
+    if(response.resultsSize == 0)
+        retval = response.responseHeader.serviceResult;
+    else
+        retval = response.results[0].statusCode;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_CreateMonitoredItemsResponse_deleteMembers(&response);
+        UA_EventFilter_delete(evFilter);
+        return retval;
+    }
+
+    /* Create the handler */
+    UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem *)UA_malloc(sizeof(UA_Client_MonitoredItem));
+    if(!newMon) {
+        UA_CreateMonitoredItemsResponse_deleteMembers(&response);
+        UA_EventFilter_delete(evFilter);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    newMon->monitoringMode = UA_MONITORINGMODE_REPORTING;
+    UA_NodeId_copy(&nodeId, &newMon->monitoredNodeId);
+    newMon->attributeID = attributeID;
+    newMon->clientHandle = client->monitoredItemHandles;
+    newMon->samplingInterval = 0;
+    newMon->queueSize = 0;
+    newMon->discardOldest = false;
+
+    newMon->handlerEvents = hf;
+    newMon->handlerEventsContext = hfContext;
+    newMon->monitoredItemId = response.results[0].monitoredItemId;
+    LIST_INSERT_HEAD(&sub->monitoredItems, newMon, listEntry);
+    *newMonitoredItemId = newMon->monitoredItemId;
+
+    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                 "Created a monitored item with client handle %u", client->monitoredItemHandles);
+
+    UA_EventFilter_delete(evFilter);
+    UA_CreateMonitoredItemsResponse_deleteMembers(&response);
+    return UA_STATUSCODE_GOOD;
+}
+
 UA_StatusCode
 UA_StatusCode
 UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
 UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
                                          UA_MonitoredItemHandlingFunction hf,
                                          UA_MonitoredItemHandlingFunction hf,
                                          void *hfContext, UA_UInt32 *newMonitoredItemId) {
                                          void *hfContext, UA_UInt32 *newMonitoredItemId) {
-    UA_Client_Subscription *sub;
-    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
-        if(sub->subscriptionID == subscriptionId)
-            break;
-    }
+    UA_Client_Subscription *sub = findSubscription(client, subscriptionId);
     if(!sub)
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
 
     /* Create the handler */
     /* Create the handler */
-    UA_Client_MonitoredItem *newMon = UA_malloc(sizeof(UA_Client_MonitoredItem));
+    UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem*)UA_malloc(sizeof(UA_Client_MonitoredItem));
     if(!newMon)
     if(!newMon)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
@@ -178,11 +268,7 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
 UA_StatusCode
 UA_StatusCode
 UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
 UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                             UA_UInt32 monitoredItemId) {
                                             UA_UInt32 monitoredItemId) {
-    UA_Client_Subscription *sub;
-    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
-        if(sub->subscriptionID == subscriptionId)
-            break;
-    }
+    UA_Client_Subscription *sub = findSubscription(client, subscriptionId);
     if(!sub)
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
 
@@ -226,19 +312,10 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
         return;
         return;
 
 
-    /* Find the subscription */
-    UA_Client_Subscription *sub;
-    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
-        if(sub->subscriptionID == response->subscriptionId)
-            break;
-    }
+    UA_Client_Subscription *sub = findSubscription(client, response->subscriptionId);
     if(!sub)
     if(!sub)
         return;
         return;
 
 
-    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
-                 "Processing a publish response on subscription %u with %u notifications",
-                 sub->subscriptionID, response->notificationMessage.notificationDataSize);
-
     /* Check if the server has acknowledged any of the sent ACKs */
     /* Check if the server has acknowledged any of the sent ACKs */
     for(size_t i = 0; i < response->resultsSize && i < request->subscriptionAcknowledgementsSize; ++i) {
     for(size_t i = 0; i < response->resultsSize && i < request->subscriptionAcknowledgementsSize; ++i) {
         /* remove also acks that are unknown to the server */
         /* remove also acks that are unknown to the server */
@@ -266,33 +343,53 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
         if(msg->notificationData[k].encoding != UA_EXTENSIONOBJECT_DECODED)
         if(msg->notificationData[k].encoding != UA_EXTENSIONOBJECT_DECODED)
             continue;
             continue;
 
 
-        /* Currently only dataChangeNotifications are supported */
-        if(msg->notificationData[k].content.decoded.type != &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION])
-            continue;
-
-        UA_DataChangeNotification *dataChangeNotification = msg->notificationData[k].content.decoded.data;
-        for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) {
-            UA_MonitoredItemNotification *mitemNot = &dataChangeNotification->monitoredItems[j];
-            UA_Client_MonitoredItem *mon;
-            LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
-                if(mon->clientHandle == mitemNot->clientHandle) {
-                    mon->handler(mon->monitoredItemId, &mitemNot->value, mon->handlerContext);
-                    break;
+        if(msg->notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
+            UA_DataChangeNotification *dataChangeNotification = (UA_DataChangeNotification *)msg->notificationData[k].content.decoded.data;
+            for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) {
+                UA_MonitoredItemNotification *mitemNot = &dataChangeNotification->monitoredItems[j];
+                UA_Client_MonitoredItem *mon;
+                LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
+                    if(mon->clientHandle == mitemNot->clientHandle) {
+                        mon->handler(mon->monitoredItemId, &mitemNot->value, mon->handlerContext);
+                        break;
+                    }
                 }
                 }
+                if(!mon)
+                    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                                 "Could not process a notification with clienthandle %u on subscription %u",
+                                 mitemNot->clientHandle, sub->subscriptionID);
             }
             }
-            if(!mon)
-                UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
-                             "Could not process a notification with clienthandle %u on subscription %u",
-                             mitemNot->clientHandle, sub->subscriptionID);
+        }
+        else if(msg->notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]) {
+            UA_EventNotificationList *eventNotificationList = (UA_EventNotificationList *)msg->notificationData[k].content.decoded.data;
+            for (size_t j = 0; j < eventNotificationList->eventsSize; ++j) {
+                UA_EventFieldList *eventFieldList = &eventNotificationList->events[j];
+                UA_Client_MonitoredItem *mon;
+                LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
+                    if(mon->clientHandle == eventFieldList->clientHandle) {
+                        mon->handlerEvents(mon->monitoredItemId, eventFieldList->eventFieldsSize,
+                                           eventFieldList->eventFields, mon->handlerContext);
+                        break;
+                    }
+                }
+                if(!mon)
+                    UA_LOG_DEBUG(client->config.logger, UA_LOGCATEGORY_CLIENT,
+                                 "Could not process a notification with clienthandle %u on subscription %u",
+                                 eventFieldList->clientHandle, sub->subscriptionID);
+            }
+        }
+        else {
+            continue; // no other types are supported
         }
         }
     }
     }
 
 
     /* Add to the list of pending acks */
     /* Add to the list of pending acks */
-    UA_Client_NotificationsAckNumber *tmpAck = UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
+    UA_Client_NotificationsAckNumber *tmpAck =
+        (UA_Client_NotificationsAckNumber*)UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
     if(!tmpAck) {
     if(!tmpAck) {
         UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT,
         UA_LOG_WARNING(client->config.logger, UA_LOGCATEGORY_CLIENT,
-                       "Not enough memory to store the acknowledgement for a "
-                       "publish message on subscription %u", sub->subscriptionID);
+                       "Not enough memory to store the acknowledgement for a publish "
+                       "message on subscription %u", sub->subscriptionID);
         return;
         return;
     }
     }
     tmpAck->subAck.sequenceNumber = msg->sequenceNumber;
     tmpAck->subAck.sequenceNumber = msg->sequenceNumber;
@@ -302,7 +399,7 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
 
 
 UA_StatusCode
 UA_StatusCode
 UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
 UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
-    if (client->state == UA_CLIENTSTATE_ERRORED)
+    if(client->state < UA_CLIENTSTATE_SESSION)
         return UA_STATUSCODE_BADSERVERNOTCONNECTED;
         return UA_STATUSCODE_BADSERVERNOTCONNECTED;
 
 
     UA_Boolean moreNotifications = true;
     UA_Boolean moreNotifications = true;
@@ -315,10 +412,10 @@ UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
             ++request.subscriptionAcknowledgementsSize;
             ++request.subscriptionAcknowledgementsSize;
         if(request.subscriptionAcknowledgementsSize > 0) {
         if(request.subscriptionAcknowledgementsSize > 0) {
-            request.subscriptionAcknowledgements =
+            request.subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement*)
                 UA_malloc(sizeof(UA_SubscriptionAcknowledgement) * request.subscriptionAcknowledgementsSize);
                 UA_malloc(sizeof(UA_SubscriptionAcknowledgement) * request.subscriptionAcknowledgementsSize);
             if(!request.subscriptionAcknowledgements)
             if(!request.subscriptionAcknowledgements)
-                return UA_STATUSCODE_GOOD;
+                return UA_STATUSCODE_BADOUTOFMEMORY;
         }
         }
 
 
         int i = 0;
         int i = 0;

+ 35 - 7
src/client/ua_client_internal.h

@@ -1,6 +1,6 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
 /* This Source Code Form is subject to the terms of the Mozilla Public
-*  License, v. 2.0. If a copy of the MPL was not distributed with this 
-*  file, You can obtain one at http://mozilla.org/MPL/2.0/.*/
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #ifndef UA_CLIENT_INTERNAL_H_
 #ifndef UA_CLIENT_INTERNAL_H_
 #define UA_CLIENT_INTERNAL_H_
 #define UA_CLIENT_INTERNAL_H_
@@ -8,9 +8,9 @@
 #include "ua_securechannel.h"
 #include "ua_securechannel.h"
 #include "queue.h"
 #include "queue.h"
 
 
-/**************************/
-/* Subscriptions Handling */
-/**************************/
+ /**************************/
+ /* Subscriptions Handling */
+ /**************************/
 
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 
 
@@ -29,8 +29,10 @@ typedef struct UA_Client_MonitoredItem {
     UA_Double samplingInterval;
     UA_Double samplingInterval;
     UA_UInt32 queueSize;
     UA_UInt32 queueSize;
     UA_Boolean discardOldest;
     UA_Boolean discardOldest;
-    void (*handler)(UA_UInt32 monId, UA_DataValue *value, void *context);
+    void(*handler)(UA_UInt32 monId, UA_DataValue *value, void *context);
     void *handlerContext;
     void *handlerContext;
+    void(*handlerEvents)(const UA_UInt32 monId, const size_t nEventFields, const UA_Variant *eventFields, void *context);
+    void *handlerEventsContext;
 } UA_Client_MonitoredItem;
 } UA_Client_MonitoredItem;
 
 
 typedef struct UA_Client_Subscription {
 typedef struct UA_Client_Subscription {
@@ -52,6 +54,14 @@ void UA_Client_Subscriptions_forceDelete(UA_Client *client, UA_Client_Subscripti
 /* Client */
 /* Client */
 /**********/
 /**********/
 
 
+typedef struct AsyncServiceCall {
+    LIST_ENTRY(AsyncServiceCall) pointers;
+    UA_UInt32 requestId;
+    UA_ClientAsyncServiceCallback callback;
+    const UA_DataType *responseType;
+    void *userdata;
+} AsyncServiceCall;
+
 typedef enum {
 typedef enum {
     UA_CLIENTAUTHENTICATION_NONE,
     UA_CLIENTAUTHENTICATION_NONE,
     UA_CLIENTAUTHENTICATION_USERNAME
     UA_CLIENTAUTHENTICATION_USERNAME
@@ -67,6 +77,7 @@ struct UA_Client {
     UA_String endpointUrl;
     UA_String endpointUrl;
 
 
     /* SecureChannel */
     /* SecureChannel */
+    UA_SecurityPolicy securityPolicy;
     UA_SecureChannel channel;
     UA_SecureChannel channel;
     UA_UInt32 requestId;
     UA_UInt32 requestId;
     UA_DateTime nextChannelRenewal;
     UA_DateTime nextChannelRenewal;
@@ -80,7 +91,10 @@ struct UA_Client {
     UA_UserTokenPolicy token;
     UA_UserTokenPolicy token;
     UA_NodeId authenticationToken;
     UA_NodeId authenticationToken;
     UA_UInt32 requestHandle;
     UA_UInt32 requestHandle;
-    
+
+    /* Async Service */
+    LIST_HEAD(ListOfAsyncServiceCall, AsyncServiceCall) asyncServiceCalls;
+
     /* Subscriptions */
     /* Subscriptions */
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     UA_UInt32 monitoredItemHandles;
     UA_UInt32 monitoredItemHandles;
@@ -89,4 +103,18 @@ struct UA_Client {
 #endif
 #endif
 };
 };
 
 
+UA_StatusCode
+UA_Client_connectInternal(UA_Client *client, const char *endpointUrl,
+                          UA_Boolean endpointsHandshake, UA_Boolean createNewSession);
+
+UA_StatusCode
+UA_Client_getEndpointsInternal(UA_Client *client, size_t* endpointDescriptionsSize,
+                               UA_EndpointDescription** endpointDescriptions);
+
+/* Receive and process messages until a synchronous message arrives or the
+ * timout finishes */
+UA_StatusCode
+receiveServiceResponse(UA_Client *client, void *response, const UA_DataType *responseType,
+                       UA_DateTime maxDate, UA_UInt32 *synchronousRequestId);
+
 #endif /* UA_CLIENT_INTERNAL_H_ */
 #endif /* UA_CLIENT_INTERNAL_H_ */

+ 0 - 0
src/server/ua_mdns.c


Some files were not shown because too many files changed in this diff