浏览代码

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

Stefan Profanter 7 年之前
父节点
当前提交
4ea40d346f
共有 100 个文件被更改,包括 8591 次插入3250 次删除
  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
 /src_generated/
 /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
 
-compiler:
-- gcc
-- clang
-
-os:
-- linux
-- osx
-
 # use new build environment (docker)
-dist: trusty
 sudo: required
 
 env:
@@ -18,28 +9,49 @@ env:
     - secure: nSunY54Wp5HkQCHHbKwlwpbaKyqRVIu/0EnhaoJSwhM1wqerQV/E5d/2JelO9/tZgbungAO7wk/fjutRMVc7d378RTIPwS8vHpvZfEoGhCFsLoTOlqESzsZFBup2H5t1lpQ23jRHDOxlLdJy2lz5U+zd1YnYgDXqdDFjegsIYdo=
     # COVERITY_SCAN_TOKEN:
     - 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:
-  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
-    - os: osx
       env: ANALYZE=true
-    - os: osx
+    - os: linux
+      compiler: gcc
       env: DOCKER=true
+      services:
+        - docker
     - os: linux
       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:
   apt:
@@ -48,25 +60,26 @@ addons:
     packages:
       - binutils-mingw-w64-i686
       - build-essential
-      - cmake
-      - gcc-multilib
-      - g++-multilib
-      - valgrind
       - check
+      - cmake
       - cppcheck
-      - mingw-w64
-      - g++-mingw-w64-x86-64
+      - gcc-multilib
       - g++-mingw-w64-i686
-      - libc6-dbg # for valgrind compilation
+      - g++-mingw-w64-x86-64
+      - g++-multilib
+      - graphviz
       - libsubunit-dev
       - libx11-dev
+      - mingw-w64
+      - python-six
+      - python3-six
+      - texlive-fonts-recommended
+      - texlive-latex-extra
+      - texlive-latex-recommended
+      - valgrind
       - wget
       - xutils-dev
       - zip
-      - graphviz
-      - texlive-latex-recommended
-      - texlive-latex-extra
-      - texlive-fonts-recommended
   coverity_scan:
     project:
       name: "open62541/open62541"
@@ -81,18 +94,32 @@ cache:
   apt: true
   directories:
     - $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:
   provider: releases
@@ -110,4 +137,4 @@ deploy:
   on:
     repo: open62541/open62541
     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)
 
 Bauer, Maximilian
+Ebrahimi, Reza <reza.ebrahimi.dev (at) gmail.com>
 Graube, Markus <markus.graube (at) tu-dresden.de>
 Gruener, Sten <s.gruener (at) plt.rwth-aachen.de>
 Iatrou, Chris Paul <chris_paul.iatrou (at) tu-dresden.de>
 Jeromin, Holger
 Palm, Florian <f.palm (at) plt.rwth-aachen.de>
 Pfrommer, Julius <julius.pfrommer (at) kit.edu>
+Profanter, Stefan <profanter (at) fortiss.org>
 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>
 
-    * 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>
 
-    * 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>
 
-    * 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)
 # set(CMAKE_VERBOSE_MAKEFILE ON)
 
 set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/tools/cmake")
 find_package(PythonInterp REQUIRED)
 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 #
 ###########
 
 set(OPEN62541_VER_MAJOR 0)
-set(OPEN62541_VER_MINOR 2)
+set(OPEN62541_VER_MINOR 3)
 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
 
@@ -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_NODEMANAGEMENT "Enable dynamic addition and removal of nodes at runtime" 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_COVERAGE "Enable gcov coverage" 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)
   set(CMAKE_BUILD_TYPE DEBUG)
   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")
 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
 option(UA_ENABLE_MULTITHREADING "Enable multithreading (experimental)" OFF)
 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)
 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)
 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)
 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)
 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()
 
+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
 option(UA_BUILD_EXAMPLES "Build example servers and clients" 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
 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)
 if(BUILD_SHARED_LIBS)
   set(UA_DYNAMIC_LINKING ON)
+  if (UA_ENABLE_DISCOVERY_MULTICAST)
+      set(MDNSD_DYNAMIC_LINKING ON)
+  endif()
 endif()
 
 # Force compilation with as C++
 option(UA_COMPILE_AS_CXX "Force compilation with a C++ compiler" OFF)
 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 #
@@ -112,27 +154,57 @@ mark_as_advanced(UA_COMPILE_AS_CXX)
 # Collect libraries
 list(APPEND open62541_LIBRARIES "")
 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()
 else()
   list(APPEND open62541_LIBRARIES ws2_32)
+    if(UA_ENABLE_DISCOVERY_MULTICAST)
+        list(APPEND open62541_LIBRARIES iphlpapi)
+    endif()
 endif()
 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)
 
-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
-    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)
     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
     set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
 
@@ -171,8 +243,14 @@ endif()
 
 if(MSVC)
   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()
 
 #########################
@@ -181,27 +259,35 @@ endif()
 
 file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/src_generated")
 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
                      ${PROJECT_SOURCE_DIR}/deps/ms_stdint.h
                      ${PROJECT_SOURCE_DIR}/include/ua_constants.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_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_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_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
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.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_SOURCE_DIR}/src/ua_connection_internal.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_timer.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_securechannel_manager.h
                      ${PROJECT_SOURCE_DIR}/src/server/ua_server_internal.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)
 
 # 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_BINARY_DIR}/src_generated/ua_types_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_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_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_utils.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_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
-                ${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
-                # method call
                 ${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_securechannel.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_nodemanagement.c
+                ${PROJECT_SOURCE_DIR}/src/server/ua_services_discovery_multicast.c
                 # client
                 ${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_subscriptions.c
+
                 # dependencies
                 ${PROJECT_SOURCE_DIR}/deps/libc_time.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
                            ${PROJECT_SOURCE_DIR}/plugins/ua_clock.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()
 
 if(UA_ENABLE_NONSTANDARD_UDP)
     list(APPEND exported_headers ${PROJECT_SOURCE_DIR}/plugins/ua_network_udp.h)
 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 #
 #########################
 
-# 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
                           ${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
                    PRE_BUILD
                    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
-                           ${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
 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
 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
                    PRE_BUILD
                    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
                    DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_datatypes.py
                            ${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
 add_custom_target(open62541-generator-transport DEPENDS
         ${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_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
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_statuscode_descriptions.c
         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
         DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_statuscode_descriptions.py
         ${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
 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
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.h
                    PRE_BUILD
                    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
-                           ${exported_headers} ${internal_headers})
+                           ${exported_headers} ${default_plugin_headers})
 
 add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/open62541.c
                    PRE_BUILD
                    COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/tools/amalgamate.py
                            ${OPEN62541_VER_COMMIT} ${CMAKE_CURRENT_BINARY_DIR}/open62541.c
                            ${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-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-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 #
 #####################
 
+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)
-    include_directories(${PROJECT_BINARY_DIR}) # contains 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
     # and thus may overwrite the amalgamation result during multiprocessor compilation
     # the header is already a dependency of open62541 target itself
@@ -401,9 +556,7 @@ if(UA_ENABLE_AMALGAMATION)
                      open62541-generator-types
                      open62541-generator-transport
                      open62541-generator-statuscode
-                     open62541-amalgamation-source
-                     )
-
+                     open62541-amalgamation-source)
 
     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_BINARY_DIR}/src_generated)
     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>)
 
@@ -434,24 +588,23 @@ else()
     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()
 
 # Export Symbols
 target_compile_definitions(open62541-object 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
 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
 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)
 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) #
 ############################
@@ -493,6 +653,7 @@ add_custom_target(lint ${CLANG_TIDY_PROGRAM}
                   -I${PROJECT_SOURCE_DIR}/src/server
                   -I${PROJECT_SOURCE_DIR}/src/client
                   -I${PROJECT_BINARY_DIR}/src_generated
+                  -DUA_NO_AMALGAMATION
                   DEPENDS ${lib_sources}
                   COMMENT "Run clang-tidy on the library")
 add_dependencies(lint open62541)
@@ -504,12 +665,52 @@ add_dependencies(lint open62541)
 # specify install location with `-DCMAKE_INSTALL_PREFIX=xyz`
 # 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)
 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
-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)    #
@@ -528,3 +729,16 @@ set(CPACK_PACKAGE_VERSION_PATCH "0")
 set(CPACK_DEBIAN_PACKAGE_MAINTAINER "open62541 team") #required
 
 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
-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
 WORKDIR /tmp/open62541/build
+RUN pip install six
 RUN cmake -DUA_ENABLE_AMALGAMATION=true  \
           -DBUILD_SHARED_LIBS=true \
           /tmp/open62541 
 RUN make -j
 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
   defined by the Mozilla Public License, v. 2.0.
-

文件差异内容过多而无法显示
+ 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 && \
     make && \
     cp *.h /usr/include/ && \
-    cp *.so /usr/lib && \
+    cp bin/*.so /usr/lib && \
     make clean && \
     apk del cmake gcc g++ musl-dev python make

+ 90 - 20
appveyor.yml

@@ -5,81 +5,151 @@ clone_depth: 20
 
 environment:
     global:
+        APPVEYOR_CACHE_ENTRY_ZIP_ARGS: -t7z -m0=lzma -mx=9
         CYG_ARCH: x86
         CYG_ROOT: C:/cygwin
         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_BASH: C:/cygwin/bin/bash
-
       
     matrix:
         - CC_NAME: MinGW Makefiles
           CC_SHORTNAME: mingw
-          MAKE: mingw32-make
+          MAKE: mingw32-make -j
           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_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
+          OUT_DIR_LIB: bin\Debug
+          OUT_DIR_EXAMPLES: bin\examples\Debug
         - CC_NAME: Visual Studio 12 2013 Win64
           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
+          OUT_DIR_LIB: bin\Debug
+          OUT_DIR_EXAMPLES: bin\examples\Debug
 
 cache:
   - '%CYG_CACHE%'
+  - 'c:\miktex'
+  #- 'c:\python27'
 
 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
 
 # Install needed build dependencies
 install:
+  - git submodule update --init --recursive
   - if not exist "%CYG_ROOT%" mkdir "%CYG_ROOT%"
   - 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
   - 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_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:
+  # 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
   - 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:
+  # log is loaded from cache, so we strip it here
+  - rd /s /q c:\miktex\texmfs\data\miktex\log
+
   - 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
   - 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%" ..
   - '%MAKE%'
   - cd ..
   - rd /s /q build
   - md 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%" ..
   - '%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 ..
+  - 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
   - md 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%" ..
   - '%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 ..
+  - 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:
   - 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"
 
 /* 2000-03-01 (mod 400 year, immediately after feb29 */
@@ -12,8 +11,7 @@
 #define DAYS_PER_100Y (365*100 + 24)
 #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;
     int remdays, remsecs, remyears;
     int qc_cycles, c_cycles, q_cycles;

+ 15 - 3
deps/libc_time.h

@@ -1,8 +1,20 @@
 #ifndef 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_ */

+ 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++" {}'
 // or compiler give many errors like this:
 //   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifndef UNDER_CE
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -54,6 +55,7 @@ extern "C" {
 #ifdef __cplusplus
 }
 #endif
+#endif
 
 // Define _W64 macros to mark types changing their size, like intptr_t.
 #ifndef _W64

+ 10 - 9
deps/pcg_basic.h

@@ -21,18 +21,19 @@
  *     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" {
 #endif
 
+#include "ua_config.h"
+
 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;
 
 #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);
 uint32_t pcg32_random_r(pcg32_random_t* rng);
 
-#if __cplusplus
+#ifdef __cplusplus
 }
 #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_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_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_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
 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}"
   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}/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_client_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")
 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}
   # 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}
   COMMENT "Generating PDF documentation from LaTeX sources")
 add_dependencies(doc_pdf doc_latex)
@@ -69,9 +69,9 @@ add_custom_target(doc ${SPHINX_EXECUTABLE}
   -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
           ${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_client_firststeps.rst
           ${DOC_SRC_DIR}/tutorial_server_firststeps.rst
@@ -84,3 +84,4 @@ add_custom_target(doc ${SPHINX_EXECUTABLE}
 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 FOLDER "open62541/doc")

+ 60 - 21
doc/building.rst

@@ -22,7 +22,7 @@ Building with CMake on Ubuntu or Debian
 
 .. 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
    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
 
-  - 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
-  - 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)
 - Open a command shell (cmd) and run
@@ -83,6 +84,7 @@ Building on OS X
 .. code-block:: bash
 
    brew install cmake
+   pip install six # python 2/3 compatibility workarounds
    pip install sphinx # for documentation generation
    pip install sphinx_rtd_theme # documentation style
    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
 -------------
 
+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
 ^^^^^^^^^^^^^^^^^^^^^^
 
@@ -130,17 +141,15 @@ Build Type and Logging
   - ``MinSizeRel`` -Os optimization without debug symbols
 
 **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
 ^^^^^^^^^^^^^^^^
@@ -173,7 +182,7 @@ This group contains build options related to the supported OPC UA features.
 **UA_ENABLE_NODEMANAGEMENT**
    Enable dynamic addition and removal of nodes at runtime
 **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**
    Enable multi-threading support
 **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.
 
 **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**
    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_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**
    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
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-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
 ============
 
-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
 ------------------------

+ 3 - 3
doc/internal.rst

@@ -3,6 +3,6 @@ Internals
 
 .. 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
                 </Reference>
             </References>
-            <InverseName Locale="en_US">inputProcidedBy</InverseName>
+            <InverseName Locale="en-US">inputProcidedBy</InverseName>
         </UAReferenceType>
         <UAObjectType IsAbstract="true" NodeId="ns=1;i=1001"
                       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_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;
       theAnswerCallback.method = pumpInstantiationCallback;

+ 1 - 1
doc/toc.rst

@@ -8,8 +8,8 @@ open62541 Documentation
    tutorials
    protocol
    types
-   information_modelling
    services
+   nodestore
    server
    client
    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 #
 #############
 
-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)
-  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()
 
-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 #
 ##################
 
-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 #
 ##################
 
-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 #
 ####################
 
-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()
 
 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}
                      DEPENDS ${PROJECT_SOURCE_DIR}/tools/certs/create_self-signed.py
                              ${PROJECT_SOURCE_DIR}/tools/certs/localhost.cnf)
-                             
   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})
 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.
  * 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 "open62541.h"
 
+#ifdef UA_ENABLE_SUBSCRIPTIONS
 static void
 handler_TheAnswerChanged(UA_UInt32 monId, UA_DataValue *value, void *context) {
     printf("The Answer has changed!\n");
 }
+#endif
 
 static UA_StatusCode
 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[]) {
-    UA_Client *client = UA_Client_new(UA_ClientConfig_standard);
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
 
     /* Listing endpoints */
     UA_EndpointDescription* endpointArray = NULL;
     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);
     if(retval != UA_STATUSCODE_GOOD) {
         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]);
 
     /* 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) {
         UA_Client_delete(client);
         return (int)retval;
@@ -104,7 +94,7 @@ int main(int argc, char *argv[]) {
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     /* Create a subscription */
     UA_UInt32 subId = 0;
-    UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_standard, &subId);
+    UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_default, &subId);
     if(subId)
         printf("Create subscription succeeded, id %u\n", subId);
     /* Add a MonitoredItem */
@@ -188,11 +178,10 @@ int main(int argc, char *argv[]) {
     /* Add new nodes*/
     /* New ReferenceType */
     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,
                                             UA_NODEID_NUMERIC(1, 12133),
                                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
@@ -204,10 +193,9 @@ int main(int argc, char *argv[]) {
 
     /* New ObjectType */
     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,
                                          UA_NODEID_NUMERIC(1, 12134),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
@@ -219,10 +207,9 @@ int main(int argc, char *argv[]) {
 
     /* New Object */
     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,
                                      UA_NODEID_NUMERIC(1, 0),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
@@ -235,11 +222,10 @@ int main(int argc, char *argv[]) {
 
     /* New Integer Variable */
     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 =
-        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;
     /* This does not copy the value */
     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="HasComponent">i=47</Alias>
     </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">
         <DisplayName>testType</DisplayName>
         <References>
@@ -24,23 +40,22 @@
             <Reference ReferenceType="HasModellingRule">i=78</Reference>
             <Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=1001</Reference>
         </References>
+        <Value>
+            <uax:Double>42.0</uax:Double>
+        </Value>
     </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>
             <Reference ReferenceType="HasTypeDefinition">i=63</Reference>
             <Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=5001</Reference>
         </References>
         <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>
     </UAVariable>
 </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. */
 
 #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
 
-#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 <errno.h> // errno, EINTR
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "open62541.h"
 
 UA_Boolean running = true;
 UA_Logger logger = UA_Log_Stdout;
@@ -38,7 +29,7 @@ static UA_ByteString loadCertificate(void) {
 
     fseek(fp, 0, SEEK_END);
     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)
         return certificate;
 
@@ -57,7 +48,10 @@ static void stopHandler(int sign) {
 
 /* Datasource Example */
 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) {
     if(range) {
         value->hasStatus = true;
@@ -77,7 +71,10 @@ readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
 /* Method Node Example */
 #ifdef UA_ENABLE_METHODCALLS
 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 outputSize, UA_Variant *output) {
     /* 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 greet;
     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.length, name->data, name->length);
     UA_Variant_setScalarCopy(output, &greet, &UA_TYPES[UA_TYPES_STRING]);
@@ -94,16 +91,22 @@ helloWorld(void *methodHandle, const UA_NodeId objectId,
 }
 
 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;
 }
 
 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_Variant_setScalarCopy(output, &out, &UA_TYPES[UA_TYPES_INT32]);
     return UA_STATUSCODE_GOOD;
@@ -113,21 +116,16 @@ outargMethod (void *methodHandle, const UA_NodeId objectId,
 int main(int argc, char** argv) {
     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);
 
     /* 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;
     UA_Int32 myInteger = 42;
     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);
 
     /* 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;
     const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
     UA_NodeId dataSourceId;
     UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         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 */
 #ifdef UA_ENABLE_METHODCALLS
@@ -158,7 +157,7 @@ int main(int argc, char** argv) {
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
     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.valueRank = -1; /* scalar argument */
 
@@ -167,13 +166,12 @@ int main(int argc, char** argv) {
     outputArguments.arrayDimensionsSize = 0;
     outputArguments.arrayDimensions = NULL;
     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.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.userExecutable = true;
     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_QUALIFIEDNAME(1, "hello_world"), addmethodattributes,
         &helloWorld, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 1, &outputArguments, NULL);
+        1, &inputArguments, 1, &outputArguments, NULL, NULL);
 #endif
 
     /* Add folders for demo information model */
@@ -192,31 +189,30 @@ int main(int argc, char** argv) {
 #define MATRIXID 50003
 #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_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, 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_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
         UA_QUALIFIEDNAME(1, "Scalar"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, 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_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
         UA_QUALIFIEDNAME(1, "Array"),
         UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, 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_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
         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)
             continue;
 
-        UA_VariableAttributes attr;
-        UA_VariableAttributes_init(&attr);
+        UA_VariableAttributes attr = UA_VariableAttributes_default;
         attr.valueRank = -2;
         attr.dataType = UA_TYPES[type].typeId;
 #ifndef UA_ENABLE_TYPENAMES
@@ -238,10 +233,10 @@ int main(int argc, char** argv) {
 #else
         sprintf(name, "%02d", type);
 #endif
-        attr.displayName = UA_LOCALIZEDTEXT("en_US", name);
+        attr.displayName = UA_LOCALIZEDTEXT("en-US", name);
         UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name);
 #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);
 #endif
         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 */
         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[1] = 3;
         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 */
     /* Enter node "depth 9" in CTT configuration - Project->Settings->Server
        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_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "DepthDemo"),
@@ -300,8 +295,8 @@ int main(int argc, char** argv) {
 #else
         sprintf(name, "depth%i", i);
 #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_NODEID_NUMERIC(1, i==1 ? DEPTHID : id+i-1), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                 UA_QUALIFIEDNAME(1, name),
@@ -316,7 +311,7 @@ int main(int argc, char** argv) {
                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), answer_nodeid, true);
 
     /* 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);
 
 #define NOARGID     60000
@@ -326,8 +321,8 @@ int main(int argc, char** argv) {
 #ifdef UA_ENABLE_METHODCALLS
     /* adding some more method nodes to pass CTT */
     /* 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.userExecutable = true;
     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_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         &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 */
-    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.userExecutable = true;
 
     UA_Argument_init(&inputArguments);
     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.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_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         &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 */
-    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.userExecutable = true;
 
     UA_Argument_init(&outputArguments);
     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.valueRank = -1;
 
@@ -375,12 +368,11 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "outarg"), addmethodattributes,
         &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 */
-    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.userExecutable = true;
 
@@ -389,17 +381,12 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "inoutarg"), addmethodattributes,
         &outargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 1, &outputArguments, NULL);
+        1, &inputArguments, 1, &outputArguments, NULL, NULL);
 #endif
 
     /* 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);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     return (int)retval;
 }

+ 7 - 18
examples/server.cpp

@@ -4,14 +4,7 @@
 #include <signal.h>
 #include <iostream>
 #include <cstring>
-
-#ifdef UA_NO_AMALGAMATION
-# include "ua_server.h"
-# include "ua_log_stdout.h"
-# include "ua_network_tcp.h"
-#else
 # include "open62541.h"
-#endif
 
 /* Build Instructions (Linux)
  * - gcc -std=c99 -c open62541.c
@@ -28,21 +21,18 @@ static void stopHandler(int sign) {
 }
 
 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);
 
     // 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_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_QualifiedName myIntegerName = UA_QUALIFIEDNAME_ALLOC(1, "the answer");
     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_Server_delete(server);
-    nl.deleteMembers(&nl);
-
+    UA_ServerConfig_delete(config);
     return retval;
 }

+ 9 - 23
examples/server_certificate.c

@@ -5,30 +5,19 @@
 #define _CRT_SECURE_NO_WARNINGS //disable fopen deprication warning in msvs
 #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 <signal.h>
+#include <errno.h> // errno, EINTR
 #include <stdlib.h>
+#include "open62541.h"
 
 UA_Boolean running = true;
 UA_Logger logger = UA_Log_Stdout;
 
 static UA_ByteString loadCertificate(void) {
     UA_ByteString certificate = UA_STRING_NULL;
-    FILE *fp = NULL;
     //FIXME: a potiential bug of locating the certificate, we need to get the path from the server's config
-    fp=fopen("server_cert.der", "rb");
-
+    FILE *fp = fopen("server_cert.der", "rb");
     if(!fp) {
         errno = 0; // we read errno also from the tcp layer...
         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);
     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)
         return certificate;
 
@@ -57,14 +46,11 @@ static void stopHandler(int sign) {
 int main(int argc, char** argv) {
     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 */
-    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");
 
 
@@ -73,10 +59,10 @@ int main(int argc, char** argv) {
     UA_StatusCode retval = UA_Server_run(server, &running);
 
     /* deallocate certificate's memory */
-    UA_ByteString_deleteMembers(&config.serverCertificate);
+    UA_ByteString_deleteMembers(&config->serverCertificate);
 
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
 
     return (int)retval;
 }

+ 71 - 75
examples/server_inheritance.c

@@ -2,15 +2,7 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 #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"
-#endif
 
 UA_Boolean running = true;
 static void stopHandler(int sig) {
@@ -21,13 +13,9 @@ int main(void) {
     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);
 
-
     /* Create a rudimentary objectType
      *
      * Type:
@@ -44,60 +32,65 @@ int main(void) {
      *          v- MakeSound = "Wuff"
      *           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_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_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_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_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_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_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_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_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_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_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_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:
      * (O) Objects
@@ -106,33 +99,36 @@ int main(void) {
      *     + 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_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_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_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);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     return (int)retval;
 }

+ 27 - 39
examples/server_instantiation.c

@@ -2,15 +2,7 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 #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"
-#endif
 
 UA_Boolean running = true;
 static void stopHandler(int sig) {
@@ -21,10 +13,7 @@ int main(void) {
     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);
     
     /* Create a rudimentary objectType
@@ -38,37 +27,35 @@ int main(void) {
      *      + (V) Name
      */ 
     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_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_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_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_NODEID_NUMERIC(1, 10000), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               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_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_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_NODEID_NUMERIC(1, 10002), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               UA_QUALIFIEDNAME(1, "Name"), UA_NODEID_NULL, vAttr, NULL, NULL);
@@ -80,16 +67,17 @@ int main(void) {
      *     + 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);
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     return (int)retval;
 }

+ 13 - 22
examples/server_mainloop.c

@@ -9,22 +9,11 @@
 #else
 # include <sys/select.h>
 #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
 
 UA_Boolean running = true;
-UA_Logger logger = UA_Log_Stdout;
-
 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;
 }
 
@@ -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. */
 
 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_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
        arrives or should it return immediately? */
     UA_Boolean waitInternal = false;
 
+    UA_StatusCode retval = UA_Server_run_startup(server);
+    if(retval != UA_STATUSCODE_GOOD)
+        goto cleanup;
+
     while(running) {
         /* timeout is the maximum possible delay (in millisec) until the next
            _iterate call. Otherwise, the server might miss an internal timeout
            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);
 
         /* 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:
     UA_Server_delete(server);
-    nl.deleteMembers(&nl);
+    UA_ServerConfig_delete(config);
     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. */
 
 #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
 testCallback(UA_Server *server, void *data) {
@@ -28,19 +19,14 @@ int main(void) {
     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);
 
-    /* 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);
-    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 <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"
-#endif
-
 
 UA_Logger logger = UA_Log_Stdout;
 
 UA_Boolean running = 1;
-
 static void stopHandler(int sign) {
     printf("Received Ctrl-C\n");
     running = 0;
@@ -37,12 +26,11 @@ int main(int argc, char** argv) {
     UA_Server *server = UA_Server_new(config);
 
     // 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_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_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     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
  * ------------------------
-
  * 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
  * creating a server. Copy the following into a file `myClient.c`: */
@@ -13,7 +12,7 @@
 #include "open62541.h"
 
 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");
     if(retval != UA_STATUSCODE_GOOD) {
         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.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 */
 
     UA_CallRequest *cr2 = UA_CallRequest_new();
@@ -120,7 +120,7 @@ variables_variants(void) {
     UA_Variant_setArrayCopy(&v3, d, 9, &UA_TYPES[UA_TYPES_DOUBLE]);
 
     /* 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.arrayDimensions[0] = 3;
     v3.arrayDimensions[1] = 3;

+ 28 - 26
examples/tutorial_server_datasource.c

@@ -40,9 +40,9 @@ updateCurrentTime(UA_Server *server) {
 static void
 addCurrentTimeVariable(UA_Server *server) {
     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_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
@@ -68,9 +68,10 @@ addCurrentTimeVariable(UA_Server *server) {
  * write operation. */
 
 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_Variant value;
     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
-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,
                 "The variable was updated");
 }
@@ -89,7 +92,6 @@ static void
 addValueCallbackToCurrentTimeVariable(UA_Server *server) {
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
     UA_ValueCallback callback ;
-    callback.handle = server;
     callback.onRead = beforeReadTime;
     callback.onWrite = afterWriteTime;
     UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);
@@ -106,8 +108,11 @@ addValueCallbackToCurrentTimeVariable(UA_Server *server) {
  * own memory management. */
 
 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_Variant_setScalarCopy(&dataValue->value, &now,
                              &UA_TYPES[UA_TYPES_DATETIME]);
@@ -116,8 +121,10 @@ readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp
 }
 
 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,
                 "Changing the system time is not implemented");
     return UA_STATUSCODE_BADINTERNALERROR;
@@ -125,9 +132,9 @@ writeCurrentTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
 
 static void
 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_QualifiedName currentName = UA_QUALIFIEDNAME(1, "current-time-datasource");
@@ -136,13 +143,12 @@ addCurrentTimeDataSourceVariable(UA_Server *server) {
     UA_NodeId variableTypeNodeId = UA_NODEID_NULL;
 
     UA_DataSource timeDataSource;
-    timeDataSource.handle = NULL;
     timeDataSource.read = readCurrentTime;
     timeDataSource.write = writeCurrentTime;
     UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId,
                                         parentReferenceNodeId, currentName,
                                         variableTypeNodeId, attr,
-                                        timeDataSource, NULL);
+                                        timeDataSource, NULL, NULL);
 }
 
 /** It follows the main server code, making use of the above definitions. */
@@ -157,21 +163,17 @@ int main(void) {
     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);
 
     addCurrentTimeVariable(server);
     addValueCallbackToCurrentTimeVariable(server);
     addCurrentTimeDataSourceVariable(server);
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     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(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_run(server, &running);
-
+    UA_StatusCode retval = UA_Server_run(server, &running);
     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"
 
 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 outputSize, UA_Variant *output) {
     UA_String *inputStr = (UA_String*)input->data;
     UA_String tmp = UA_STRING_ALLOC("Hello ");
     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);
         tmp.length += inputStr->length;
     }
@@ -54,30 +57,29 @@ static void
 addHellWorldMethod(UA_Server *server) {
     UA_Argument 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.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArgument.valueRank = -1; /* scalar */
 
     UA_Argument 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.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     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.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                             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. */
 
 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 outputSize, UA_Variant *output) {
     UA_Int32 *inputArray = (UA_Int32*)input[0].data;
@@ -112,7 +117,7 @@ addIncInt32ArrayMethod(UA_Server *server) {
     /* Two input arguments */
     UA_Argument inputArguments[2];
     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].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     inputArguments[0].valueRank = 1;
@@ -121,7 +126,7 @@ addIncInt32ArrayMethod(UA_Server *server) {
     inputArguments[0].arrayDimensions = &pInputDimension;
 
     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].dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     inputArguments[1].valueRank = -1; /* scalar */
@@ -129,7 +134,7 @@ addIncInt32ArrayMethod(UA_Server *server) {
     /* One output argument */
     UA_Argument 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.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
     outputArgument.valueRank = 1;
@@ -138,18 +143,18 @@ addIncInt32ArrayMethod(UA_Server *server) {
     outputArgument.arrayDimensions = &pOutputDimension;
 
     /* 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.userExecutable = true;
     UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "IncInt32ArrayValues"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                             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. */
@@ -164,18 +169,14 @@ int main(void) {
     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);
 
     addHellWorldMethod(server);
     addIncInt32ArrayMethod(server);
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     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
 manuallyDefinePump(UA_Server *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_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Pump (Manual)"), UA_NODEID_NULL,
                             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_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_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "ManufacturerName"),
                               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_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_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "ModelName"),
                               UA_NODEID_NULL, modelAttr, NULL, NULL);
 
-    UA_VariableAttributes statusAttr;
-    UA_VariableAttributes_init(&statusAttr);
+    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;
     UA_Boolean status = true;
     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_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "Status"),
                               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_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_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "MotorRPMs"),
@@ -174,18 +169,16 @@ static void
 defineObjectTypes(UA_Server *server) {
     /* Define the object type for "Device" */
     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_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                                 UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "DeviceType"), dtAttr,
                                 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_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
                               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_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_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                               UA_QUALIFIEDNAME(1, "ModelName"),
                               UA_NODEID_NULL, modelAttr, NULL, NULL);
 
     /* 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,
                                 deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                 UA_QUALIFIEDNAME(1, "PumpType"), ptAttr,
                                 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;
     UA_NodeId statusId;
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
@@ -228,9 +218,8 @@ defineObjectTypes(UA_Server *server) {
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
                            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;
     UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
@@ -248,9 +237,8 @@ defineObjectTypes(UA_Server *server) {
 
 static void
 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_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
@@ -268,11 +256,11 @@ addPumpObjectInstance(UA_Server *server, char *name) {
  * 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");
 
     /* Find the NodeId of the status child variable */
@@ -285,33 +273,34 @@ pumpTypeConstructor(const UA_NodeId instance) {
     
     UA_BrowsePath bp;
     UA_BrowsePath_init(&bp);
-    bp.startingNode = instance;
+    bp.startingNode = *nodeId;
     bp.relativePath.elementsSize = 1;
     bp.relativePath.elements = &rpe;
     
     UA_BrowsePathResult bpr =
-        UA_Server_translateBrowsePathToNodeIds(s, &bp);
+        UA_Server_translateBrowsePathToNodeIds(server, &bp);
     if(bpr.statusCode != UA_STATUSCODE_GOOD ||
        bpr.targetsSize < 1)
-        return NULL;
+        return bpr.statusCode;
 
     /* Set the status value */
     UA_Boolean status = true;
     UA_Variant value;
     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);
 
-    /* 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
 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. */
@@ -326,13 +315,8 @@ int main(void) {
     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);
-    s = server; /* required for the constructor */
 
     manuallyDefinePump(server);
     defineObjectTypes(server);
@@ -342,8 +326,8 @@ int main(void) {
     addPumpObjectInstance(server, "pump4");
     addPumpObjectInstance(server, "pump5");
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     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
  * definition of the ``UA_VariableAttrbitues`` structure to see the list of all
  * 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>
@@ -18,13 +21,13 @@
 static void
 addVariable(UA_Server *server) {
     /* 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_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.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
 
     /* Add the variable node to the information model */
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
@@ -103,19 +106,15 @@ int main(void) {
     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);
 
     addVariable(server);
     writeVariable(server);
     writeWrongVariable(server);
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     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
 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.valueRank = 1; /* array with one dimension */
     UA_UInt32 arrayDims[1] = {2};
     vtAttr.arrayDimensions = arrayDims;
     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 */
     UA_Double zero[2] = {0.0, 0.0};
     UA_Variant_setArray(&vtAttr.value, zero, 2, &UA_TYPES[UA_TYPES_DOUBLE]);
 
     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_QUALIFIEDNAME(1, "2DPoint Type"), UA_NODEID_NULL,
                                   vtAttr, NULL, &pointTypeId);
@@ -56,14 +55,14 @@ static UA_NodeId pointVariableId;
 static void
 addVariable(UA_Server *server) {
     /* 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.valueRank = 1; /* array with one dimension */
     UA_UInt32 arrayDims[1] = {2};
     vAttr.arrayDimensions = arrayDims;
     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 */
 
     /* Add the node */
@@ -83,11 +82,10 @@ addVariable(UA_Server *server) {
 static void
 addVariableFail(UA_Server *server) {
     /* 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.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_Variant_setScalar(&vAttr.value, &s, &UA_TYPES[UA_TYPES_STRING]);
 
@@ -108,7 +106,7 @@ static void
 writeVariable(UA_Server *server) {
     UA_StatusCode retval = UA_Server_writeValueRank(server, pointVariableId, 0);
     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));
 
 }
@@ -125,19 +123,16 @@ int main(void) {
     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);
 
     addVariableType2DPoint(server);
     addVariable(server);
     addVariableFail(server);
+    writeVariable(server);
 
-    UA_Server_run(server, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     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
-*  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_
 #define UA_CLIENT_H_
@@ -9,12 +9,11 @@
 extern "C" {
 #endif
 
-#include "ua_config.h"
 #include "ua_types.h"
-#include "ua_connection.h"
-#include "ua_log.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated_handling.h"
+#include "ua_plugin_network.h"
+#include "ua_plugin_log.h"
 
 /**
  * .. _client:
@@ -35,74 +34,59 @@ extern "C" {
  *
  * Client Configuration
  * -------------------- */
-typedef UA_Connection
-(*UA_ConnectClientConnection)(UA_ConnectionConfig localConf,
-                              const char *endpointUrl, UA_Logger logger);
 
 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
                                         to be renewed) */
     UA_Logger logger;
     UA_ConnectionConfig localConnectionConfig;
     UA_ConnectClientConnection connectionFunc;
+
+    /* Custom DataTypes */
+    size_t customDataTypesSize;
+    const UA_DataType *customDataTypes;
 } UA_ClientConfig;
 
 /**
  * Client Lifecycle
  * ---------------- */
+
 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;
 
 struct 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 */
-UA_ClientState UA_EXPORT UA_Client_getState(UA_Client *client);
+UA_ClientState UA_EXPORT
+UA_Client_getState(UA_Client *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 */
-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 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);
 
 /* 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 */
-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:
  *
- * Raw Services
- * ------------
+ * Services
+ * --------
  * 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``
  * that wrap the raw services. */
@@ -350,6 +405,30 @@ UA_Client_Service_publish(UA_Client *client, const UA_PublishRequest request) {
 
 #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::
  *

+ 39 - 7
include/ua_client_highlevel.h

@@ -1,6 +1,6 @@
 /* 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_
 #define UA_CLIENT_HIGHLEVEL_H_
@@ -152,8 +152,8 @@ UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
 
 UA_StatusCode UA_EXPORT
 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
 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_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
 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_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 */
 UA_StatusCode UA_EXPORT
 __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
@@ -558,7 +575,7 @@ typedef struct {
     UA_Byte priority;
 } 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_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_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,
                                                  UA_DataValue *value,
                                                  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
-*  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_
 #define UA_CONFIG_H_
@@ -10,8 +10,8 @@ extern "C" {
 #endif
 
 /**
- * Library Version
- * --------------- */
+ * open62541 Version
+ * ----------------- */
 #define UA_OPEN62541_VER_MAJOR ${OPEN62541_VER_MAJOR}
 #define UA_OPEN62541_VER_MINOR ${OPEN62541_VER_MINOR}
 #define UA_OPEN62541_VER_PATCH ${OPEN62541_VER_PATCH}
@@ -19,59 +19,89 @@ extern "C" {
 #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}
 #cmakedefine UA_ENABLE_METHODCALLS
 #cmakedefine UA_ENABLE_NODEMANAGEMENT
 #cmakedefine UA_ENABLE_SUBSCRIPTIONS
 #cmakedefine UA_ENABLE_MULTITHREADING
 
-/**
- * Advanced Options
- * ---------------- */
+/* Advanced Options */
 #cmakedefine UA_ENABLE_STATUSCODE_DESCRIPTIONS
 #cmakedefine UA_ENABLE_TYPENAMES
-#cmakedefine UA_ENABLE_EMBEDDED_LIBC
 #cmakedefine UA_ENABLE_DETERMINISTIC_RNG
 #cmakedefine UA_ENABLE_GENERATE_NAMESPACE0
-#cmakedefine UA_ENABLE_NONSTANDARD_STATELESS
 #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 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
 # include <stdint.h>
+# include <stdbool.h> /* C99 Boolean */
 #else
 # 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
 
-#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
 
-#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
- * ---------------
- * 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__)
 # include <malloc.h>
 #endif
@@ -97,6 +127,7 @@ typedef uint8_t bool;
  * order to export symbols for a DLL. Define ``UA_DYNAMIC_LINKING`` only to
  * import symbols from a DLL.*/
 #cmakedefine UA_DYNAMIC_LINKING
+
 #if defined(_WIN32) && defined(UA_DYNAMIC_LINKING)
 # ifdef UA_DYNAMIC_LINKING_EXPORT /* export dll */
 #  ifdef __GNUC__
@@ -143,36 +174,31 @@ typedef uint8_t bool;
 /**
  * Function attributes
  * ------------------- */
-#ifdef __GNUC__
+#if defined(__GNUC__) || defined(__clang__)
 # define UA_FUNC_ATTR_MALLOC __attribute__((malloc))
 # define UA_FUNC_ATTR_PURE __attribute__ ((pure))
 # define UA_FUNC_ATTR_CONST __attribute__((const))
 # define UA_FUNC_ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+# define UA_FORMAT(X,Y) __attribute__ ((format (printf, X, Y)))
 #else
 # define UA_FUNC_ATTR_MALLOC
 # define UA_FUNC_ATTR_PURE
 # define UA_FUNC_ATTR_CONST
 # define UA_FUNC_ATTR_WARN_UNUSED_RESULT
+# define UA_FORMAT(X,Y)
 #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
-  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
 
 /**
- * Binary Encoding Overlays
- * ------------------------
+ * Detect Binary Overlaying for Encoding
+ * -------------------------------------
  * Integers and floating point numbers are transmitted in little-endian (IEEE 754
  * for floating point) encoding. If the target architecture uses the same
  * 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. */
 #if defined(_WIN32) || (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
                         (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
-# define UA_BINARY_OVERLAYABLE_INTEGER true
+# define UA_BINARY_OVERLAYABLE_INTEGER 1
 #elif defined(__ANDROID__) /* Andoid */
 # include <endian.h>
 # if __BYTE_ORDER == __LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 #elif defined(__linux__) /* Linux */
 # include <endian.h>
 # if __BYTE_ORDER == __LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 # if __FLOAT_BYTE_ORDER == __LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_FLOAT true
+#  define UA_BINARY_OVERLAYABLE_FLOAT 1
 # endif
 #elif defined(__OpenBSD__) /* OpenBSD */
 # include <sys/endian.h>
 # if BYTE_ORDER == LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 #elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) /* Other BSD */
 # include <sys/endian.h>
 # if _BYTE_ORDER == _LITTLE_ENDIAN
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 #elif defined(__APPLE__) /* Apple (MacOS, iOS) */
 # include <libkern/OSByteOrder.h>
 # if defined(__LITTLE_ENDIAN__)
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 #elif defined(__QNX__) || defined(__QNXNTO__) /* QNX */
 # include <gulliver.h>
 # if defined(__LITTLEENDIAN__)
-#  define UA_BINARY_OVERLAYABLE_INTEGER true
+#  define UA_BINARY_OVERLAYABLE_INTEGER 1
 # endif
 #endif
 
 #ifndef UA_BINARY_OVERLAYABLE_INTEGER
-# define UA_BINARY_OVERLAYABLE_INTEGER false
+# define UA_BINARY_OVERLAYABLE_INTEGER 0
 #endif
 
 /**
@@ -232,40 +258,19 @@ typedef uint8_t bool;
  * this cannot be reliable detected with macros for the clang compiler
  * (beginning of 2017). Just override if necessary. */
 #if defined(_WIN32)
-# define UA_BINARY_OVERLAYABLE_FLOAT true
+# define UA_BINARY_OVERLAYABLE_FLOAT 1
 #elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
     (__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) && \
     (__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
 
 #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
 
 #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_ */

文件差异内容过多而无法显示
+ 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
-*  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
 extern "C" {
@@ -32,10 +39,11 @@ extern "C" {
  * section on :ref:`ReferenceTypes <referencetypenode>` for more details on
  * 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
  * --------------------
@@ -48,6 +56,15 @@ extern "C" {
  * 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
  * 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                  \
     UA_NodeId nodeId;                           \
     UA_NodeClass nodeClass;                     \
@@ -55,9 +72,11 @@ extern "C" {
     UA_LocalizedText displayName;               \
     UA_LocalizedText description;               \
     UA_UInt32 writeMask;                        \
-    UA_UInt32 userWriteMask;                    \
     size_t referencesSize;                      \
-    UA_ReferenceNode *references;
+    UA_NodeReferenceKind *references;           \
+                                                \
+    /* Members specific to open62541 */         \
+    void *context;
 
 typedef struct {
     UA_NODE_BASEATTRIBUTES
@@ -128,6 +147,7 @@ typedef struct {
  *
  * Consistency between the array dimensions attribute in the variable and its
  * :ref:`variabletypenode` is ensured. */
+
 /* Indicates whether a variable contains data inline or whether it points to an
  * external data source */
 typedef enum {
@@ -156,7 +176,6 @@ typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
     UA_Byte accessLevel;
-    UA_Byte userAccessLevel;
     UA_Double minimumSamplingInterval;
     UA_Boolean historizing; /* currently unsupported */
 } UA_VariableNode;
@@ -173,10 +192,14 @@ typedef struct {
  * variable type may provide semantic information. For example, an instance from
  * ``MotorTemperatureVariableType`` is more meaningful than a float variable
  * instantiated from ``BaseDataVariable``. */
+
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_NODE_VARIABLEATTRIBUTES
     UA_Boolean isAbstract;
+
+    /* Members specific to open62541 */
+    UA_NodeTypeLifecycle lifecycle;
 } UA_VariableTypeNode;
 
 /**
@@ -195,16 +218,14 @@ typedef struct {
  *
  * 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
- * providing context* is part of a Call request message.
- */
+ * providing context* is part of a Call request message. */
+
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Boolean executable;
-    UA_Boolean userExecutable;
 
     /* Members specific to open62541 */
-    void *methodHandle;
-    UA_MethodCallback attachedMethod;
+    UA_MethodCallback method;
 } UA_MethodNode;
 
 /**
@@ -215,12 +236,10 @@ typedef struct {
  * and software objects. Objects are instances of an :ref:`object
  * type<objecttypenode>` and may contain variables, methods and further
  * objects. */
+
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Byte eventNotifier;
-
-    /* Members specific to open62541 */
-    void *instanceHandle;
 } UA_ObjectNode;
 
 /**
@@ -230,14 +249,15 @@ typedef struct {
  * --------------
  *
  * 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. */
+
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Boolean isAbstract;
 
     /* Members specific to open62541 */
-    UA_ObjectLifecycleManagement lifecycleManagement;
+    UA_NodeTypeLifecycle lifecycle;
 } UA_ObjectTypeNode;
 
 /**
@@ -342,6 +362,7 @@ typedef struct {
  * electrical and information related connections. A client can then learn the
  * layout of a (physical) system represented in an OPC UA information model
  * based on a common understanding of just two custom reference types. */
+
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Boolean isAbstract;
@@ -363,6 +384,7 @@ typedef struct {
  * Abstract DataTypes (e.g. ``Number``) cannot be the type of actual values.
  * They are used to constrain values to possible child DataTypes (e.g.
  * ``UInt32``). */
+
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Boolean isAbstract;
@@ -377,14 +399,112 @@ typedef struct {
  * references only. ViewNodes can be created and be interacted with. But their
  * use in the :ref:`Browse<view-services>` service is currently unsupported in
  * open62541. */
+
 typedef struct {
     UA_NODE_BASEATTRIBUTES
     UA_Byte eventNotifier;
     UA_Boolean containsNoLoops;
 } 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
 } // extern "C"
 #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
-*  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_
 #define UA_SERVER_H_
@@ -9,14 +9,15 @@
 extern "C" {
 #endif
 
-#include "ua_config.h"
 #include "ua_types.h"
 #include "ua_types_generated.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:
@@ -24,123 +25,16 @@ extern "C" {
  * 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
  * ---------------- */
-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);
 
 /* 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 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
  * 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.
  *
@@ -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.
  *        The default max wait time is 50millisec.
  * @return Returns how long we can wait until the next scheduled
- *         job (in millisec) */
+ *         callback (in ms) */
 UA_UInt16 UA_EXPORT
 UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal);
 
 /* The epilogue part of UA_Server_run (no need to use if you call
  * UA_Server_run) */
-UA_StatusCode UA_EXPORT UA_Server_run_shutdown(UA_Server *server);
+UA_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 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
  *        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.
  *         An error code otherwise. */
 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 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.
  *         An error code otherwise. */
 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
@@ -370,13 +272,14 @@ UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId,
  * - ContainsNoLoop
  *
  * 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
  * - UserAccessLevel
  * - UserExecutable
  *
  * Historizing is currently unsupported */
+
 /* Overwrite an attribute of a node. The specialized functions below provide a
  * more concise syntax.
  *
@@ -525,36 +428,205 @@ UA_StatusCode UA_EXPORT
 UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
                                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:
  *
  * Data Source Callback
- * ~~~~~~~~~~~~~~~~~~~~
+ * ^^^^^^^^^^^^^^^^^^^^
  *
  * 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
@@ -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
  * be set to a null-pointer. */
 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.
      *
      * @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
      *         original caller are set in the value. If an error is returned,
      *         then no releasing of the value is done. */
-    UA_StatusCode (*read)(void *handle, 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);
 
     /* 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 range An optional data range. If the data source is scalar or does
      *        not support writing of ranges, then an error code is returned.
-     * @return Returns a status code that is returned to the user
-     */
-    UA_StatusCode (*write)(void *handle, const UA_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_StatusCode UA_EXPORT
@@ -611,13 +683,10 @@ UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  * .. _value-callback:
  *
  * Value Callback
- * ~~~~~~~~~~~~~~
+ * ^^^^^^^^^^^^^^
  * 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 {
-    /* Pointer to user-provided data for the callback */
-    void *handle;
-
     /* 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
      * 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 range Points to the numeric range the client wants to read from
      *        (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
      * 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 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
      *        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_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);
 
-/**
- * .. _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 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
-(*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
+
 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
 
 /**
  * .. _addnodes:
  *
  * Node Addition and Deletion
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
- *
+ * --------------------------
  * 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
  * reference it later. When passing numeric NodeIds with a numeric identifier 0,
  * 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
  * 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
  * 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
- * 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. */
 UA_StatusCode UA_EXPORT
 __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
-                    const UA_NodeId requestedNewNodeId,
-                    const UA_NodeId parentNodeId,
-                    const UA_NodeId referenceTypeId,
+                    const UA_NodeId *requestedNewNodeId,
+                    const UA_NodeId *parentNodeId,
+                    const UA_NodeId *referenceTypeId,
                     const UA_QualifiedName browseName,
-                    const UA_NodeId typeDefinition,
+                    const UA_NodeId *typeDefinition,
                     const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType,
-                    UA_InstantiationCallback *instantiationCallback,
-                    UA_NodeId *outNewNodeId);
+                    void *nodeContext, UA_NodeId *outNewNodeId);
 
 static UA_INLINE UA_StatusCode
 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_NodeId typeDefinition,
                           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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -749,14 +831,13 @@ UA_Server_addVariableTypeNode(UA_Server *server,
                               const UA_QualifiedName browseName,
                               const UA_NodeId typeDefinition,
                               const UA_VariableTypeAttributes attr,
-                              UA_InstantiationCallback *instantiationCallback,
-                              UA_NodeId *outNewNodeId) {
+                              void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE,
-                               requestedNewNodeId, parentNodeId, referenceTypeId,
-                               browseName, typeDefinition,
+                               &requestedNewNodeId, &parentNodeId, &referenceTypeId,
+                               browseName, &typeDefinition,
                                (const UA_NodeAttributes*)&attr,
                                &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 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_NodeId typeDefinition,
                         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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 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_QualifiedName browseName,
                             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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 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_QualifiedName browseName,
                       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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -812,14 +890,13 @@ UA_Server_addReferenceTypeNode(UA_Server *server,
                                const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName,
                                const UA_ReferenceTypeAttributes attr,
-                               UA_InstantiationCallback *instantiationCallback,
-                               UA_NodeId *outNewNodeId) {
+                               void *nodeContext, UA_NodeId *outNewNodeId) {
     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,
                                &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -829,13 +906,12 @@ UA_Server_addDataTypeNode(UA_Server *server,
                           const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName,
                           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],
-                               instantiationCallback, outNewNodeId);
+                               nodeContext, outNewNodeId);
 }
 
 UA_StatusCode UA_EXPORT
@@ -847,23 +923,53 @@ UA_Server_addDataSourceVariableNode(UA_Server *server,
                                     const UA_NodeId typeDefinition,
                                     const UA_VariableAttributes attr,
                                     const UA_DataSource dataSource,
-                                    UA_NodeId *outNewNodeId);
+                                    void *nodeContext, UA_NodeId *outNewNodeId);
 
-#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId,
                         const UA_NodeId referenceTypeId,
                         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_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
                      UA_Boolean deleteReferences);
@@ -882,6 +988,54 @@ UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                           const UA_ExpandedNodeId targetNodeId,
                           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
 }
 #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
  * 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_
 #define UA_TYPES_H_
@@ -12,6 +12,8 @@ extern "C" {
 #include "ua_config.h"
 #include "ua_constants.h"
 
+#define UA_BUILTIN_TYPES_COUNT 25U
+
 /**
  * .. _types:
  *
@@ -20,7 +22,7 @@ extern "C" {
  *
  * 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,
- * 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
  * looked up at https://opcfoundation.org/UA/schemas/Opc.Ua.Types.bsd.xml.
  *
@@ -29,11 +31,8 @@ extern "C" {
  * implementation details.
  *
  * Builtin Types
- * ------------- */
-
-#define UA_BUILTIN_TYPES_COUNT 25U
-
-/**
+ * -------------
+ *
  * Boolean
  * ^^^^^^^
  * A two-state logical value (true or false). */
@@ -128,26 +127,13 @@ typedef double UA_Double;
  * specific code. */
 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
@@ -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_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
  * of the char-array. */
 static UA_INLINE UA_String
@@ -191,6 +177,9 @@ typedef int64_t UA_DateTime;
 #define UA_USEC_TO_DATETIME 10LL
 #define UA_MSEC_TO_DATETIME (UA_USEC_TO_DATETIME * 1000LL)
 #define UA_SEC_TO_DATETIME (UA_MSEC_TO_DATETIME * 1000LL)
+#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 */
 #define UA_DATETIME_UNIX_EPOCH (11644473600LL * UA_SEC_TO_DATETIME)
@@ -359,6 +348,8 @@ typedef struct {
     UA_UInt32 serverIndex;
 } UA_ExpandedNodeId;
 
+UA_EXPORT extern const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL;
+
 /** The following functions are shorthand for creating ExpandedNodeIds. */
 static UA_INLINE UA_ExpandedNodeId
 UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier) {
@@ -509,7 +500,7 @@ typedef struct UA_DataType UA_DataType;
 typedef enum {
     UA_VARIANT_DATA,          /* The data has the same lifecycle as the
                                  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
                                  variant's lifecycle. */
 } UA_VariantStorageType;
@@ -743,8 +734,7 @@ typedef struct UA_DiagnosticInfo {
  *   memory for the data type itself.
  *
  * 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 {
 #ifdef UA_ENABLE_TYPENAMES
@@ -775,8 +765,8 @@ struct UA_DataType {
     UA_Byte    membersSize;      /* How many members does the type have? */
     UA_Boolean builtin      : 1; /* The type is "builtin" and has dedicated de-
                                     and encoding functions */
-    UA_Boolean fixedSize    : 1; /* The type (and its members) contains no
-                                    pointers */
+    UA_Boolean 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
                                     memory and on the binary stream. */
     UA_UInt16  binaryEncodingId; /* NodeId of datatype when encoded as binary */
@@ -784,10 +774,19 @@ struct UA_DataType {
     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
  * 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. */
+
 /* Returns the data type description for the type's identifier or NULL if no
  * matching data type was found. */
 const UA_DataType UA_EXPORT *
@@ -896,6 +895,31 @@ UA_Guid UA_EXPORT UA_Guid_random(void);     /* no cryptographic entropy */
  * .. toctree::
  *
  *    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
 } // extern "C"
 #endif

+ 13 - 4
open62541.spec

@@ -1,12 +1,12 @@
 Name:     open62541
-Version:  0.2
+Version:  0.3
 Release:  1%{?dist}
 Summary:  OPC UA implementation
 License:  MPLv2.0
 URL:      http://open62541.org
 Source0:  https://github.com/open62541/open62541/archive/%{name}-%{version}.tar.gz
 
-BuildRequires: cmake, python
+BuildRequires: cmake3, python
 
 %description
 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
 
 %build
-%cmake -DUA_ENABLE_AMALGAMATION=ON .
+%cmake3 -DUA_ENABLE_AMALGAMATION=ON .
 make
 
 %install
@@ -46,11 +46,20 @@ rm examples/CMakeLists.txt
 %files devel
 %license LICENSE LICENSE-CC0
 %{_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 examples/
 
 %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
 - 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.
  * 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>
 #ifdef _WIN32
+/* Backup definition of SLIST_ENTRY on mingw winnt.h */
 # 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
 # include <windows.h>
+/* restore definition */
+# ifdef POP_SLIST_ENTRY
+#  undef SLIST_ENTRY
+#  undef POP_SLIST_ENTRY
+#  pragma pop_macro("SLIST_ENTRY")
+# endif
 #else
 # include <sys/time.h>
 #endif
@@ -18,6 +38,8 @@
 # include <mach/mach.h>
 #endif
 
+#include "ua_types.h"
+
 UA_DateTime UA_DateTime_now(void) {
 #if defined(_WIN32)
     /* 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;
 #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
-
 void
 UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
               const char *msg, va_list args) {
@@ -28,7 +26,7 @@ UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
 #ifdef UA_ENABLE_MULTITHREADING
     pthread_mutex_lock(&printf_mutex);
 #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);
     printf("\n");
     fflush(stdout);
@@ -37,8 +35,3 @@ UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
 #endif
     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_
 #define UA_LOG_STDOUT_H_
 
-#include "ua_types.h"
-#include "ua_log.h"
+#include "ua_plugin_log.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-UA_EXPORT void
+void UA_EXPORT
 UA_Log_Stdout(UA_LogLevel level, UA_LogCategory category,
               const char *msg, va_list args);
 

文件差异内容过多而无法显示
+ 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_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
 } // extern "C"

+ 20 - 15
plugins/ua_network_udp.c

@@ -2,7 +2,6 @@
  * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
 
 #include "ua_network_udp.h"
-#include <stdlib.h> // malloc, free
 #include <stdio.h>
 #include <string.h> // memset
 
@@ -14,7 +13,11 @@
 # include <errno.h> // errno, EINTR
 # include <fcntl.h> // fcntl
 # 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/tcp.h>
 # include <sys/socketvar.h>
@@ -121,20 +124,22 @@ static void setFDSet(ServerNetworkLayerUDP *layer) {
 }
 
 static void closeConnectionUDP(UA_Connection *handle) {
-    free(handle);
+    UA_free(handle);
 }
 
 static UA_StatusCode ServerNetworkLayerUDP_start(UA_ServerNetworkLayer *nl, UA_Logger logger) {
     ServerNetworkLayerUDP *layer = nl->handle;
     layer->logger = logger;
-    layer->serversockfd = socket(PF_INET, SOCK_DGRAM, 0);
+    layer->serversockfd = socket(AF_INET6, SOCK_DGRAM, 0);
     if(layer->serversockfd < 0) {
         UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
         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;
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
@@ -164,12 +169,12 @@ static size_t ServerNetworkLayerUDP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **
         *jobs = items;
         return 0;
     }
-    items = malloc(sizeof(UA_Job)*(unsigned long)resultsize);
+    items = UA_malloc(sizeof(UA_Job)*(unsigned long)resultsize);
     // read from established sockets
     size_t j = 0;
     UA_ByteString buf = {0, NULL};
     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)
             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);
     if (rec_result > 0) {
         buf.length = (size_t)rec_result;
-        UDPConnection *c = malloc(sizeof(UDPConnection));
+        UDPConnection *c = UA_malloc(sizeof(UDPConnection));
         if(!c){
-                free(items);
+                UA_free(items);
             return UA_STATUSCODE_BADINTERNALERROR;
         }
         UA_Connection_init(&c->connection);
@@ -204,11 +209,11 @@ static size_t ServerNetworkLayerUDP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **
         j++;
         *jobs = items;
     } else {
-        free(items);
+        UA_free(items);
         *jobs = NULL;
     }
     if(buf.data)
-        free(buf.data);
+        UA_free(buf.data);
     return j;
 }
 
@@ -222,7 +227,7 @@ static size_t ServerNetworkLayerUDP_stop(UA_ServerNetworkLayer *nl, UA_Job **job
 
 static void ServerNetworkLayerUDP_deleteMembers(UA_ServerNetworkLayer *nl) {
     ServerNetworkLayerUDP *layer = nl->handle;
-    free(layer);
+    UA_free(layer);
     UA_String_deleteMembers(&nl->discoveryUrl);
 }
 
@@ -231,7 +236,7 @@ UA_ServerNetworkLayerUDP(UA_ConnectionConfig conf, UA_UInt16 port) {
     UA_ServerNetworkLayer nl;
     memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
 
-    ServerNetworkLayerUDP *layer = malloc(sizeof(ServerNetworkLayerUDP));
+    ServerNetworkLayerUDP *layer = UA_malloc(sizeof(ServerNetworkLayerUDP));
     if(!layer)
         return nl;
     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_ */

文件差异内容过多而无法显示
+ 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
-*  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_highlevel.h"
 #include "ua_util.h"
-#include "ua_nodeids.h"
 
 UA_StatusCode
 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;
-    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){
         if(UA_String_equal(namespaceUri, &ns[i])) {
             *namespaceIndex = (UA_UInt16)i;
@@ -51,35 +50,31 @@ UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
 UA_StatusCode
 UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId,
                                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 typeDefinition, const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_AddNodesRequest request;
     UA_AddNodesRequest_init(&request);
     UA_AddNodesItem item;
@@ -199,20 +193,25 @@ __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
     request.nodesToAdd = &item;
     request.nodesToAddSize = 1;
     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);
         return retval;
     }
+
     if(response.resultsSize != 1) {
         UA_AddNodesResponse_deleteMembers(&response);
         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;
         UA_NodeId_init(&response.results[0].addedNodeId);
     }
-    retval = response.results[0].statusCode;
+
     UA_AddNodesResponse_deleteMembers(&response);
     return retval;
 }
@@ -235,7 +234,7 @@ UA_Client_call(UA_Client *client, const UA_NodeId objectId,
     UA_CallMethodRequest_init(&item);
     item.methodId = methodId;
     item.objectId = objectId;
-    item.inputArguments = (void*)(uintptr_t)input; // cast const...
+    item.inputArguments = (UA_Variant *)(void*)(uintptr_t)input; // cast const...
     item.inputArgumentsSize = inputSize;
     request.methodsToCall = &item;
     request.methodsToCallSize = 1;
@@ -309,8 +308,8 @@ __UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,
 
 UA_StatusCode
 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)
       return UA_STATUSCODE_BADTYPEMISMATCH;
 
@@ -400,10 +399,39 @@ __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
     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_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_init(&item);
     item.nodeId = nodeId;
@@ -412,39 +440,10 @@ UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId
     UA_ReadRequest_init(&request);
     request.nodesToRead = &item;
     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);
     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
-*  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_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_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) {
-        retval = UA_STATUSCODE_BADOUTOFMEMORY;
-        goto cleanup;
+        UA_CreateSubscriptionResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
     LIST_INIT(&newSub->monitoredItems);
@@ -43,19 +45,24 @@ UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
     if(newSubscriptionId)
         *newSubscriptionId = newSub->subscriptionID;
 
- cleanup:
     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) {
         if(sub->subscriptionID == subscriptionId)
             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)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
@@ -104,21 +111,104 @@ UA_Client_Subscriptions_forceDelete(UA_Client *client,
     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_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_NodeId nodeId, UA_UInt32 attributeID,
                                          UA_MonitoredItemHandlingFunction hf,
                                          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)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
     /* 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)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
@@ -178,11 +268,7 @@ UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscripti
 UA_StatusCode
 UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
                                             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)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
 
@@ -226,19 +312,10 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
         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)
         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 */
     for(size_t i = 0; i < response->resultsSize && i < request->subscriptionAcknowledgementsSize; ++i) {
         /* 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)
             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 */
-    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) {
         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;
     }
     tmpAck->subAck.sequenceNumber = msg->sequenceNumber;
@@ -302,7 +399,7 @@ UA_Client_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
 
 UA_StatusCode
 UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
-    if (client->state == UA_CLIENTSTATE_ERRORED)
+    if(client->state < UA_CLIENTSTATE_SESSION)
         return UA_STATUSCODE_BADSERVERNOTCONNECTED;
 
     UA_Boolean moreNotifications = true;
@@ -315,10 +412,10 @@ UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
             ++request.subscriptionAcknowledgementsSize;
         if(request.subscriptionAcknowledgementsSize > 0) {
-            request.subscriptionAcknowledgements =
+            request.subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement*)
                 UA_malloc(sizeof(UA_SubscriptionAcknowledgement) * request.subscriptionAcknowledgementsSize);
             if(!request.subscriptionAcknowledgements)
-                return UA_STATUSCODE_GOOD;
+                return UA_STATUSCODE_BADOUTOFMEMORY;
         }
 
         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
-*  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_
 #define UA_CLIENT_INTERNAL_H_
@@ -8,9 +8,9 @@
 #include "ua_securechannel.h"
 #include "queue.h"
 
-/**************************/
-/* Subscriptions Handling */
-/**************************/
+ /**************************/
+ /* Subscriptions Handling */
+ /**************************/
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 
@@ -29,8 +29,10 @@ typedef struct UA_Client_MonitoredItem {
     UA_Double samplingInterval;
     UA_UInt32 queueSize;
     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(*handlerEvents)(const UA_UInt32 monId, const size_t nEventFields, const UA_Variant *eventFields, void *context);
+    void *handlerEventsContext;
 } UA_Client_MonitoredItem;
 
 typedef struct UA_Client_Subscription {
@@ -52,6 +54,14 @@ void UA_Client_Subscriptions_forceDelete(UA_Client *client, UA_Client_Subscripti
 /* Client */
 /**********/
 
+typedef struct AsyncServiceCall {
+    LIST_ENTRY(AsyncServiceCall) pointers;
+    UA_UInt32 requestId;
+    UA_ClientAsyncServiceCallback callback;
+    const UA_DataType *responseType;
+    void *userdata;
+} AsyncServiceCall;
+
 typedef enum {
     UA_CLIENTAUTHENTICATION_NONE,
     UA_CLIENTAUTHENTICATION_USERNAME
@@ -67,6 +77,7 @@ struct UA_Client {
     UA_String endpointUrl;
 
     /* SecureChannel */
+    UA_SecurityPolicy securityPolicy;
     UA_SecureChannel channel;
     UA_UInt32 requestId;
     UA_DateTime nextChannelRenewal;
@@ -80,7 +91,10 @@ struct UA_Client {
     UA_UserTokenPolicy token;
     UA_NodeId authenticationToken;
     UA_UInt32 requestHandle;
-    
+
+    /* Async Service */
+    LIST_HEAD(ListOfAsyncServiceCall, AsyncServiceCall) asyncServiceCalls;
+
     /* Subscriptions */
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     UA_UInt32 monitoredItemHandles;
@@ -89,4 +103,18 @@ struct UA_Client {
 #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_ */

+ 0 - 0
src/server/ua_mdns.c


部分文件因为文件数量过多而无法显示