Ver código fonte

Merge branch 'master' into client_getEndpoints

Conflicts:
	examples/client.c
Stasik0 9 anos atrás
pai
commit
a883dc3145
75 arquivos alterados com 2560 adições e 2375 exclusões
  1. 11 11
      CMakeLists.txt
  2. 17 17
      README.md
  3. 6 6
      deps/pcg_basic.c
  4. 4 4
      deps/pcg_basic.h
  5. 79 72
      doc/tutorial_client_firstSteps.rst
  6. 80 65
      doc/tutorial_server_firstSteps.rst
  7. 2 2
      doc/tutorial_server_variables.rst
  8. 6 6
      examples/client.c
  9. 3 2
      examples/client_firstSteps.c
  10. 29 16
      examples/server.c
  11. 11 7
      examples/server.cpp
  12. 23 14
      examples/server_datasource.c
  13. 12 12
      examples/server_firstSteps.c
  14. 15 11
      examples/server_method.c
  15. 10 6
      examples/server_nodeset.c
  16. 9 4
      examples/server_readspeed.c
  17. 8 4
      examples/server_repeated_job.c
  18. 10 8
      examples/server_variable.c
  19. 2 3
      include/ua_client.h
  20. 1 1
      include/ua_client_highlevel.h
  21. 7 2
      include/ua_config.h.in
  22. 72 67
      include/ua_server.h
  23. 5 5
      include/ua_types.h
  24. 13 8
      src/client/ua_client.c
  25. 3 3
      src/client/ua_client_highlevel.c
  26. 2 2
      src/client/ua_client_highlevel_subscriptions.c
  27. 18 18
      src/client/ua_client_internal.h
  28. 109 345
      src/server/ua_nodes.c
  29. 6 20
      src/server/ua_nodes.h
  30. 141 126
      src/server/ua_nodestore.c
  31. 32 48
      src/server/ua_nodestore.h
  32. 96 138
      src/server/ua_nodestore_concurrent.c
  33. 10 8
      src/server/ua_nodestore_hash.inc
  34. 4 4
      src/server/ua_securechannel_manager.h
  35. 194 256
      src/server/ua_server.c
  36. 27 12
      src/server/ua_server_binary.c
  37. 17 21
      src/server/ua_server_internal.h
  38. 131 150
      src/server/ua_server_worker.c
  39. 2 2
      src/server/ua_services.h
  40. 65 60
      src/server/ua_services_attribute.c
  41. 1 1
      src/server/ua_services_call.c
  42. 51 11
      src/server/ua_services_discovery.c
  43. 118 121
      src/server/ua_services_nodemanagement.c
  44. 6 6
      src/server/ua_services_securechannel.c
  45. 13 13
      src/server/ua_services_session.c
  46. 8 7
      src/server/ua_services_subscription.c
  47. 14 14
      src/server/ua_services_view.c
  48. 4 4
      src/server/ua_session_manager.h
  49. 21 17
      src/server/ua_subscription.c
  50. 7 7
      src/server/ua_subscription.h
  51. 11 8
      src/server/ua_subscription_manager.c
  52. 11 8
      src/server/ua_subscription_manager.h
  53. 18 5
      src/ua_connection.c
  54. 14 3
      src/ua_securechannel.c
  55. 0 14
      src/ua_session.c
  56. 1 2
      src/ua_session.h
  57. 22 11
      src/ua_types.c
  58. 624 386
      src/ua_types_encoding_binary.c
  59. 4 2
      src/ua_types_encoding_binary.h
  60. 23 9
      src/ua_util.h
  61. 4 4
      examples/logger_stdout.c
  62. 0 0
      src_extra/logger_stdout.h
  63. 106 79
      examples/networklayer_tcp.c
  64. 3 2
      examples/networklayer_tcp.h
  65. 0 0
      src_extra/networklayer_udp.c
  66. 0 0
      src_extra/networklayer_udp.h
  67. 2 0
      tests/CMakeLists.txt
  68. 19 5
      tests/check_builtin.c
  69. 19 0
      tests/check_memory.c
  70. 53 48
      tests/check_nodestore.c
  71. 46 10
      tests/check_services_attributes.c
  72. 32 3
      tests/check_services_nodemanagement.c
  73. 3 3
      tools/pyUANamespace/open62541_MacroHelper.py
  74. 3 3
      tools/pyUANamespace/ua_builtin_types.py
  75. 7 3
      tools/pyUANamespace/ua_node_types.py

+ 11 - 11
CMakeLists.txt

@@ -58,14 +58,14 @@ list(APPEND open62541_LIBRARIES "")
 # compiler flags
 # compiler flags
 if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
 if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
     add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat -Wno-unused-parameter
     add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat -Wno-unused-parameter
-                    -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
-                    -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes #-Wshadow #-Wconversion
+                    -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare
+                    -Wmultichar -Wstrict-overflow -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes
                     -Winit-self -Wuninitialized -Wformat-security -Wformat-nonliteral)
                     -Winit-self -Wuninitialized -Wformat-security -Wformat-nonliteral)
 
 
   # library linking
   # library linking
   set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
   set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
   if(NOT WIN32 AND NOT CYGWIN)
   if(NOT WIN32 AND NOT CYGWIN)
-	add_definitions(-fvisibility=hidden -fPIC)
+	add_definitions(-Wshadow -Wconversion -fvisibility=hidden -fPIC)
     if(NOT APPLE)
     if(NOT APPLE)
       set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
       set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
     endif()
     endif()
@@ -131,7 +131,6 @@ option(UA_ENABLE_TYPENAMES "Add the type and member names to the UA_DataType str
 mark_as_advanced(UA_ENABLE_TYPENAMES)
 mark_as_advanced(UA_ENABLE_TYPENAMES)
 
 
 option(UA_ENABLE_GENERATE_NAMESPACE0 "Generate and load UA XML Namespace 0 definition" OFF)
 option(UA_ENABLE_GENERATE_NAMESPACE0 "Generate and load UA XML Namespace 0 definition" OFF)
-mark_as_advanced(UA_ENABLE_GENERATE_NAMESPACE0)
 
 
 option(UA_ENABLE_EMBEDDED_LIBC "Target has no libc, use internal definitions" OFF)
 option(UA_ENABLE_EMBEDDED_LIBC "Target has no libc, use internal definitions" OFF)
 mark_as_advanced(UA_ENABLE_EMBEDDED_LIBC)
 mark_as_advanced(UA_ENABLE_EMBEDDED_LIBC)
@@ -179,11 +178,11 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server_external_ns.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server_external_ns.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
-                     ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h
-                     ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h)
-set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
-                     ${PROJECT_SOURCE_DIR}/deps/queue.h
+                     ${PROJECT_SOURCE_DIR}/src_extra/networklayer_tcp.h
+                     ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.h)
+set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_util.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
@@ -218,8 +217,8 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
-                ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c
-                ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
+                ${PROJECT_SOURCE_DIR}/src_extra/networklayer_tcp.c
+                ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.c
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
                 ##TODO: make client stuff optional
                 ##TODO: make client stuff optional
 
 
@@ -360,8 +359,9 @@ else()
     add_definitions(-DUA_NO_AMALGAMATION)
     add_definitions(-DUA_NO_AMALGAMATION)
     add_library(open62541-object OBJECT ${lib_sources} ${internal_headers} ${exported_headers})
     add_library(open62541-object OBJECT ${lib_sources} ${internal_headers} ${exported_headers})
     include_directories(${PROJECT_SOURCE_DIR}/include)
     include_directories(${PROJECT_SOURCE_DIR}/include)
-    include_directories(${PROJECT_SOURCE_DIR}/deps)
     include_directories(${PROJECT_SOURCE_DIR}/src)
     include_directories(${PROJECT_SOURCE_DIR}/src)
+    include_directories(${PROJECT_SOURCE_DIR}/src_extra)
+    include_directories(${PROJECT_SOURCE_DIR}/deps)
 endif()
 endif()
 target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING)
 target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING)
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)
 add_library(open62541 SHARED $<TARGET_OBJECTS:open62541-object>)

+ 17 - 17
README.md

@@ -36,11 +36,10 @@ With the GCC compiler, just run ```gcc -std=c99 <server.c> open62541.c -o server
 #include <signal.h>
 #include <signal.h>
 #include "open62541.h"
 #include "open62541.h"
 
 
-#define WORKER_THREADS 2 /* if multithreading is enabled */
 #define PORT 16664
 #define PORT 16664
 
 
 UA_Boolean running = UA_TRUE;
 UA_Boolean running = UA_TRUE;
-void signalHandler(int sign) {
+void signalHandler(int sig) {
     running = UA_FALSE;
     running = UA_FALSE;
 }
 }
 
 
@@ -50,18 +49,20 @@ int main(int argc, char** argv)
     signal(SIGINT, signalHandler);
     signal(SIGINT, signalHandler);
 
 
     /* init the server */
     /* init the server */
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, Logger_Stdout_new());
-    UA_Server_addNetworkLayer(server,
-        ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, PORT);
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
 
     /* add a variable node */
     /* add a variable node */
-    /* 1) set the variable attributes */
+    /* 1) set the variable attributes (no memory allocations here) */
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
     UA_VariableAttributes attr;
     UA_VariableAttributes attr;
     UA_VariableAttributes_init(&attr);
     UA_VariableAttributes_init(&attr);
-    UA_Variant_setScalarCopy(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US","the answer");
+    UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
 
 
     /* 2) define where the variable shall be added with which browsename */
     /* 2) define where the variable shall be added with which browsename */
     UA_NodeId newNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId newNodeId = UA_NODEID_STRING(1, "the.answer");
@@ -71,14 +72,13 @@ int main(int argc, char** argv)
     UA_QualifiedName browseName = UA_QUALIFIEDNAME(1, "the answer");
     UA_QualifiedName browseName = UA_QUALIFIEDNAME(1, "the answer");
 
 
     /* 3) add the variable */
     /* 3) add the variable */
-    UA_Server_addVariableNode(server, newNodeId, parentNodeId,
-                              parentReferenceNodeId, browseName,
-                              variableType, attr, NULL);
-    UA_VariableAttributes_deleteMembers(&attr);
+    UA_Server_addVariableNode(server, newNodeId, parentNodeId, parentReferenceNodeId,
+                              browseName, variableType, attr, NULL);
 
 
     /* run the server loop */
     /* run the server loop */
-    UA_StatusCode retval = UA_Server_run(server, WORKER_THREADS, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
     return retval;
     return retval;
 }
 }
 ```
 ```
@@ -91,8 +91,8 @@ int main(int argc, char** argv)
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
 {
 {
     /* create a client and connect */
     /* create a client and connect */
-    UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
-    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
+    UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
+    UA_StatusCode retval = UA_Client_connect(client, UA_ClientConnectionTCP,
                                              "opc.tcp://localhost:16664");
                                              "opc.tcp://localhost:16664");
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         UA_Client_delete(client);
@@ -102,7 +102,7 @@ int main(int argc, char *argv[])
     /* create a readrequest with one entry */
     /* create a readrequest with one entry */
     UA_ReadRequest req;
     UA_ReadRequest req;
     UA_ReadRequest_init(&req);
     UA_ReadRequest_init(&req);
-    req.nodesToRead = UA_ReadValueId_new();
+    req.nodesToRead = UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]);
     req.nodesToReadSize = 1;
     req.nodesToReadSize = 1;
     
     
     /* define the node and attribute to be read */
     /* define the node and attribute to be read */

+ 6 - 6
deps/pcg_basic.c

@@ -34,17 +34,17 @@
 
 
 static pcg32_random_t pcg32_global = PCG32_INITIALIZER;
 static pcg32_random_t pcg32_global = PCG32_INITIALIZER;
 
 
-// pcg32_srandom(initstate, initseq)
-// pcg32_srandom_r(rng, initstate, initseq):
+// pcg32_srandom(initial_state, initseq)
+// pcg32_srandom_r(rng, initial_state, initseq):
 //     Seed the rng.  Specified in two parts, state initializer and a
 //     Seed the rng.  Specified in two parts, state initializer and a
 //     sequence selection constant (a.k.a. stream id)
 //     sequence selection constant (a.k.a. stream id)
 
 
-void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
+void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq)
 {
 {
     rng->state = 0U;
     rng->state = 0U;
     rng->inc = (initseq << 1u) | 1u;
     rng->inc = (initseq << 1u) | 1u;
     pcg32_random_r(rng);
     pcg32_random_r(rng);
-    rng->state += initstate;
+    rng->state += initial_state;
     pcg32_random_r(rng);
     pcg32_random_r(rng);
 }
 }
 
 
@@ -61,8 +61,8 @@ uint32_t pcg32_random_r(pcg32_random_t* rng)
 {
 {
     uint64_t oldstate = rng->state;
     uint64_t oldstate = rng->state;
     rng->state = oldstate * 6364136223846793005ULL + rng->inc;
     rng->state = oldstate * 6364136223846793005ULL + rng->inc;
-    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
-    uint32_t rot = oldstate >> 59u;
+    uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u);
+    uint32_t rot = (uint32_t)(oldstate >> 59u);
     return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
     return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
 }
 }
 
 

+ 4 - 4
deps/pcg_basic.h

@@ -48,13 +48,13 @@ typedef struct pcg_state_setseq_64 pcg32_random_t;
 
 
 #define PCG32_INITIALIZER   { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
 #define PCG32_INITIALIZER   { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
 
 
-// pcg32_srandom(initstate, initseq)
-// pcg32_srandom_r(rng, initstate, initseq):
+// pcg32_srandom(initial_state, initseq)
+// pcg32_srandom_r(rng, initial_state, initseq):
 //     Seed the rng.  Specified in two parts, state initializer and a
 //     Seed the rng.  Specified in two parts, state initializer and a
 //     sequence selection constant (a.k.a. stream id)
 //     sequence selection constant (a.k.a. stream id)
 
 
-void pcg32_srandom(uint64_t initstate, uint64_t initseq);
-void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate,
+void pcg32_srandom(uint64_t initial_state, uint64_t initseq);
+void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state,
                      uint64_t initseq);
                      uint64_t initseq);
 
 
 // pcg32_random()
 // pcg32_random()

+ 79 - 72
doc/tutorial_client_firstSteps.rst

@@ -8,28 +8,34 @@ You should already have a basic server from the previous tutorial. open62541 pro
 As a recap, your directory structure should now look like this::
 As a recap, your directory structure should now look like this::
  
  
   :myApp> rm *.o open62541.*
   :myApp> rm *.o open62541.*
+  :myApp> cp ../open62541/build/open62541.h include/
   :myApp> ln -s ../open62541/build/*so ./
   :myApp> ln -s ../open62541/build/*so ./
   :myApp> tree
   :myApp> tree
   .
   .
-  +── include
-  │   +── logger_stdout.h
-  │   +── networklayer_tcp.h
-  │   +── networklayer_udp.h
-  │   +── open62541.h
-  │   +── ua_client.h
-  │   +── ua_config.h
-  │   +── ua_config.h.in
-  │   +── ua_connection.h
-  │   +── ua_log.h
-  │   +── ua_nodeids.h
-  │   +── ua_server.h
-  │   +── ua_statuscodes.h
-  │   +── ua_transport_generated.h
-  │   +── ua_types_generated.h
-  │   +── ua_types.h
-  +── libopen62541.so -> ../../open62541/build/libopen62541.so
-  +── myServer
-  +── myServer.c
+  ├── include
+  │   ├── logger_stdout.h
+  │   ├── networklayer_tcp.h
+  │   ├── networklayer_udp.h
+  │   ├── open62541.h
+  │   ├── ua_client.h
+  │   ├── ua_client_highlevel.h
+  │   ├── ua_config.h
+  │   ├── ua_config.h.in
+  │   ├── ua_connection.h
+  │   ├── ua_job.h
+  │   ├── ua_log.h
+  │   ├── ua_nodeids.h
+  │   ├── ua_server_external_ns.h
+  │   ├── ua_server.h
+  │   ├── ua_statuscodes.h
+  │   ├── ua_transport_generated_encoding_binary.h
+  │   ├── ua_transport_generated.h
+  │   ├── ua_types_generated_encoding_binary.h
+  │   ├── ua_types_generated.h
+  │   └── ua_types.h
+  ├── libopen62541.so -> ../open62541/build/libopen62541.so
+  ├── myServer
+  └── myServer.c
 
 
 Note that I have linked the library into the folder to spare me the trouble of copying it every time I change/rebuild the stack.
 Note that I have linked the library into the folder to spare me the trouble of copying it every time I change/rebuild the stack.
 
 
@@ -38,24 +44,24 @@ To create a really basic client, navigate back into the myApp folder from the pr
 .. code-block:: c
 .. code-block:: c
 
 
     #include <stdio.h>
     #include <stdio.h>
-
+    
     #include "ua_types.h"
     #include "ua_types.h"
     #include "ua_server.h"
     #include "ua_server.h"
     #include "logger_stdout.h"
     #include "logger_stdout.h"
     #include "networklayer_tcp.h"
     #include "networklayer_tcp.h"
-
+    
     int main(void) {
     int main(void) {
-      UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
-      UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664");
+      UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
+      UA_StatusCode retval = UA_Client_connect(client, UA_ClientConnectionTCP,"opc.tcp://localhost:16664");
       if(retval != UA_STATUSCODE_GOOD) {
       if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         UA_Client_delete(client);
         return retval;
         return retval;
       }
       }
-      
+    
       UA_Client_disconnect(client);
       UA_Client_disconnect(client);
       UA_Client_delete(client);
       UA_Client_delete(client);
       return 0;
       return 0;
-    } 
+    }
 
 
 Let's recompile both server and client - if you feel up to it, you can create a Makefile for this procedure. I will show a final command line compile example and ommit the compilation directives in future examples.::
 Let's recompile both server and client - if you feel up to it, you can create a Makefile for this procedure. I will show a final command line compile example and ommit the compilation directives in future examples.::
 
 
@@ -125,31 +131,32 @@ Let us extend the client with with an action reading node's value:
 .. code-block:: c
 .. code-block:: c
 
 
     #include <stdio.h>
     #include <stdio.h>
-
+    #include <stdio.h>
+    
     #include "ua_types.h"
     #include "ua_types.h"
     #include "ua_server.h"
     #include "ua_server.h"
     #include "logger_stdout.h"
     #include "logger_stdout.h"
     #include "networklayer_tcp.h"
     #include "networklayer_tcp.h"
-
+    
     int main(void) {
     int main(void) {
-      UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
-      UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664");
+      UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
+      UA_StatusCode retval = UA_Client_connect(client, UA_ClientConnectionTCP,"opc.tcp://localhost:16664");
       if(retval != UA_STATUSCODE_GOOD) {
       if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         UA_Client_delete(client);
         return retval;
         return retval;
       }
       }
-      
+    
       //variable to store data
       //variable to store data
       UA_DateTime raw_date = 0;
       UA_DateTime raw_date = 0;
-
+    
       UA_ReadRequest rReq;
       UA_ReadRequest rReq;
       UA_ReadRequest_init(&rReq);
       UA_ReadRequest_init(&rReq);
-      rReq.nodesToRead = UA_ReadValueId_new();
+      rReq.nodesToRead = UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]);
       rReq.nodesToReadSize = 1;
       rReq.nodesToReadSize = 1;
       rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
       rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
       rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
       rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
-
-      UA_ReadResponse rResp = UA_Client_read(client, &rReq);
+    
+      UA_ReadResponse rResp = UA_Client_Service_read(client, rReq);
       if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
       if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
          rResp.resultsSize > 0 && rResp.results[0].hasValue &&
          rResp.resultsSize > 0 && rResp.results[0].hasValue &&
          UA_Variant_isScalar(&rResp.results[0].value) &&
          UA_Variant_isScalar(&rResp.results[0].value) &&
@@ -157,14 +164,14 @@ Let us extend the client with with an action reading node's value:
              raw_date = *(UA_DateTime*)rResp.results[0].value.data;
              raw_date = *(UA_DateTime*)rResp.results[0].value.data;
              printf("raw date is: %" PRId64 "\n", raw_date);
              printf("raw date is: %" PRId64 "\n", raw_date);
       }
       }
-      
+    
       UA_ReadRequest_deleteMembers(&rReq);
       UA_ReadRequest_deleteMembers(&rReq);
       UA_ReadResponse_deleteMembers(&rResp);
       UA_ReadResponse_deleteMembers(&rResp);
-
+    
       UA_Client_disconnect(client);
       UA_Client_disconnect(client);
       UA_Client_delete(client);
       UA_Client_delete(client);
       return 0;
       return 0;
-    } 
+    }
 
 
 You should see raw time in milliseconds since January 1, 1601 UTC midnight::
 You should see raw time in milliseconds since January 1, 1601 UTC midnight::
 
 
@@ -185,42 +192,42 @@ As the last step for this tutorial, we are going to convert the raw date value i
     #include "networklayer_tcp.h"
     #include "networklayer_tcp.h"
     
     
     int main(void) {
     int main(void) {
-      UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
-      UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664");
-      if(retval != UA_STATUSCODE_GOOD) {
-        UA_Client_delete(client);
-        return retval;
-      }
-    
-      //variables to store data
-      UA_DateTime raw_date = 0;
-      UA_String* string_date = UA_String_new();
-
-      UA_ReadRequest rReq;
-      UA_ReadRequest_init(&rReq);
-      rReq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], 1);
-      rReq.nodesToReadSize = 1;
-      rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
-      rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
-
-      UA_ReadResponse rResp = UA_Client_read(client, &rReq);
-      if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
-         rResp.resultsSize > 0 && rResp.results[0].hasValue &&
-         UA_Variant_isScalar(&rResp.results[0].value) &&
-         rResp.results[0].value.type == &UA_TYPES[UA_TYPES_DATETIME]) {
-             raw_date = *(UA_DateTime*)rResp.results[0].value.data;
-             printf("raw date is: %llu\n", raw_date);
-             UA_DateTime_toString(raw_date, string_date);
-             printf("string date is: %.*s\n", string_date->length, string_date->data);
-      }
+        UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
+        UA_StatusCode retval = UA_Client_connect(client, UA_ClientConnectionTCP, "opc.tcp://localhost:16664");
+        if(retval != UA_STATUSCODE_GOOD) {
+          UA_Client_delete(client);
+          return retval;
+        }
       
       
-      UA_ReadRequest_deleteMembers(&rReq);
-      UA_ReadResponse_deleteMembers(&rResp);
-      UA_String_delete(string_date);
-
-      UA_Client_disconnect(client);
-      UA_Client_delete(client);
-      return 0;
+        //variables to store data
+        UA_DateTime raw_date = 0;
+        UA_String string_date;
+      
+        UA_ReadRequest rReq;
+        UA_ReadRequest_init(&rReq);
+        rReq.nodesToRead = UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]);
+        rReq.nodesToReadSize = 1;
+        rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
+        rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
+      
+        UA_ReadResponse rResp = UA_Client_Service_read(client, rReq);
+        if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
+            rResp.resultsSize > 0 && rResp.results[0].hasValue &&
+            UA_Variant_isScalar(&rResp.results[0].value) &&
+            rResp.results[0].value.type == &UA_TYPES[UA_TYPES_DATETIME]) {
+          raw_date = *(UA_DateTime*)rResp.results[0].value.data;
+          printf("raw date is: %" PRId64 "\n", raw_date);
+          string_date = UA_DateTime_toString(raw_date);
+          printf("string date is: %.*s\n", (int)string_date.length, string_date.data);
+        }
+      
+        UA_ReadRequest_deleteMembers(&rReq);
+        UA_ReadResponse_deleteMembers(&rResp);
+        UA_String_deleteMembers(&string_date);
+      
+        UA_Client_disconnect(client);
+        UA_Client_delete(client);
+        return UA_STATUSCODE_GOOD;
     }
     }
 
 
 Note that this file can be found as "examples/client_firstSteps.c" in the repository.
 Note that this file can be found as "examples/client_firstSteps.c" in the repository.

Diferenças do arquivo suprimidas por serem muito extensas
+ 80 - 65
doc/tutorial_server_firstSteps.rst


+ 2 - 2
doc/tutorial_server_variables.rst

@@ -49,11 +49,11 @@ Adding a variable node to the server that contains a user-defined variable
 
 
 This simple case allows to 'inject' a pre-defined variable into a variable node. The variable is wrapped by a "UA_Variant" before being insterted into the node.
 This simple case allows to 'inject' a pre-defined variable into a variable node. The variable is wrapped by a "UA_Variant" before being insterted into the node.
 
 
-Consider 'examples/server_variable.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.
+Consider 'examples/server_variable.c' in the repository. The examples are compiled if the Cmake option UA_BUILD_EXAMPLE is turned on.
 
 
 Adding a variable node to the server that contains a user-defined callback
 Adding a variable node to the server that contains a user-defined callback
 --------------------------------------------------------------------------
 --------------------------------------------------------------------------
 
 
 The latter case allows to define callback functions that are executed on read or write of the node. In this case an "UA_DataSource" containing the respective callback pointer is intserted into the node.
 The latter case allows to define callback functions that are executed on read or write of the node. In this case an "UA_DataSource" containing the respective callback pointer is intserted into the node.
 
 
-Consider 'examples/server_datasource.c' in the repository. The examples are compiled if the Cmake option BUILD_EXAMPLE is turned on.
+Consider 'examples/server_datasource.c' in the repository. The examples are compiled if the Cmake option UA_BUILD_EXAMPLE is turned on.

+ 6 - 6
examples/client.c

@@ -25,7 +25,7 @@ int main(int argc, char *argv[]) {
     //listing endpoints
     //listing endpoints
     UA_EndpointDescription* endpointArray = NULL;
     UA_EndpointDescription* endpointArray = NULL;
     size_t endpointArraySize = 0;
     size_t endpointArraySize = 0;
-    UA_StatusCode retval = UA_client_getEndpoints(client, ClientNetworkLayerTCP_connect,
+    UA_StatusCode retval = UA_client_getEndpoints(client, UA_ClientConnectionTCP,
             "opc.tcp://localhost:16664", &endpointArraySize, &endpointArray);
             "opc.tcp://localhost:16664", &endpointArraySize, &endpointArray);
 
 
     //freeing the endpointArray
     //freeing the endpointArray
@@ -38,14 +38,14 @@ int main(int argc, char *argv[]) {
 
 
     printf("%i endpoints found\n", (int)endpointArraySize);
     printf("%i endpoints found\n", (int)endpointArraySize);
     for(size_t i=0;i<endpointArraySize;i++){
     for(size_t i=0;i<endpointArraySize;i++){
-        printf("URL of endpoint %i is %.*s\n", (int)i, (int)endpointArray[i].endpointUrl.length, endpointArray[i].endpointUrl.data);
+        printf("SecurityPolicyUri of endpoint %i is %.*s\n", (int)i, (int)endpointArray[i].securityPolicyUri.length, endpointArray[i].securityPolicyUri.data);
     }
     }
 
 
     //cleanup array of enpoints
     //cleanup array of enpoints
     UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
     UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
 
 
     //connect to a server
     //connect to a server
-    retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
+    retval = UA_Client_connect(client, UA_ClientConnectionTCP,
                                              "opc.tcp://localhost:16664");
                                              "opc.tcp://localhost:16664");
 
 
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
@@ -112,7 +112,7 @@ int main(int argc, char *argv[]) {
     printf("\nReading the value of node (1, \"the.answer\"):\n");
     printf("\nReading the value of node (1, \"the.answer\"):\n");
     UA_ReadRequest rReq;
     UA_ReadRequest rReq;
     UA_ReadRequest_init(&rReq);
     UA_ReadRequest_init(&rReq);
-    rReq.nodesToRead = UA_ReadValueId_new();
+    rReq.nodesToRead =  UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]);
     rReq.nodesToReadSize = 1;
     rReq.nodesToReadSize = 1;
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
@@ -167,12 +167,12 @@ int main(int argc, char *argv[]) {
     UA_Variant_init(&input);
     UA_Variant_init(&input);
     UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
     UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
     
     
-    UA_Int32 outputSize;
+    size_t outputSize;
     UA_Variant *output;
     UA_Variant *output;
     retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
     retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
                             UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
     if(retval == UA_STATUSCODE_GOOD) {
     if(retval == UA_STATUSCODE_GOOD) {
-        printf("Method call was successfull, and %i returned values available.\n", outputSize);
+        printf("Method call was successfull, and %zu returned values available.\n", outputSize);
         UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
         UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
     } else {
     } else {
         printf("Method call was unsuccessfull, and %x returned values available.\n", retval);
         printf("Method call was unsuccessfull, and %x returned values available.\n", retval);

+ 3 - 2
examples/client_firstSteps.c

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

+ 29 - 16
examples/server.c

@@ -180,7 +180,7 @@ static UA_ByteString loadCertificate(void) {
     }
     }
 
 
     fseek(fp, 0, SEEK_END);
     fseek(fp, 0, SEEK_END);
-    certificate.length = ftell(fp);
+    certificate.length = (size_t)ftell(fp);
     certificate.data = malloc(certificate.length*sizeof(UA_Byte));
     certificate.data = malloc(certificate.length*sizeof(UA_Byte));
 	if(!certificate.data){
 	if(!certificate.data){
 		fclose(fp);
 		fclose(fp);
@@ -200,18 +200,25 @@ nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, voi
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
+static UA_StatusCode
+instantiationHandle(UA_NodeId newNodeId, UA_NodeId templateId, void *handle ) {
+  printf("Instantiated Node ns=%d; id=%d from ns=%d; id=%d\n", newNodeId.namespaceIndex, newNodeId.identifier.numeric, templateId.namespaceIndex, templateId.identifier.numeric);
+  return UA_STATUSCODE_GOOD;
+}
+
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
     pthread_rwlock_init(&writeLock, 0);
     pthread_rwlock_init(&writeLock, 0);
 #endif
 #endif
 
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
-    UA_ByteString certificate = loadCertificate();
-    UA_Server_setServerCertificate(server, certificate);
-    UA_ByteString_deleteMembers(&certificate);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664);
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    config.logger = Logger_Stdout;
+    config.serverCertificate = loadCertificate();
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
 
     // add node with the datetime data source
     // add node with the datetime data source
     UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
     UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
@@ -287,8 +294,12 @@ int main(int argc, char** argv) {
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    /* Instantiation Callback can be used when a typeDefinition creates new nodes under this added one.
+     * The method will be called for each created node.
+     */
+    UA_InstantiationCallback theAnswerCallback = {.method=instantiationHandle, .handle=(void*) server};
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                              myIntegerName, UA_NODEID_NULL, myVar, NULL);
+                              myIntegerName, UA_NODEID_NULL, myVar, &theAnswerCallback, NULL);
     UA_Variant_deleteMembers(&myVar.value);
     UA_Variant_deleteMembers(&myVar.value);
 
 
     /**************/
     /**************/
@@ -303,7 +314,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Demo"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 
 #define SCALARID 50001
 #define SCALARID 50001
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
@@ -311,7 +322,7 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Scalar"),
                             UA_QUALIFIEDNAME(1, "Scalar"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 
 #define ARRAYID 50002
 #define ARRAYID 50002
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
@@ -319,14 +330,14 @@ int main(int argc, char** argv) {
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Array"),
                             UA_QUALIFIEDNAME(1, "Array"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 
 #define MATRIXID 50003
 #define MATRIXID 50003
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
     object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
     object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID),
     UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(1, DEMOID),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Matrix"),
-                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
+                            UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL, NULL);
 
 
     UA_UInt32 id = 51000; // running id in namespace 0
     UA_UInt32 id = 51000; // running id in namespace 0
     for(UA_UInt32 type = 0; type < UA_TYPES_DIAGNOSTICINFO; type++) {
     for(UA_UInt32 type = 0; type < UA_TYPES_DIAGNOSTICINFO; type++) {
@@ -346,7 +357,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, SCALARID),
                                   UA_NODEID_NUMERIC(1, SCALARID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
         UA_Variant_deleteMembers(&attr.value);
 
 
         /* add an array node for every built-in type */
         /* add an array node for every built-in type */
@@ -355,7 +366,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, ARRAYID),
                                   UA_NODEID_NUMERIC(1, ARRAYID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
         UA_Variant_deleteMembers(&attr.value);
 
 
         /* add an matrix node for every built-in type */
         /* add an matrix node for every built-in type */
@@ -370,7 +381,7 @@ int main(int argc, char** argv) {
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, MATRIXID),
                                   UA_NODEID_NUMERIC(1, MATRIXID),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  qualifiedName, UA_NODEID_NULL, attr, NULL);
+                                  qualifiedName, UA_NODEID_NULL, attr, NULL, NULL);
         UA_Variant_deleteMembers(&attr.value);
         UA_Variant_deleteMembers(&attr.value);
     }
     }
 
 
@@ -417,10 +428,11 @@ int main(int argc, char** argv) {
     UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
     UA_Server_writeDisplayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
   
   
     //start server
     //start server
-    UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false
+    UA_StatusCode retval = UA_Server_run(server, &running); //blocks until running=false
 
 
     //ctrl-c received -> clean up
     //ctrl-c received -> clean up
     UA_Server_delete(server);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
 
 
     if(temperatureFile)
     if(temperatureFile)
         fclose(temperatureFile);
         fclose(temperatureFile);
@@ -439,5 +451,6 @@ int main(int argc, char** argv) {
     pthread_rwlock_destroy(&writeLock);
     pthread_rwlock_destroy(&writeLock);
 #endif
 #endif
 
 
+    UA_ByteString_deleteMembers(&config.serverCertificate);
     return retval;
     return retval;
 }
 }

+ 11 - 7
examples/server.cpp

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

+ 23 - 14
examples/server_datasource.c

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

+ 12 - 12
examples/server_firstSteps.c

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

+ 15 - 11
examples/server_method.c

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

+ 10 - 6
examples/server_nodeset.c

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

+ 9 - 4
examples/server_readspeed.c

@@ -31,8 +31,12 @@ static void stopHandler(int sign) {
 int main(int argc, char** argv) {
 int main(int argc, char** argv) {
     signal(SIGINT, stopHandler); /* catches ctrl-c */
     signal(SIGINT, stopHandler); /* catches ctrl-c */
 
 
-    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
-    UA_Server_setLogger(server, logger);
+    UA_ServerConfig config = UA_ServerConfig_standard;
+    UA_ServerNetworkLayer nl = UA_ServerNetworkLayerTCP(UA_ConnectionConfig_standard, 16664, logger);
+    config.logger = Logger_Stdout;
+    config.networkLayers = &nl;
+    config.networkLayersSize = 1;
+    UA_Server *server = UA_Server_new(config);
 
 
     /* add a variable node to the address space */
     /* add a variable node to the address space */
     UA_VariableAttributes attr;
     UA_VariableAttributes attr;
@@ -47,7 +51,7 @@ int main(int argc, char** argv) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, attr, NULL);
+                              UA_NODEID_NULL, attr, NULL, NULL);
 
 
     UA_ReadRequest request;
     UA_ReadRequest request;
     UA_ReadRequest_init(&request);
     UA_ReadRequest_init(&request);
@@ -96,8 +100,9 @@ int main(int argc, char** argv) {
     UA_ByteString_deleteMembers(&request_msg);
     UA_ByteString_deleteMembers(&request_msg);
     UA_ByteString_deleteMembers(&response_msg);
     UA_ByteString_deleteMembers(&response_msg);
 
 
-    retval |= UA_Server_run(server, 1, &running);
+    retval |= UA_Server_run(server, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
 
 
     return retval;
     return retval;
 }
 }

+ 8 - 4
examples/server_repeated_job.c

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

+ 10 - 8
examples/server_variable.c

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

+ 2 - 3
include/ua_client.h

@@ -15,9 +15,8 @@ struct UA_Client;
 typedef struct UA_Client UA_Client;
 typedef struct UA_Client UA_Client;
 
 
 typedef struct UA_ClientConfig {
 typedef struct UA_ClientConfig {
-    UA_Int32 timeout; //sync response timeout
-    UA_Int32 secureChannelLifeTime; // lifetime in ms (then the channel needs to be renewed)
-    UA_Int32 timeToRenewSecureChannel; //time in ms  before expiration to renew the secure channel
+    UA_UInt32 timeout; //sync response timeout
+    UA_UInt32 secureChannelLifeTime; // lifetime in ms (then the channel needs to be renewed)
     UA_ConnectionConfig localConnectionConfig;
     UA_ConnectionConfig localConnectionConfig;
 } UA_ClientConfig;
 } UA_ClientConfig;
 
 

+ 1 - 1
include/ua_client_highlevel.h

@@ -249,7 +249,7 @@ UA_Client_readUserExecutableAttribute(UA_Client *client, UA_NodeId nodeId, UA_Bo
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId,
 UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId,
-               UA_Int32 inputSize, const UA_Variant *input, UA_Int32 *outputSize, UA_Variant **output);
+               size_t inputSize, const UA_Variant *input, size_t *outputSize, UA_Variant **output);
 
 
 /**************************/
 /**************************/
 /* Subscriptions Handling */
 /* Subscriptions Handling */

+ 7 - 2
include/ua_config.h.in

@@ -55,7 +55,12 @@
 # define le32toh(x) (x)
 # define le32toh(x) (x)
 # define le64toh(x) (x)
 # define le64toh(x) (x)
 #else
 #else
-# if defined(__linux__)
+# if defined(__ANDROID__)
+#  include <endian.h>
+#  define le16toh(x) letoh16(x)
+#  define le32toh(x) letoh32(x)
+#  define le64toh(x) letoh64(x)
+# elif defined(__linux__)
 #  include <endian.h>
 #  include <endian.h>
 # elif defined(__OpenBSD__)
 # elif defined(__OpenBSD__)
 #  include <sys/endian.h>
 #  include <sys/endian.h>
@@ -85,7 +90,7 @@
 #  define le32toh(x) ENDIAN_LE32(x)
 #  define le32toh(x) ENDIAN_LE32(x)
 #  define le64toh(x) ENDIAN_LE64(x)
 #  define le64toh(x) ENDIAN_LE64(x)
 # endif
 # endif
-# if ( __BYTE_ORDER != __LITTLE_ENDIAN )
+# if ( __BYTE_ORDER != __LITTLE_ENDIAN ) && (_BYTE_ORDER != _LITTLE_ENDIAN)
 #  define UA_NON_LITTLEENDIAN_ARCHITECTURE
 #  define UA_NON_LITTLEENDIAN_ARCHITECTURE
 # endif
 # endif
 #endif
 #endif

+ 72 - 67
include/ua_server.h

@@ -28,51 +28,58 @@ extern "C" {
 #include "ua_job.h"
 #include "ua_job.h"
 #include "ua_connection.h"
 #include "ua_connection.h"
 
 
-/*********************************/
-/* Initialize and run the server */
-/*********************************/
+/*****************/
+/* Server Config */
+/*****************/
+
+struct UA_ServerNetworkLayer; // forwards declaration
+typedef struct UA_ServerNetworkLayer UA_ServerNetworkLayer;    
+
+typedef struct {
+    UA_String username;
+    UA_String password;
+} UA_UsernamePasswordLogin;
+
+typedef struct {
+    UA_UInt16 nThreads; // only if multithreading is enabled
+    UA_Logger logger;
 
 
-typedef struct UA_ServerConfig {
-    UA_Boolean  Login_enableAnonymous;
+    UA_BuildInfo buildInfo;
+    UA_ApplicationDescription applicationDescription;
+    UA_ByteString serverCertificate;
 
 
-    UA_Boolean  Login_enableUsernamePassword;
-    char**      Login_usernames;
-    char**      Login_passwords;
-    UA_UInt32   Login_loginsCount;
+    size_t networkLayersSize;
+    UA_ServerNetworkLayer *networkLayers;
 
 
-    char*       Application_applicationURI;
-    char*       Application_applicationName;
+    UA_Boolean enableAnonymousLogin;
+    UA_Boolean enableUsernamePasswordLogin;
+    size_t usernamePasswordLoginsSize;
+    UA_UsernamePasswordLogin usernamePasswordLogins[];
 } UA_ServerConfig;
 } UA_ServerConfig;
 
 
 extern UA_EXPORT const UA_ServerConfig UA_ServerConfig_standard;
 extern UA_EXPORT const UA_ServerConfig UA_ServerConfig_standard;
 
 
-UA_Server UA_EXPORT * UA_Server_new(UA_ServerConfig config);
-void UA_EXPORT UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate);
-void UA_EXPORT UA_Server_delete(UA_Server *server);
+/*********************************/
+/* Initialize and run the server */
+/*********************************/
 
 
-/** Sets the logger used by the server */
-void UA_EXPORT UA_Server_setLogger(UA_Server *server, UA_Logger logger);
+UA_Server UA_EXPORT * UA_Server_new(const UA_ServerConfig config);
+void UA_EXPORT UA_Server_delete(UA_Server *server);
 
 
 /**
 /**
  * Runs the main loop of the server. In each iteration, this calls into the networklayers to see if
  * 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.
  * jobs have arrived and checks if repeated jobs need to be triggered.
- *
- * @param server The server object
- * @param nThreads The number of worker threads. Is ignored if MULTITHREADING is not activated.
- * @param running Points to a boolean value on the heap. When running is set to false, the worker
- *        threads and the main loop close and the server is shut down.
- * @return Indicates whether the server shut down cleanly
  */
  */
-UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
+UA_StatusCode UA_EXPORT UA_Server_run(UA_Server *server, volatile UA_Boolean *running);
 
 
 /** The prologue part of UA_Server_run (no need to use if you call UA_Server_run) */
 /** The prologue part of UA_Server_run (no need to use if you call UA_Server_run) */
-UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running);
-
-/** The epilogue part of UA_Server_run (no need to use if you call UA_Server_run) */
-UA_StatusCode UA_EXPORT UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads);
+UA_StatusCode UA_EXPORT UA_Server_run_startup(UA_Server *server);
 
 
 /** One iteration of UA_Server_run (no need to use if you call UA_Server_run) */
 /** One iteration of UA_Server_run (no need to use if you call UA_Server_run) */
-UA_StatusCode UA_EXPORT UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running);
+UA_StatusCode UA_EXPORT UA_Server_run_iterate(UA_Server *server);
+
+/** The epilogue part of UA_Server_run (no need to use if you call UA_Server_run) */
+UA_StatusCode UA_EXPORT UA_Server_run_shutdown(UA_Server *server);
 
 
 /**
 /**
  * @param server The server object.
  * @param server The server object.
@@ -97,6 +104,9 @@ UA_StatusCode UA_EXPORT UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
  */
  */
 UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId);
 UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid jobId);
 
 
+/** @brief Add a new namespace to the server. Returns the index of the new namespace */
+UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
+
 /**
 /**
  * Interface to the binary network layers. This structure is returned from the
  * Interface to the binary network layers. This structure is returned from the
  * function that initializes the network layer. The layer is already bound to a
  * function that initializes the network layer. The layer is already bound to a
@@ -104,9 +114,9 @@ UA_StatusCode UA_EXPORT UA_Server_removeRepeatedJob(UA_Server *server, UA_Guid j
  * in parallel but only sequentially from the server's main loop. So the network
  * in parallel but only sequentially from the server's main loop. So the network
  * layer does not need to be thread-safe.
  * layer does not need to be thread-safe.
  */
  */
-typedef struct UA_ServerNetworkLayer {
+struct UA_ServerNetworkLayer {
+    void *handle; // pointer to internal data
     UA_String discoveryUrl;
     UA_String discoveryUrl;
-    UA_Logger logger; ///< Set during _start
 
 
     /**
     /**
      * Starts listening on the the networklayer.
      * Starts listening on the the networklayer.
@@ -115,7 +125,7 @@ typedef struct UA_ServerNetworkLayer {
      * @param logger The logger
      * @param logger The logger
      * @return Returns UA_STATUSCODE_GOOD or an error code.
      * @return Returns UA_STATUSCODE_GOOD or an error code.
      */
      */
-    UA_StatusCode (*start)(struct UA_ServerNetworkLayer *nl, UA_Logger logger);
+    UA_StatusCode (*start)(UA_ServerNetworkLayer *nl, UA_Logger logger);
     
     
     /**
     /**
      * Gets called from the main server loop and returns the jobs (accumulated messages and close
      * Gets called from the main server loop and returns the jobs (accumulated messages and close
@@ -127,7 +137,7 @@ typedef struct UA_ServerNetworkLayer {
      * @param timeout The timeout during which an event must arrive in microseconds
      * @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.
      * @return The size of the jobs array. If the result is negative, an error has occurred.
      */
      */
-    size_t (*getJobs)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
+    size_t (*getJobs)(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout);
 
 
     /**
     /**
      * Closes the network connection and returns all the jobs that need to be finished before the
      * Closes the network connection and returns all the jobs that need to be finished before the
@@ -138,22 +148,11 @@ typedef struct UA_ServerNetworkLayer {
      * returned size.
      * returned size.
      * @return The size of the jobs array. If the result is negative, an error has occurred.
      * @return The size of the jobs array. If the result is negative, an error has occurred.
      */
      */
-    size_t (*stop)(struct UA_ServerNetworkLayer *nl, UA_Job **jobs);
-
-    /** Deletes the network layer. Call only after a successful shutdown. */
-    void (*deleteMembers)(struct UA_ServerNetworkLayer *nl);
-} UA_ServerNetworkLayer;
-
-/**
- * Adds a network layer to the server. The network layer is destroyed together
- * with the server. Do not use it after adding it as it might be moved around on
- * the heap.
- */
-void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *networkLayer);
-
-/** @brief Add a new namespace to the server. Returns the index of the new namespace */
-UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
+    size_t (*stop)(UA_ServerNetworkLayer *nl, UA_Job **jobs);
 
 
+    /** Deletes the network content. Call only after stopping. */
+    void (*deleteMembers)(UA_ServerNetworkLayer *nl);
+};
 
 
 /**********************/
 /**********************/
 /* Set Node Callbacks */
 /* Set Node Callbacks */
@@ -225,8 +224,8 @@ typedef struct {
 } UA_ObjectLifecycleManagement;
 } UA_ObjectLifecycleManagement;
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
-UA_Server_setObjectTypeNode_instanceLifecycleManagement(UA_Server *server, UA_NodeId nodeId,
-                                                        UA_ObjectLifecycleManagement olm);
+UA_Server_setObjectTypeNode_lifecycleManagement(UA_Server *server, UA_NodeId nodeId,
+                                                UA_ObjectLifecycleManagement olm);
 
 
 /* Iterate over all nodes referenced by parentNodeId by calling the callback
 /* Iterate over all nodes referenced by parentNodeId by calling the callback
    function for each child node */
    function for each child node */
@@ -241,6 +240,11 @@ UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
 /* Node Management */
 /* Node Management */
 /*******************/
 /*******************/
 
 
+typedef struct UA_InstantiationCallback_s {
+  UA_StatusCode (*method)(UA_NodeId objectId, UA_NodeId definitionId, void *handle);
+  void *handle;
+} UA_InstantiationCallback;
+
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
 UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
                        const UA_ExpandedNodeId targetId, UA_Boolean isForward);
                        const UA_ExpandedNodeId targetId, UA_Boolean isForward);
@@ -258,70 +262,71 @@ UA_StatusCode UA_EXPORT
 __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
 __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 parentNodeId, const UA_NodeId referenceTypeId,
                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                    const UA_NodeAttributes *attr, const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
+                    const UA_NodeAttributes *attr, const UA_DataType *attributeType, 
+                    UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId);
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                           const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                          const UA_VariableAttributes attr, UA_NodeId *outNewNodeId) {
+                          const UA_VariableAttributes attr, UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                               const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
                               const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
-                              UA_NodeId *outNewNodeId) {
+                              UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
     return __UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                         const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
+                        const UA_ObjectAttributes attr, UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
                                referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                             const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                             const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                             const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
                             const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
-                            UA_NodeId *outNewNodeId) {
+                            UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
     return __UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addViewNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                       const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                       const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                       const UA_QualifiedName browseName, const UA_ViewAttributes attr,
                       const UA_QualifiedName browseName, const UA_ViewAttributes attr,
-                      UA_NodeId *outNewNodeId) {
+                      UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
     return __UA_Server_addNode(server, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_VIEWATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
                                const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
-                               UA_NodeId *outNewNodeId) {
+                               UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
     return __UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                           const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
                           const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
-                          UA_NodeId *outNewNodeId) {
+                          UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
     return __UA_Server_addNode(server, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
                                referenceTypeId, browseName, UA_NODEID_NULL, (const UA_NodeAttributes*)&attr,
-                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], outNewNodeId); }
+                               &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES], instantiationCallback, outNewNodeId); }
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
@@ -330,18 +335,18 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
                                     const UA_VariableAttributes attr, const UA_DataSource dataSource,
                                     const UA_VariableAttributes attr, const UA_DataSource dataSource,
                                     UA_NodeId *outNewNodeId);
                                     UA_NodeId *outNewNodeId);
 
 
-#ifdef UA_ENABLE_METHODCALLS
 typedef UA_StatusCode (*UA_MethodCallback)(void *methodHandle, const UA_NodeId objectId,
 typedef UA_StatusCode (*UA_MethodCallback)(void *methodHandle, const UA_NodeId objectId,
                                            size_t inputSize, const UA_Variant *input,
                                            size_t inputSize, const UA_Variant *input,
                                            size_t outputSize, UA_Variant *output);
                                            size_t outputSize, UA_Variant *output);
 
 
+#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                         UA_MethodCallback method, void *handle,
                         UA_MethodCallback method, void *handle,
-                        UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
-                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments,
+                        size_t inputArgumentsSize, const UA_Argument* inputArguments, 
+                        size_t outputArgumentsSize, const UA_Argument* outputArguments,
                         UA_NodeId *outNewNodeId);
                         UA_NodeId *outNewNodeId);
 #endif
 #endif
 
 

+ 5 - 5
include/ua_types.h

@@ -35,7 +35,7 @@ extern "C" {
 /* Builtin Type Definitions */
 /* Builtin Type Definitions */
 /****************************/
 /****************************/
 
 
-#define UA_BUILTIN_TYPES_COUNT 25
+#define UA_BUILTIN_TYPES_COUNT 25U
 
 
 /** Boolean: A two-state logical value (true or false) */
 /** Boolean: A two-state logical value (true or false) */
 typedef bool UA_Boolean;
 typedef bool UA_Boolean;
@@ -146,9 +146,9 @@ typedef struct UA_DateTimeStruct {
     UA_UInt16 year;
     UA_UInt16 year;
 } UA_DateTimeStruct;
 } UA_DateTimeStruct;
 
 
-UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
+UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime t);
 
 
-UA_String UA_EXPORT UA_DateTime_toString(UA_DateTime time);
+UA_String UA_EXPORT UA_DateTime_toString(UA_DateTime t);
 
 
 /**************************************************************************/
 /**************************************************************************/
 /* Guid: A 16 byte value that can be used as a globally unique identifier */
 /* Guid: A 16 byte value that can be used as a globally unique identifier */
@@ -222,7 +222,7 @@ static UA_INLINE UA_Boolean UA_NodeId_isNull(const UA_NodeId *p) {
 
 
 UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 
 
-static UA_INLINE UA_NodeId UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
+static UA_INLINE UA_NodeId UA_NODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier) {
     UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_NUMERIC;
     UA_NodeId id; id.namespaceIndex = nsIndex; id.identifierType = UA_NODEIDTYPE_NUMERIC;
     id.identifier.numeric = identifier; return id; }
     id.identifier.numeric = identifier; return id; }
 
 
@@ -255,7 +255,7 @@ typedef struct {
     UA_UInt32 serverIndex;
     UA_UInt32 serverIndex;
 } UA_ExpandedNodeId;
 } UA_ExpandedNodeId;
 
 
-static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_Int32 identifier) {
+static UA_INLINE UA_ExpandedNodeId UA_EXPANDEDNODEID_NUMERIC(UA_UInt16 nsIndex, UA_UInt32 identifier) {
     UA_ExpandedNodeId id; id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier);
     UA_ExpandedNodeId id; id.nodeId = UA_NODEID_NUMERIC(nsIndex, identifier);
     id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
     id.serverIndex = 0; id.namespaceUri = UA_STRING_NULL; return id; }
 
 

+ 13 - 8
src/client/ua_client.c

@@ -11,7 +11,6 @@
 
 
 const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
 const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
     { .timeout = 5000 /* ms receive timout */, .secureChannelLifeTime = 30000,
     { .timeout = 5000 /* ms receive timout */, .secureChannelLifeTime = 30000,
-      .timeToRenewSecureChannel = 2000,
       {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
       {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
        .maxMessageSize = 65536, .maxChunkCount = 1}};
        .maxMessageSize = 65536, .maxChunkCount = 1}};
 
 
@@ -33,7 +32,7 @@ static void UA_Client_init(UA_Client* client, UA_ClientConfig config,
 
 
     client->logger = logger;
     client->logger = logger;
     client->config = config;
     client->config = config;
-    client->scExpiresAt = 0;
+    client->scRenewAt = 0;
 
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     client->monitoredItemHandles = 0;
     client->monitoredItemHandles = 0;
@@ -114,7 +113,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
 
 
     size_t offset = 8;
     size_t offset = 8;
     retval |= UA_TcpHelloMessage_encodeBinary(&hello, &message, &offset);
     retval |= UA_TcpHelloMessage_encodeBinary(&hello, &message, &offset);
-    messageHeader.messageSize = offset;
+    messageHeader.messageSize = (UA_UInt32)offset;
     offset = 0;
     offset = 0;
     retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
     retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
     UA_TcpHelloMessage_deleteMembers(&hello);
     UA_TcpHelloMessage_deleteMembers(&hello);
@@ -169,7 +168,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
 
 
 static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
 static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew) {
     /* Check if sc is still valid */
     /* Check if sc is still valid */
-    if(renew && client->scExpiresAt - UA_DateTime_now() > client->config.timeToRenewSecureChannel * 10000)
+    if(renew && client->scRenewAt - UA_DateTime_now() > 0)
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
 
 
     UA_Connection *c = &client->connection;
     UA_Connection *c = &client->connection;
@@ -178,7 +177,11 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
 
 
     UA_SecureConversationMessageHeader messageHeader;
     UA_SecureConversationMessageHeader messageHeader;
     messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
     messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
-    messageHeader.secureChannelId = 0;
+    if(renew){
+        messageHeader.secureChannelId = client->channel.securityToken.channelId;
+    }else{
+        messageHeader.secureChannelId = 0;
+    }
 
 
     UA_SequenceHeader seqHeader;
     UA_SequenceHeader seqHeader;
     seqHeader.sequenceNumber = ++client->channel.sequenceNumber;
     seqHeader.sequenceNumber = ++client->channel.sequenceNumber;
@@ -220,7 +223,7 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
     retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &message, &offset);
     retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset);
     retval |= UA_NodeId_encodeBinary(&requestType, &message, &offset);
     retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
     retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
-    messageHeader.messageHeader.messageSize = offset;
+    messageHeader.messageHeader.messageSize = (UA_UInt32)offset;
     offset = 0;
     offset = 0;
     retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset);
     retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset);
 
 
@@ -282,7 +285,9 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
         return retval;
         return retval;
     }
     }
 
 
-    client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000;
+    //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->scRenewAt = UA_DateTime_now() + (UA_DateTime)(response.securityToken.revisedLifetime * (UA_Double)UA_MSEC_TO_DATETIME * 0.75);
     retval = response.responseHeader.serviceResult;
     retval = response.responseHeader.serviceResult;
 
 
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
@@ -482,7 +487,7 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
     retval |= UA_NodeId_encodeBinary(&typeId, &message, &offset);
     retval |= UA_NodeId_encodeBinary(&typeId, &message, &offset);
     retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], &message, &offset);
     retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], &message, &offset);
 
 
-    msgHeader.messageHeader.messageSize = offset;
+    msgHeader.messageHeader.messageSize = (UA_UInt32)offset;
     offset = 0;
     offset = 0;
     retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
     retval |= UA_SecureConversationMessageHeader_encodeBinary(&msgHeader, &message, &offset);
 
 

+ 3 - 3
src/client/ua_client_highlevel.c

@@ -33,7 +33,7 @@ UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt1
     UA_String *ns = response.results[0].value.data;
     UA_String *ns = response.results[0].value.data;
     for(size_t i = 0; i < response.results[0].value.arrayLength; i++){
     for(size_t i = 0; i < response.results[0].value.arrayLength; i++){
         if(UA_String_equal(namespaceUri, &ns[i])) {
         if(UA_String_equal(namespaceUri, &ns[i])) {
-            *namespaceIndex = i;
+            *namespaceIndex = (UA_UInt16)i;
             retval = UA_STATUSCODE_GOOD;
             retval = UA_STATUSCODE_GOOD;
             break;
             break;
         }
         }
@@ -178,8 +178,8 @@ __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass, const UA_No
 /********/
 /********/
 
 
 UA_StatusCode
 UA_StatusCode
-UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId, UA_Int32 inputSize,
-               const UA_Variant *input, UA_Int32 *outputSize, UA_Variant **output) {
+UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId, size_t inputSize,
+               const UA_Variant *input, size_t *outputSize, UA_Variant **output) {
     UA_CallRequest request;
     UA_CallRequest request;
     UA_CallRequest_init(&request);
     UA_CallRequest_init(&request);
     UA_CallMethodRequest item;
     UA_CallMethodRequest item;

+ 2 - 2
src/client/ua_client_highlevel_subscriptions.c

@@ -230,8 +230,8 @@ UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
         if(msg.notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
         if(msg.notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
             // This is a dataChangeNotification
             // This is a dataChangeNotification
             UA_DataChangeNotification *dataChangeNotification = msg.notificationData[k].content.decoded.data;
             UA_DataChangeNotification *dataChangeNotification = msg.notificationData[k].content.decoded.data;
-            for(size_t i = 0; i < dataChangeNotification->monitoredItemsSize; i++) {
-            UA_MonitoredItemNotification *mitemNot = &dataChangeNotification->monitoredItems[i];
+            for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; j++) {
+            UA_MonitoredItemNotification *mitemNot = &dataChangeNotification->monitoredItems[j];
                 // find this client handle
                 // find this client handle
                 LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
                 LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
                     if(mon->ClientHandle == mitemNot->clientHandle) {
                     if(mon->ClientHandle == mitemNot->clientHandle) {

+ 18 - 18
src/client/ua_client_internal.h

@@ -16,26 +16,26 @@ typedef struct UA_Client_NotificationsAckNumber_s {
 } UA_Client_NotificationsAckNumber;
 } UA_Client_NotificationsAckNumber;
 
 
 typedef struct UA_Client_MonitoredItem_s {
 typedef struct UA_Client_MonitoredItem_s {
-    UA_UInt32          MonitoredItemId;
-    UA_UInt32          MonitoringMode;
-    UA_NodeId          monitoredNodeId;
-    UA_UInt32          AttributeID;
-    UA_UInt32          ClientHandle;
-    UA_UInt32          SamplingInterval;
-    UA_UInt32          QueueSize;
-    UA_Boolean         DiscardOldest;
-    void               (*handler)(UA_UInt32 handle, UA_DataValue *value, void *context);
-    void               *handlerContext;
+    UA_UInt32  MonitoredItemId;
+    UA_UInt32  MonitoringMode;
+    UA_NodeId  monitoredNodeId;
+    UA_UInt32  AttributeID;
+    UA_UInt32  ClientHandle;
+    UA_Double  SamplingInterval;
+    UA_UInt32  QueueSize;
+    UA_Boolean DiscardOldest;
+    void       (*handler)(UA_UInt32 handle, UA_DataValue *value, void *context);
+    void       *handlerContext;
     LIST_ENTRY(UA_Client_MonitoredItem_s)  listEntry;
     LIST_ENTRY(UA_Client_MonitoredItem_s)  listEntry;
 } UA_Client_MonitoredItem;
 } UA_Client_MonitoredItem;
 
 
 typedef struct UA_Client_Subscription_s {
 typedef struct UA_Client_Subscription_s {
-    UA_UInt32    LifeTime;
-    UA_Int32     KeepAliveCount;
-    UA_DateTime  PublishingInterval;
-    UA_UInt32    SubscriptionID;
-    UA_Int32     NotificationsPerPublish;
-    UA_UInt32    Priority;
+    UA_UInt32 LifeTime;
+    UA_UInt32 KeepAliveCount;
+    UA_Double PublishingInterval;
+    UA_UInt32 SubscriptionID;
+    UA_UInt32 NotificationsPerPublish;
+    UA_UInt32 Priority;
     LIST_ENTRY(UA_Client_Subscription_s) listEntry;
     LIST_ENTRY(UA_Client_Subscription_s) listEntry;
     LIST_HEAD(UA_ListOfClientMonitoredItems, UA_Client_MonitoredItem_s) MonitoredItems;
     LIST_HEAD(UA_ListOfClientMonitoredItems, UA_Client_MonitoredItem_s) MonitoredItems;
 } UA_Client_Subscription;
 } UA_Client_Subscription;
@@ -69,7 +69,7 @@ struct UA_Client {
     UA_UInt32 requestHandle;
     UA_UInt32 requestHandle;
     
     
 #ifdef UA_ENABLE_SUBSCRIPTIONS
 #ifdef UA_ENABLE_SUBSCRIPTIONS
-    UA_Int32 monitoredItemHandles;
+    UA_UInt32 monitoredItemHandles;
     LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
     LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
     LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;
     LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;
 #endif
 #endif
@@ -77,7 +77,7 @@ struct UA_Client {
     /* Config */
     /* Config */
     UA_Logger logger;
     UA_Logger logger;
     UA_ClientConfig config;
     UA_ClientConfig config;
-    UA_DateTime scExpiresAt;
+    UA_DateTime scRenewAt;
 };
 };
 
 
 #endif /* UA_CLIENT_INTERNAL_H_ */
 #endif /* UA_CLIENT_INTERNAL_H_ */

+ 109 - 345
src/server/ua_nodes.c

@@ -1,233 +1,63 @@
 #include "ua_nodes.h"
 #include "ua_nodes.h"
 #include "ua_util.h"
 #include "ua_util.h"
 
 
-/* UA_Node */
-static void UA_Node_deleteMembers(UA_Node *p) {
-	UA_NodeId_deleteMembers(&p->nodeId);
-	UA_QualifiedName_deleteMembers(&p->browseName);
-	UA_LocalizedText_deleteMembers(&p->displayName);
-	UA_LocalizedText_deleteMembers(&p->description);
-	UA_Array_delete(p->references, p->referencesSize, &UA_TYPES[UA_TYPES_REFERENCENODE]);
-}
-
-static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
-	UA_StatusCode retval = UA_STATUSCODE_GOOD;
-	retval |= UA_NodeId_copy(&src->nodeId, &dst->nodeId);
-	dst->nodeClass = src->nodeClass;
-	retval |= UA_QualifiedName_copy(&src->browseName, &dst->browseName);
-	retval |= UA_LocalizedText_copy(&src->displayName, &dst->displayName);
-	retval |= UA_LocalizedText_copy(&src->description, &dst->description);
-	dst->writeMask = src->writeMask;
-	dst->userWriteMask = src->userWriteMask;
-	if(retval != UA_STATUSCODE_GOOD) {
-    	UA_Node_deleteMembers(dst);
-        return retval;
-    }
-	retval |= UA_Array_copy(src->references, src->referencesSize, (void**)&dst->references,
-                            &UA_TYPES[UA_TYPES_REFERENCENODE]);
-	if(retval == UA_STATUSCODE_GOOD)
-        dst->referencesSize = src->referencesSize;
-	return retval;
-}
-
-
 void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
 void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
+    /* delete standard content */
+    UA_NodeId_deleteMembers(&node->nodeId);
+    UA_QualifiedName_deleteMembers(&node->browseName);
+    UA_LocalizedText_deleteMembers(&node->displayName);
+    UA_LocalizedText_deleteMembers(&node->description);
+    UA_Array_delete(node->references, node->referencesSize, &UA_TYPES[UA_TYPES_REFERENCENODE]);
+    node->references = NULL;
+    node->referencesSize = 0;
+
+    /* delete unique content of the nodeclass */
     switch(node->nodeClass) {
     switch(node->nodeClass) {
     case UA_NODECLASS_OBJECT:
     case UA_NODECLASS_OBJECT:
-        UA_ObjectNode_deleteMembers((UA_ObjectNode*)node);
-        break;
-    case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_deleteMembers((UA_VariableNode*)node);
         break;
         break;
     case UA_NODECLASS_METHOD:
     case UA_NODECLASS_METHOD:
-        UA_MethodNode_deleteMembers((UA_MethodNode*)node);
         break;
         break;
     case UA_NODECLASS_OBJECTTYPE:
     case UA_NODECLASS_OBJECTTYPE:
-        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode*)node);
-        break;
-    case UA_NODECLASS_VARIABLETYPE:
-        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode*)node);
-        break;
-    case UA_NODECLASS_REFERENCETYPE:
-        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode*)node);
-        break;
-    case UA_NODECLASS_DATATYPE:
-        UA_DataTypeNode_deleteMembers((UA_DataTypeNode*)node);
-        break;
-    case UA_NODECLASS_VIEW:
-        UA_ViewNode_deleteMembers((UA_ViewNode*)node);
-        break;
-    default:
-        break;
-    }
-}
-
-void UA_Node_deleteAnyNodeClass(UA_Node *node) {
-    UA_Node_deleteMembersAnyNodeClass(node);
-    UA_free(node);
-}
-
-typedef UA_Node *(*UA_NewNodeFunction)(void);
-typedef UA_StatusCode (*UA_CopyNodeFunction)(const UA_Node *src, UA_Node *dst);
-typedef void (*UA_DeleteNodeFunction)(UA_Node *p);
-
-UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node) {
-    UA_NewNodeFunction newNode;
-    UA_CopyNodeFunction copyNode;
-    UA_DeleteNodeFunction deleteNode;
-
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        newNode = (UA_NewNodeFunction)UA_ObjectNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_ObjectNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_ObjectNode_delete;
         break;
         break;
     case UA_NODECLASS_VARIABLE:
     case UA_NODECLASS_VARIABLE:
-        newNode = (UA_NewNodeFunction)UA_VariableNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_VariableNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_VariableNode_delete;
-        break;
-    case UA_NODECLASS_METHOD:
-        newNode = (UA_NewNodeFunction)UA_MethodNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_MethodNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_MethodNode_delete;
-        break;
-    case UA_NODECLASS_OBJECTTYPE:
-        newNode = (UA_NewNodeFunction)UA_ObjectTypeNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_ObjectTypeNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_ObjectTypeNode_delete;
-        break;
-    case UA_NODECLASS_VARIABLETYPE:
-        newNode = (UA_NewNodeFunction)UA_VariableTypeNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_VariableTypeNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_VariableTypeNode_delete;
+    case UA_NODECLASS_VARIABLETYPE: {
+        UA_VariableNode *p = (UA_VariableNode*)node;
+        if(p->valueSource == UA_VALUESOURCE_VARIANT)
+            UA_Variant_deleteMembers(&p->value.variant.value);
         break;
         break;
-    case UA_NODECLASS_REFERENCETYPE:
-        newNode = (UA_NewNodeFunction)UA_ReferenceTypeNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_ReferenceTypeNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_ReferenceTypeNode_delete;
+    }
+    case UA_NODECLASS_REFERENCETYPE: {
+        UA_ReferenceTypeNode *p = (UA_ReferenceTypeNode*)node;
+        UA_LocalizedText_deleteMembers(&p->inverseName);
         break;
         break;
+    }
     case UA_NODECLASS_DATATYPE:
     case UA_NODECLASS_DATATYPE:
-        newNode = (UA_NewNodeFunction)UA_DataTypeNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_DataTypeNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_DataTypeNode_delete;
         break;
         break;
     case UA_NODECLASS_VIEW:
     case UA_NODECLASS_VIEW:
-        newNode = (UA_NewNodeFunction)UA_ViewNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_ViewNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_ViewNode_delete;
         break;
         break;
     default:
     default:
-        return NULL;
         break;
         break;
     }
     }
-
-    UA_Node *copy = newNode();
-    if(!copy)
-        return NULL;
-    if(copyNode(node, copy) != UA_STATUSCODE_GOOD) {
-        deleteNode(copy);
-        return NULL;
-    }
-    return copy;
-}
-
-/* UA_ObjectNode */
-void UA_ObjectNode_init(UA_ObjectNode *p) {
-    memset(p, 0, sizeof(UA_ObjectNode));
-    p->nodeClass = UA_NODECLASS_OBJECT;
-}
-
-UA_ObjectNode * UA_ObjectNode_new(void) {
-    UA_ObjectNode *p = (UA_ObjectNode*)UA_malloc(sizeof(UA_ObjectNode));
-    if(p)
-        UA_ObjectNode_init(p);
-    return p;
-}
-
-void UA_ObjectNode_deleteMembers(UA_ObjectNode *p) {
-    UA_Node_deleteMembers((UA_Node*)p);
-}
-
-void UA_ObjectNode_delete(UA_ObjectNode *p) {
-    UA_ObjectNode_deleteMembers(p);
-    UA_free(p);
 }
 }
 
 
-UA_StatusCode UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
+static UA_StatusCode
+UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
     dst->eventNotifier = src->eventNotifier;
     dst->eventNotifier = src->eventNotifier;
     dst->instanceHandle = src->instanceHandle;
     dst->instanceHandle = src->instanceHandle;
-	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-}
-
-/* UA_ObjectTypeNode */
-void UA_ObjectTypeNode_init(UA_ObjectTypeNode *p) {
-    memset(p, 0, sizeof(UA_ObjectTypeNode));
-    p->nodeClass = UA_NODECLASS_OBJECTTYPE;
-}
-
-UA_ObjectTypeNode * UA_ObjectTypeNode_new(void) {
-    UA_ObjectTypeNode *p = (UA_ObjectTypeNode*)UA_malloc(sizeof(UA_ObjectTypeNode));
-    if(p)
-        UA_ObjectTypeNode_init(p);
-    return p;
-}
-
-void UA_ObjectTypeNode_deleteMembers(UA_ObjectTypeNode *p) {
-    UA_Node_deleteMembers((UA_Node*)p);
-}
-
-void UA_ObjectTypeNode_delete(UA_ObjectTypeNode *p) {
-    UA_ObjectTypeNode_deleteMembers(p);
-    UA_free(p);
-}
-
-UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
-    dst->isAbstract = src->isAbstract;
-    dst->lifecycleManagement = src->lifecycleManagement;
-	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-}
-
-/* UA_VariableNode */
-void UA_VariableNode_init(UA_VariableNode *p) {
-    memset(p, 0, sizeof(UA_VariableNode));
-    p->nodeClass = UA_NODECLASS_VARIABLE;
-    p->valueRank = -2; // scalar or array of any dimension
-    p->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
-    p->userAccessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
-}
-
-UA_VariableNode * UA_VariableNode_new(void) {
-    UA_VariableNode *p = (UA_VariableNode*)UA_malloc(sizeof(UA_VariableNode));
-    if(p)
-        UA_VariableNode_init(p);
-    return p;
-}
-
-void UA_VariableNode_deleteMembers(UA_VariableNode *p) {
-    UA_Node_deleteMembers((UA_Node*)p);
-    if(p->valueSource == UA_VALUESOURCE_VARIANT)
-        UA_Variant_deleteMembers(&p->value.variant.value);
-}
-
-void UA_VariableNode_delete(UA_VariableNode *p) {
-    UA_VariableNode_deleteMembers(p);
-    UA_free(p);
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
-	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+static UA_StatusCode
+UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
     dst->valueRank = src->valueRank;
     dst->valueRank = src->valueRank;
     dst->valueSource = src->valueSource;
     dst->valueSource = src->valueSource;
     if(src->valueSource == UA_VALUESOURCE_VARIANT) {
     if(src->valueSource == UA_VALUESOURCE_VARIANT) {
-        retval = UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
+        UA_StatusCode retval = UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
         dst->value.variant.callback = src->value.variant.callback;
         dst->value.variant.callback = src->value.variant.callback;
     } else
     } else
         dst->value.dataSource = src->value.dataSource;
         dst->value.dataSource = src->value.dataSource;
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_VariableNode_deleteMembers(dst);
-        return retval;
-    }
     dst->accessLevel = src->accessLevel;
     dst->accessLevel = src->accessLevel;
     dst->userAccessLevel = src->accessLevel;
     dst->userAccessLevel = src->accessLevel;
     dst->minimumSamplingInterval = src->minimumSamplingInterval;
     dst->minimumSamplingInterval = src->minimumSamplingInterval;
@@ -235,178 +65,112 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-/* UA_VariableTypeNode */
-void UA_VariableTypeNode_init(UA_VariableTypeNode *p) {
-    memset(p, 0, sizeof(UA_VariableTypeNode));
-    p->nodeClass = UA_NODECLASS_VARIABLETYPE;
-    p->valueRank = -2; // scalar or array of any dimension
-}
-
-UA_VariableTypeNode * UA_VariableTypeNode_new(void) {
-    UA_VariableTypeNode *p = (UA_VariableTypeNode*)UA_malloc(sizeof(UA_VariableTypeNode));
-    if(p)
-        UA_VariableTypeNode_init(p);
-    return p;
-}
-
-void UA_VariableTypeNode_deleteMembers(UA_VariableTypeNode *p) {
-    UA_Node_deleteMembers((UA_Node*)p);
-    if(p->valueSource == UA_VALUESOURCE_VARIANT)
-        UA_Variant_deleteMembers(&p->value.variant.value);
+static UA_StatusCode
+UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
+    dst->executable = src->executable;
+    dst->userExecutable = src->userExecutable;
+    dst->methodHandle  = src->methodHandle;
+    dst->attachedMethod = src->attachedMethod;
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
-    UA_VariableTypeNode_deleteMembers(p);
-    UA_free(p);
+static UA_StatusCode
+UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
+    dst->isAbstract = src->isAbstract;
+    dst->lifecycleManagement = src->lifecycleManagement;
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) {
-	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+static UA_StatusCode
+UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) {
     dst->valueRank = src->valueRank;
     dst->valueRank = src->valueRank;
     dst->valueSource = src->valueSource;
     dst->valueSource = src->valueSource;
     if(src->valueSource == UA_VALUESOURCE_VARIANT){
     if(src->valueSource == UA_VALUESOURCE_VARIANT){
-        UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
+        UA_StatusCode retval = UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
         dst->value.variant.callback = src->value.variant.callback;
         dst->value.variant.callback = src->value.variant.callback;
     } else
     } else
         dst->value.dataSource = src->value.dataSource;
         dst->value.dataSource = src->value.dataSource;
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_VariableTypeNode_deleteMembers(dst);
-        return retval;
-    }
     dst->isAbstract = src->isAbstract;
     dst->isAbstract = src->isAbstract;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-/* UA_ReferenceTypeNode */
-void UA_ReferenceTypeNode_init(UA_ReferenceTypeNode *p) {
-    memset(p, 0, sizeof(UA_ReferenceTypeNode));
-    p->nodeClass = UA_NODECLASS_REFERENCETYPE;
-}
-
-UA_ReferenceTypeNode * UA_ReferenceTypeNode_new(void) {
-    UA_ReferenceTypeNode *p = (UA_ReferenceTypeNode*)UA_malloc(sizeof(UA_ReferenceTypeNode));
-    if(p)
-        UA_ReferenceTypeNode_init(p);
-    return p;
-}
-
-void UA_ReferenceTypeNode_deleteMembers(UA_ReferenceTypeNode *p) {
-    UA_Node_deleteMembers((UA_Node*)p);
-    UA_LocalizedText_deleteMembers(&p->inverseName);
-}
-
-void UA_ReferenceTypeNode_delete(UA_ReferenceTypeNode *p) {
-    UA_ReferenceTypeNode_deleteMembers(p);
-    UA_free(p);
-}
-
-UA_StatusCode UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src, UA_ReferenceTypeNode *dst) {
-    UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    retval = UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_ReferenceTypeNode_deleteMembers(dst);
-        return retval;
-    }
+static UA_StatusCode
+UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src, UA_ReferenceTypeNode *dst) {
+    UA_StatusCode retval = UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
     dst->isAbstract = src->isAbstract;
     dst->isAbstract = src->isAbstract;
     dst->symmetric = src->symmetric;
     dst->symmetric = src->symmetric;
-    return UA_STATUSCODE_GOOD;
-}
-
-/* UA_MethodNode */
-void UA_MethodNode_init(UA_MethodNode *p) {
-    memset(p, 0, sizeof(UA_MethodNode));
-    p->nodeClass = UA_NODECLASS_METHOD;
-}
-
-UA_MethodNode * UA_MethodNode_new(void) {
-    UA_MethodNode *p = (UA_MethodNode*)UA_malloc(sizeof(UA_MethodNode));
-    if(p)
-        UA_MethodNode_init(p);
-    return p;
-}
-
-void UA_MethodNode_deleteMembers(UA_MethodNode *p) {
-#ifdef UA_ENABLE_METHODCALLS
-    p->attachedMethod = NULL;
-#endif
-    UA_Node_deleteMembers((UA_Node*)p);
-}
-
-void UA_MethodNode_delete(UA_MethodNode *p) {
-    UA_MethodNode_deleteMembers(p);
-#ifdef UA_ENABLE_METHODCALLS
-    p->methodHandle   = NULL;
-    p->attachedMethod = NULL;
-#endif
-    UA_free(p);
-}
-
-UA_StatusCode UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
-    UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    dst->executable = src->executable;
-    dst->userExecutable = src->userExecutable;
-#ifdef UA_ENABLE_METHODCALLS
-    dst->methodHandle  = src->methodHandle;
-    dst->attachedMethod = src->attachedMethod;
-#endif
     return retval;
     return retval;
 }
 }
 
 
-/* UA_ViewNode */
-void UA_ViewNode_init(UA_ViewNode *p) {
-    memset(p, 0, sizeof(UA_ViewNode));
-    p->nodeClass = UA_NODECLASS_VIEW;
-}
-
-UA_ViewNode * UA_ViewNode_new(void) {
-    UA_ViewNode *p = UA_malloc(sizeof(UA_ViewNode));
-    if(p)
-        UA_ViewNode_init(p);
-    return p;
-}
-
-void UA_ViewNode_deleteMembers(UA_ViewNode *p) {
-    UA_Node_deleteMembers((UA_Node*)p);
-}
-
-void UA_ViewNode_delete(UA_ViewNode *p) {
-    UA_ViewNode_deleteMembers(p);
-    UA_free(p);
+static UA_StatusCode
+UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) {
+    dst->isAbstract = src->isAbstract;
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
+static UA_StatusCode
+UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
     dst->containsNoLoops = src->containsNoLoops;
     dst->containsNoLoops = src->containsNoLoops;
     dst->eventNotifier = src->eventNotifier;
     dst->eventNotifier = src->eventNotifier;
-	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-}
-
-/* UA_DataTypeNode */
-void UA_DataTypeNode_init(UA_DataTypeNode *p) {
-    memset(p, 0, sizeof(UA_DataTypeNode));
-    p->nodeClass = UA_NODECLASS_DATATYPE;
-}
-
-UA_DataTypeNode * UA_DataTypeNode_new(void) {
-    UA_DataTypeNode *p = UA_malloc(sizeof(UA_DataTypeNode));
-    if(p)
-        UA_DataTypeNode_init(p);
-    return p;
-}
-
-void UA_DataTypeNode_deleteMembers(UA_DataTypeNode *p) {
-    UA_Node_deleteMembers((UA_Node*)p);
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
-void UA_DataTypeNode_delete(UA_DataTypeNode *p) {
-    UA_DataTypeNode_deleteMembers(p);
-    UA_free(p);
-}
+UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst) {
+    if(src->nodeClass != dst->nodeClass)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    
+    /* copy standard content */
+	UA_StatusCode retval = UA_NodeId_copy(&src->nodeId, &dst->nodeId);
+	dst->nodeClass = src->nodeClass;
+	retval |= UA_QualifiedName_copy(&src->browseName, &dst->browseName);
+	retval |= UA_LocalizedText_copy(&src->displayName, &dst->displayName);
+	retval |= UA_LocalizedText_copy(&src->description, &dst->description);
+	dst->writeMask = src->writeMask;
+	dst->userWriteMask = src->userWriteMask;
+	if(retval != UA_STATUSCODE_GOOD) {
+    	UA_Node_deleteMembersAnyNodeClass(dst);
+        return retval;
+    }
+	retval |= UA_Array_copy(src->references, src->referencesSize, (void**)&dst->references,
+                            &UA_TYPES[UA_TYPES_REFERENCENODE]);
+	if(retval != UA_STATUSCODE_GOOD) {
+    	UA_Node_deleteMembersAnyNodeClass(dst);
+        return retval;
+    }
+    dst->referencesSize = src->referencesSize;
 
 
-UA_StatusCode UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) {
-    dst->isAbstract = src->isAbstract;
-	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
+    /* copy unique content of the nodeclass */
+    switch(src->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        retval = UA_ObjectNode_copy((const UA_ObjectNode*)src, (UA_ObjectNode*)dst);
+        break;
+    case UA_NODECLASS_VARIABLE:
+        retval = UA_VariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst);
+        break;
+    case UA_NODECLASS_METHOD:
+        retval = UA_MethodNode_copy((const UA_MethodNode*)src, (UA_MethodNode*)dst);
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        retval = UA_ObjectTypeNode_copy((const UA_ObjectTypeNode*)src, (UA_ObjectTypeNode*)dst);
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        retval = UA_VariableTypeNode_copy((const UA_VariableTypeNode*)src, (UA_VariableTypeNode*)dst);
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        retval = UA_ReferenceTypeNode_copy((const UA_ReferenceTypeNode*)src, (UA_ReferenceTypeNode*)dst);
+        break;
+    case UA_NODECLASS_DATATYPE:
+        retval = UA_DataTypeNode_copy((const UA_DataTypeNode*)src, (UA_DataTypeNode*)dst);
+        break;
+    case UA_NODECLASS_VIEW:
+        retval = UA_ViewNode_copy((const UA_ViewNode*)src, (UA_ViewNode*)dst);
+        break;
+    default:
+        break;
+    }
+	if(retval != UA_STATUSCODE_GOOD)
+    	UA_Node_deleteMembersAnyNodeClass(dst);
+    return retval;
 }
 }

+ 6 - 20
src/server/ua_nodes.h

@@ -5,12 +5,11 @@
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
 
 
-#define UA_TYPE_HANDLING_FUNCTIONS(TYPE)                             \
-    TYPE UA_EXPORT * TYPE##_new(void);                               \
-    void UA_EXPORT TYPE##_init(TYPE * p);                            \
-    void UA_EXPORT TYPE##_delete(TYPE * p);                          \
-    void UA_EXPORT TYPE##_deleteMembers(TYPE * p);                   \
-    UA_StatusCode UA_EXPORT TYPE##_copy(const TYPE *src, TYPE *dst);
+/*
+ * Most APIs take and return UA_EditNode and UA_ConstNode. By looking up the
+ * nodeclass, nodes can be cast to their "true" class, i.e. UA_VariableNode,
+ * UA_ObjectNode, and so on.
+ */
 
 
 #define UA_STANDARD_NODEMEMBERS                 \
 #define UA_STANDARD_NODEMEMBERS                 \
     UA_NodeId nodeId;                           \
     UA_NodeId nodeId;                           \
@@ -27,9 +26,8 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
 } UA_Node;
 } UA_Node;
 
 
-void UA_Node_deleteAnyNodeClass(UA_Node *node);
 void UA_Node_deleteMembersAnyNodeClass(UA_Node *node);
 void UA_Node_deleteMembersAnyNodeClass(UA_Node *node);
-UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node);
+UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst);
 
 
 /**************/
 /**************/
 /* ObjectNode */
 /* ObjectNode */
@@ -40,7 +38,6 @@ typedef struct {
     UA_Byte eventNotifier;
     UA_Byte eventNotifier;
     void *instanceHandle;
     void *instanceHandle;
 } UA_ObjectNode;
 } UA_ObjectNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectNode)
 
 
 /******************/
 /******************/
 /* ObjectTypeNode */
 /* ObjectTypeNode */
@@ -51,7 +48,6 @@ typedef struct {
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
     UA_ObjectLifecycleManagement lifecycleManagement;
     UA_ObjectLifecycleManagement lifecycleManagement;
 } UA_ObjectTypeNode;
 } UA_ObjectTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 
 
 typedef enum {
 typedef enum {
     UA_VALUESOURCE_VARIANT,
     UA_VALUESOURCE_VARIANT,
@@ -83,9 +79,6 @@ typedef struct {
     UA_Double minimumSamplingInterval;
     UA_Double minimumSamplingInterval;
     UA_Boolean historizing;
     UA_Boolean historizing;
 } UA_VariableNode;
 } UA_VariableNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_VariableNode)
-/** Make a copy but leave out the references and the variable */
-UA_StatusCode UA_VariableNode_copyWithoutRefsAndVariable(const UA_VariableNode *src, UA_VariableNode *dst);
 
 
 /********************/
 /********************/
 /* VariableTypeNode */
 /* VariableTypeNode */
@@ -105,7 +98,6 @@ typedef struct {
     /* <--- similar to variablenodes up to there--->*/
     /* <--- similar to variablenodes up to there--->*/
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
 } UA_VariableTypeNode;
 } UA_VariableTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)
 
 
 /*********************/
 /*********************/
 /* ReferenceTypeNode */
 /* ReferenceTypeNode */
@@ -117,7 +109,6 @@ typedef struct {
     UA_Boolean symmetric;
     UA_Boolean symmetric;
     UA_LocalizedText inverseName;
     UA_LocalizedText inverseName;
 } UA_ReferenceTypeNode;
 } UA_ReferenceTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ReferenceTypeNode)
 
 
 /**************/
 /**************/
 /* MethodNode */
 /* MethodNode */
@@ -127,12 +118,9 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
     UA_Boolean executable;
     UA_Boolean executable;
     UA_Boolean userExecutable;
     UA_Boolean userExecutable;
-#ifdef UA_ENABLE_METHODCALLS
     void *methodHandle;
     void *methodHandle;
     UA_MethodCallback attachedMethod;
     UA_MethodCallback attachedMethod;
-#endif
 } UA_MethodNode;
 } UA_MethodNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_MethodNode)
 
 
 /************/
 /************/
 /* ViewNode */
 /* ViewNode */
@@ -144,7 +132,6 @@ typedef struct {
     /* <-- the same as objectnode until here --> */
     /* <-- the same as objectnode until here --> */
     UA_Boolean containsNoLoops;
     UA_Boolean containsNoLoops;
 } UA_ViewNode;
 } UA_ViewNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ViewNode)
 
 
 /****************/
 /****************/
 /* DataTypeNode */
 /* DataTypeNode */
@@ -154,6 +141,5 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS
     UA_Boolean isAbstract;
     UA_Boolean isAbstract;
 } UA_DataTypeNode;
 } UA_DataTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_DataTypeNode)
 
 
 #endif /* UA_NODES_H_ */
 #endif /* UA_NODES_H_ */

+ 141 - 126
src/server/ua_nodestore.c

@@ -1,26 +1,17 @@
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
+#include <stdio.h>
 
 
 #define UA_NODESTORE_MINSIZE 64
 #define UA_NODESTORE_MINSIZE 64
 
 
-typedef struct {
-    UA_Boolean taken;
-    union {
-        UA_Node node;
-        UA_ObjectNode objectNode;
-        UA_ObjectTypeNode objectTypeNode;
-        UA_VariableNode variableNode;
-        UA_VariableTypeNode variableTypeNode;
-        UA_ReferenceTypeNode referenceTypeNode;
-        UA_MethodNode methodeNode;
-        UA_ViewNode viewNode;
-        UA_DataTypeNode dataTypeNode;
-    } node;
+typedef struct UA_NodeStoreEntry {
+    struct UA_NodeStoreEntry *orig; // the version this is a copy from (or NULL)
+    UA_Node node;
 } UA_NodeStoreEntry;
 } UA_NodeStoreEntry;
 
 
 struct UA_NodeStore {
 struct UA_NodeStore {
-    UA_NodeStoreEntry *entries;
+    UA_NodeStoreEntry **entries;
     UA_UInt32 size;
     UA_UInt32 size;
     UA_UInt32 count;
     UA_UInt32 count;
     UA_UInt32 sizePrimeIndex;
     UA_UInt32 sizePrimeIndex;
@@ -38,50 +29,92 @@ static hash_t const primes[] = {
     134217689, 268435399,  536870909,  1073741789, 2147483647,  4294967291
     134217689, 268435399,  536870909,  1073741789, 2147483647,  4294967291
 };
 };
 
 
-static UA_Int16 higher_prime_index(hash_t n) {
+static UA_UInt16 higher_prime_index(hash_t n) {
     UA_UInt16 low  = 0;
     UA_UInt16 low  = 0;
-    UA_UInt16 high = sizeof(primes) / sizeof(hash_t);
+    UA_UInt16 high = (UA_UInt16)(sizeof(primes) / sizeof(hash_t));
     while(low != high) {
     while(low != high) {
-        UA_UInt16 mid = low + (high - low) / 2;
+        UA_UInt16 mid = (UA_UInt16)(low + ((high - low) / 2));
         if(n > primes[mid])
         if(n > primes[mid])
-            low = mid + 1;
+            low = (UA_UInt16)(mid + 1);
         else
         else
             high = mid;
             high = mid;
     }
     }
     return low;
     return low;
 }
 }
 
 
+static UA_NodeStoreEntry * instantiateEntry(UA_NodeClass class) {
+    size_t size = sizeof(UA_NodeStoreEntry) - sizeof(UA_Node);
+    switch(class) {
+    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_NodeStoreEntry *entry = UA_calloc(1, size);
+    if(!entry)
+        return NULL;
+    entry->node.nodeClass = class;
+    return entry;
+}
+
+static void deleteEntry(UA_NodeStoreEntry *entry) {
+    UA_Node_deleteMembersAnyNodeClass(&entry->node);
+    UA_free(entry);
+}
+
 /* Returns UA_TRUE if an entry was found under the nodeid. Otherwise, returns
 /* Returns UA_TRUE if an entry was found under the nodeid. Otherwise, returns
    false and sets slot to a pointer to the next free slot. */
    false and sets slot to a pointer to the next free slot. */
 static UA_Boolean
 static UA_Boolean
-containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, UA_NodeStoreEntry **entry) {
-    hash_t         h     = hash(nodeid);
-    UA_UInt32      size  = ns->size;
-    hash_t         index = mod(h, size);
-    UA_NodeStoreEntry *e = &ns->entries[index];
+containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, UA_NodeStoreEntry ***entry) {
+    hash_t h = hash(nodeid);
+    UA_UInt32 size = ns->size;
+    hash_t idx = mod(h, size);
+    UA_NodeStoreEntry *e = ns->entries[idx];
 
 
-    if(!e->taken) {
-        *entry = e;
+    if(!e) {
+        *entry = &ns->entries[idx];
         return UA_FALSE;
         return UA_FALSE;
     }
     }
 
 
-    if(UA_NodeId_equal(&e->node.node.nodeId, nodeid)) {
-        *entry = e;
+    if(UA_NodeId_equal(&e->node.nodeId, nodeid)) {
+        *entry = &ns->entries[idx];
         return UA_TRUE;
         return UA_TRUE;
     }
     }
 
 
     hash_t hash2 = mod2(h, size);
     hash_t hash2 = mod2(h, size);
     for(;;) {
     for(;;) {
-        index += hash2;
-        if(index >= size)
-            index -= size;
-        e = &ns->entries[index];
-        if(!e->taken) {
-            *entry = e;
+        idx += hash2;
+        if(idx >= size)
+            idx -= size;
+        e = ns->entries[idx];
+        if(!e) {
+            *entry = &ns->entries[idx];
             return UA_FALSE;
             return UA_FALSE;
         }
         }
-        if(UA_NodeId_equal(&e->node.node.nodeId, nodeid)) {
-            *entry = e;
+        if(UA_NodeId_equal(&e->node.nodeId, nodeid)) {
+            *entry = &ns->entries[idx];
             return UA_TRUE;
             return UA_TRUE;
         }
         }
     }
     }
@@ -90,33 +123,31 @@ containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, UA_NodeStoreEntr
     return UA_TRUE;
     return UA_TRUE;
 }
 }
 
 
-/* The following function changes size of memory allocated for the entries and
-   repeatedly inserts the table elements. The occupancy of the table after the
-   call will be about 50%. */
+/* The occupancy of the table after the call will be about 50% */
 static UA_StatusCode expand(UA_NodeStore *ns) {
 static UA_StatusCode expand(UA_NodeStore *ns) {
     UA_UInt32 osize = ns->size;
     UA_UInt32 osize = ns->size;
     UA_UInt32 count = ns->count;
     UA_UInt32 count = ns->count;
-    /* Resize only when table after removal of unused elements is either too full or too empty.  */
+    /* 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_NODESTORE_MINSIZE))
     if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODESTORE_MINSIZE))
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
 
 
+    UA_NodeStoreEntry **oentries = ns->entries;
     UA_UInt32 nindex = higher_prime_index(count * 2);
     UA_UInt32 nindex = higher_prime_index(count * 2);
-    UA_Int32 nsize = primes[nindex];
-    UA_NodeStoreEntry *nentries;
-    if(!(nentries = UA_calloc(nsize, sizeof(UA_NodeStoreEntry))))
+    UA_UInt32 nsize = primes[nindex];
+    UA_NodeStoreEntry **nentries;
+    if(!(nentries = UA_calloc(nsize, sizeof(UA_NodeStoreEntry*))))
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
-    UA_NodeStoreEntry *oentries = ns->entries;
     ns->entries = nentries;
     ns->entries = nentries;
-    ns->size    = nsize;
+    ns->size = nsize;
     ns->sizePrimeIndex = nindex;
     ns->sizePrimeIndex = nindex;
 
 
-    // recompute the position of every entry and insert the pointer
+    /* recompute the position of every entry and insert the pointer */
     for(size_t i = 0, j = 0; i < osize && j < count; i++) {
     for(size_t i = 0, j = 0; i < osize && j < count; i++) {
-        if(!oentries[i].taken)
+        if(!oentries[i])
             continue;
             continue;
-        UA_NodeStoreEntry *e;
-        containsNodeId(ns, &oentries[i].node.node.nodeId, &e);  /* We know this returns an empty entry here */
+        UA_NodeStoreEntry **e;
+        containsNodeId(ns, &oentries[i]->node.nodeId, &e);  /* We know this returns an empty entry here */
         *e = oentries[i];
         *e = oentries[i];
         j++;
         j++;
     }
     }
@@ -125,49 +156,6 @@ static UA_StatusCode expand(UA_NodeStore *ns) {
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-/* Marks the entry dead and deletes if necessary. */
-static UA_INLINE void
-deleteEntry(UA_NodeStoreEntry *entry) {
-    UA_Node_deleteMembersAnyNodeClass(&entry->node.node);
-    entry->taken = UA_FALSE;
-}
-
-/** Copies the node into the entry. Then free the original node (but not its content). */
-static void fillEntry(UA_NodeStoreEntry *entry, UA_Node *node) {
-    size_t nodesize = 0;
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        nodesize = sizeof(UA_ObjectNode);
-        break;
-    case UA_NODECLASS_VARIABLE:
-        nodesize = sizeof(UA_VariableNode);
-        break;
-    case UA_NODECLASS_METHOD:
-        nodesize = sizeof(UA_MethodNode);
-        break;
-    case UA_NODECLASS_OBJECTTYPE:
-        nodesize = sizeof(UA_ObjectTypeNode);
-        break;
-    case UA_NODECLASS_VARIABLETYPE:
-        nodesize = sizeof(UA_VariableTypeNode);
-        break;
-    case UA_NODECLASS_REFERENCETYPE:
-        nodesize = sizeof(UA_ReferenceTypeNode);
-        break;
-    case UA_NODECLASS_DATATYPE:
-        nodesize = sizeof(UA_DataTypeNode);
-        break;
-    case UA_NODECLASS_VIEW:
-        nodesize = sizeof(UA_ViewNode);
-        break;
-    default:
-        UA_assert(UA_FALSE);
-    }
-    memcpy(&entry->node, node, nodesize);
-    UA_free(node);
-    entry->taken = UA_TRUE;
-}
-
 /**********************/
 /**********************/
 /* Exported functions */
 /* Exported functions */
 /**********************/
 /**********************/
@@ -179,7 +167,7 @@ UA_NodeStore * UA_NodeStore_new(void) {
     ns->sizePrimeIndex = higher_prime_index(UA_NODESTORE_MINSIZE);
     ns->sizePrimeIndex = higher_prime_index(UA_NODESTORE_MINSIZE);
     ns->size = primes[ns->sizePrimeIndex];
     ns->size = primes[ns->sizePrimeIndex];
     ns->count = 0;
     ns->count = 0;
-    if(!(ns->entries = UA_calloc(ns->size, sizeof(UA_NodeStoreEntry)))) {
+    if(!(ns->entries = UA_calloc(ns->size, sizeof(UA_NodeStoreEntry*)))) {
         UA_free(ns);
         UA_free(ns);
         return NULL;
         return NULL;
     }
     }
@@ -188,31 +176,42 @@ UA_NodeStore * UA_NodeStore_new(void) {
 
 
 void UA_NodeStore_delete(UA_NodeStore *ns) {
 void UA_NodeStore_delete(UA_NodeStore *ns) {
     UA_UInt32 size = ns->size;
     UA_UInt32 size = ns->size;
-    UA_NodeStoreEntry *entries = ns->entries;
-    for(UA_UInt32 i = 0;i < size;i++) {
-        if(entries[i].taken)
-            deleteEntry(&entries[i]);
+    UA_NodeStoreEntry **entries = ns->entries;
+    for(UA_UInt32 i = 0; i < size; i++) {
+        if(entries[i])
+            deleteEntry(entries[i]);
     }
     }
     UA_free(ns->entries);
     UA_free(ns->entries);
     UA_free(ns);
     UA_free(ns);
 }
 }
 
 
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, UA_Node **inserted) {
+UA_Node * UA_NodeStore_newNode(UA_NodeClass class) {
+    UA_NodeStoreEntry *entry = instantiateEntry(class);
+    if(!entry)
+        return NULL;
+    return (UA_Node*)&entry->node;
+}
+
+void UA_NodeStore_deleteNode(UA_Node *node) {
+    deleteEntry(container_of(node, UA_NodeStoreEntry, node));
+}
+
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node) {
     if(ns->size * 3 <= ns->count * 4) {
     if(ns->size * 3 <= ns->count * 4) {
         if(expand(ns) != UA_STATUSCODE_GOOD)
         if(expand(ns) != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADINTERNALERROR;
             return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
 
 
-    UA_NodeStoreEntry *entry;
     UA_NodeId tempNodeid;
     UA_NodeId tempNodeid;
     tempNodeid = node->nodeId;
     tempNodeid = node->nodeId;
     tempNodeid.namespaceIndex = 0;
     tempNodeid.namespaceIndex = 0;
+    UA_NodeStoreEntry **entry;
     if(UA_NodeId_isNull(&tempNodeid)) {
     if(UA_NodeId_isNull(&tempNodeid)) {
-        /* find a free nodeid */
-        if(node->nodeId.namespaceIndex == 0) //original request for ns=0 should yield ns=1
+        if(node->nodeId.namespaceIndex == 0)
             node->nodeId.namespaceIndex = 1;
             node->nodeId.namespaceIndex = 1;
-        UA_Int32 identifier = ns->count+1; // start value
-        UA_Int32 size = ns->size;
+        /* find a free nodeid */
+        UA_UInt32 identifier = ns->count+1; // start value
+        UA_UInt32 size = ns->size;
         hash_t increase = mod2(identifier, size);
         hash_t increase = mod2(identifier, size);
         while(UA_TRUE) {
         while(UA_TRUE) {
             node->nodeId.identifier.numeric = identifier;
             node->nodeId.identifier.numeric = identifier;
@@ -223,45 +222,61 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, UA_Node **ins
                 identifier -= size;
                 identifier -= size;
         }
         }
     } else {
     } else {
-        if(containsNodeId(ns, &node->nodeId, &entry))
+        if(containsNodeId(ns, &node->nodeId, &entry)) {
+            deleteEntry(container_of(node, UA_NodeStoreEntry, node));
             return UA_STATUSCODE_BADNODEIDEXISTS;
             return UA_STATUSCODE_BADNODEIDEXISTS;
+        }
     }
     }
 
 
-    fillEntry(entry, node);
+    *entry = container_of(node, UA_NodeStoreEntry, node);
     ns->count++;
     ns->count++;
-    if(inserted)
-        *inserted = &entry->node.node;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 UA_StatusCode
 UA_StatusCode
-UA_NodeStore_replace(UA_NodeStore *ns, UA_Node *oldNode,
-                     UA_Node *node, UA_Node **inserted) {
-    UA_NodeStoreEntry *slot;
-    if(!containsNodeId(ns, &node->nodeId, &slot))
+UA_NodeStore_replace(UA_NodeStore *ns, UA_Node *node) {
+    UA_NodeStoreEntry **entry;
+    if(!containsNodeId(ns, &node->nodeId, &entry))
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
-    /* that is not the node you are looking for */
-    if(&slot->node.node != oldNode)
-        return UA_STATUSCODE_BADINTERNALERROR;
-    deleteEntry(slot);
-    fillEntry(slot, node);
-    if(inserted)
-        *inserted = &slot->node.node;
+    UA_NodeStoreEntry *newEntry = container_of(node, UA_NodeStoreEntry, node);
+    if(*entry != newEntry->orig) {
+        deleteEntry(newEntry);
+        return UA_STATUSCODE_BADINTERNALERROR; // the node was replaced since the copy was made
+    }
+    deleteEntry(*entry);
+    *entry = newEntry;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
-    UA_NodeStoreEntry *slot;
+const UA_Node * UA_NodeStore_get(UA_NodeStore *ns, const UA_NodeId *nodeid) {
+    UA_NodeStoreEntry **entry;
+    if(!containsNodeId(ns, nodeid, &entry))
+        return NULL;
+    return (const UA_Node*)&(*entry)->node;
+}
+
+UA_Node * UA_NodeStore_getCopy(UA_NodeStore *ns, const UA_NodeId *nodeid) {
+    UA_NodeStoreEntry **slot;
     if(!containsNodeId(ns, nodeid, &slot))
     if(!containsNodeId(ns, nodeid, &slot))
         return NULL;
         return NULL;
-    return &slot->node.node;
+    UA_NodeStoreEntry *entry = *slot;
+    UA_NodeStoreEntry *new = instantiateEntry(entry->node.nodeClass);
+    if(!new)
+        return NULL;
+    if(UA_Node_copyAnyNodeClass(&entry->node, &new->node) != UA_STATUSCODE_GOOD) {
+        deleteEntry(new);
+        return NULL;
+    }
+    new->orig = entry;
+    return &new->node;
 }
 }
 
 
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
-    UA_NodeStoreEntry *slot;
+    UA_NodeStoreEntry **slot;
     if(!containsNodeId(ns, nodeid, &slot))
     if(!containsNodeId(ns, nodeid, &slot))
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
-    deleteEntry(slot);
+    deleteEntry(*slot);
+    *slot = NULL;
     ns->count--;
     ns->count--;
     /* Downsize the hashmap if it is very empty */
     /* Downsize the hashmap if it is very empty */
     if(ns->count * 8 < ns->size && ns->size > 32)
     if(ns->count * 8 < ns->size && ns->size > 32)
@@ -269,9 +284,9 @@ UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
-    for(UA_UInt32 i = 0;i < ns->size;i++) {
-        if(ns->entries[i].taken)
-            visitor(&ns->entries[i].node.node);
+void UA_NodeStore_iterate(UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
+    for(UA_UInt32 i = 0; i < ns->size; i++) {
+        if(ns->entries[i])
+            visitor((UA_Node*)&ns->entries[i]->node);
     }
     }
 }
 }

+ 32 - 48
src/server/ua_nodestore.h

@@ -5,33 +5,10 @@
 #include "ua_nodes.h"
 #include "ua_nodes.h"
 
 
 /**
 /**
- * @ingroup server
- *
- * @defgroup nodestore NodeStore
- *
- * @brief Stores the nodes in the address space. Internally, it is based on a
- * hash-map that maps nodes to their nodeid.
- *
- * Nodes need to be allocated on the heap before adding them to the nodestore
- * with. When adding, the node is copied to a new (managed) location in the
- * nodestore and the original memory is freed. The nodes in the nodestore are
- * immutable. To change the content of a node, it needs to be replaced as a
- * whole.
- *
- * Every node you _get from the nodestore needs to be _released when it is no
- * longer needed. In the background, reference counting is used to know if
- * somebody still uses the node in multi-threaded environments.
- *
- * @{
+ * Stores the nodes in the address space. Internally, it is based on a hash-map
+ * that maps nodes to their nodeid.
  */
  */
 
 
-/* For multithreading, nodes in the nodestore are immutable */
-#ifdef UA_ENABLE_MULTITHREADING
-# define UA_MT_CONST const
-#else
-# define UA_MT_CONST
-#endif
-
 struct UA_NodeStore;
 struct UA_NodeStore;
 typedef struct UA_NodeStore UA_NodeStore;
 typedef struct UA_NodeStore UA_NodeStore;
 
 
@@ -42,37 +19,46 @@ UA_NodeStore * UA_NodeStore_new(void);
     critical section (multithreading). */
     critical section (multithreading). */
 void UA_NodeStore_delete(UA_NodeStore *ns);
 void UA_NodeStore_delete(UA_NodeStore *ns);
 
 
+/** Create an editable node of the given NodeClass. */
+UA_Node * UA_NodeStore_newNode(UA_NodeClass class);
+#define UA_NodeStore_newObjectNode() (UA_ObjectNode*)UA_NodeStore_newNode(UA_NODECLASS_OBJECT)
+#define UA_NodeStore_newVariableNode() (UA_VariableNode*)UA_NodeStore_newNode(UA_NODECLASS_VARIABLE)
+#define UA_NodeStore_newMethodNode() (UA_MethodNode*)UA_NodeStore_newNode(UA_NODECLASS_METHOD)
+#define UA_NodeStore_newObjectTypeNode() (UA_ObjectTypeNode*)UA_NodeStore_newNode(UA_NODECLASS_OBJECTTYPE)
+#define UA_NodeStore_newVariableTypeNode() (UA_VariableTypeNode*)UA_NodeStore_newNode(UA_NODECLASS_VARIABLETYPE)
+#define UA_NodeStore_newReferenceTypeNode() (UA_ReferenceTypeNode*)UA_NodeStore_newNode(UA_NODECLASS_REFERENCETYPE)
+#define UA_NodeStore_newDataTypeNode() (UA_DataTypeNode*)UA_NodeStore_newNode(UA_NODECLASS_DATATYPE)
+#define UA_NodeStore_newViewNode() (UA_ViewNode*)UA_NodeStore_newNode(UA_NODECLASS_VIEW)
+
+/** Delete an editable node. */
+void UA_NodeStore_deleteNode(UA_Node *node);
+
 /**
 /**
  * Inserts a new node into the nodestore. If the nodeid is zero, then a fresh
  * Inserts a new node into the nodestore. If the nodeid is zero, then a fresh
- * numeric nodeid from nodestore 1 is assigned. The memory of the original node
- * is freed and the content is moved to a managed (immutable) node. If inserted
- * is not NULL, then a pointer to the managed node is returned (and must be
- * released).
+ * numeric nodeid from namespace 1 is assigned. If insertion fails, the node is
+ * deleted.
  */
  */
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, UA_MT_CONST UA_Node **inserted);
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node);
 
 
 /**
 /**
- * Replace an existing node in the nodestore. If the node was already replaced,
- * UA_STATUSCODE_BADINTERNALERROR is returned. A pointer to the inserted node is
- * returned. It is important that oldNode is not used afterwards in the same
- * thread.
+ * To replace, get an editable copy, edit and use 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 UA_NodeStore_replace(UA_NodeStore *ns, UA_MT_CONST UA_Node *oldNode,
-                                   UA_Node *node, UA_MT_CONST UA_Node **inserted);
+UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, UA_Node *node);
 
 
-/**
- * Remove a node from the nodestore. Always succeeds, even if the node was not
- * found.
- */
+/** Remove a node in the nodestore. */
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid);
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid);
 
 
 /**
 /**
- * Retrieve a managed node (read-only) from the nodestore. Nodes are reference-
- * counted (for garbage collection) and immutable. They can only be replaced
- * entirely. After the node is no longer used, it needs to be released to decrease
- * the reference count.
+ * The returned pointer is only valid as long as the node has not been replaced
+ * or removed (in the same thread).
  */
  */
-UA_MT_CONST UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid);
+const UA_Node * UA_NodeStore_get(UA_NodeStore *ns, const UA_NodeId *nodeid);
+
+/** Returns the copy of a node. */
+UA_Node * UA_NodeStore_getCopy(UA_NodeStore *ns, const UA_NodeId *nodeid);
 
 
 /**
 /**
  * A function that can be evaluated on all entries in a nodestore via
  * A function that can be evaluated on all entries in a nodestore via
@@ -81,8 +67,6 @@ UA_MT_CONST UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *
 typedef void (*UA_NodeStore_nodeVisitor)(const UA_Node *node);
 typedef void (*UA_NodeStore_nodeVisitor)(const UA_Node *node);
 
 
 /** Iterate over all nodes in a nodestore. */
 /** Iterate over all nodes in a nodestore. */
-void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor);
-
-/** @} */
+void UA_NodeStore_iterate(UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor);
 
 
 #endif /* UA_NODESTORE_H_ */
 #endif /* UA_NODESTORE_H_ */

+ 96 - 138
src/server/ua_nodestore_concurrent.c

@@ -4,47 +4,53 @@
 struct nodeEntry {
 struct nodeEntry {
     struct cds_lfht_node htn; ///< Contains the next-ptr for urcu-hashmap
     struct cds_lfht_node htn; ///< Contains the next-ptr for urcu-hashmap
     struct rcu_head rcu_head; ///< For call-rcu
     struct rcu_head rcu_head; ///< For call-rcu
+    struct nodeEntry *orig; //< the version this is a copy from (or NULL)
     UA_Node node; ///< Might be cast from any _bigger_ UA_Node* type. Allocate enough memory!
     UA_Node node; ///< Might be cast from any _bigger_ UA_Node* type. Allocate enough memory!
 };
 };
 
 
-struct UA_NodeStore {
-    struct cds_lfht *ht;
-};
-
 #include "ua_nodestore_hash.inc"
 #include "ua_nodestore_hash.inc"
 
 
-static void deleteEntry(struct rcu_head *head) {
-    struct nodeEntry *entry = caa_container_of(head, struct nodeEntry, rcu_head);
-    switch(entry->node.nodeClass) {
+static struct nodeEntry * instantiateEntry(UA_NodeClass class) {
+    size_t size = sizeof(struct nodeEntry) - sizeof(UA_Node);
+    switch(class) {
     case UA_NODECLASS_OBJECT:
     case UA_NODECLASS_OBJECT:
-        UA_ObjectNode_deleteMembers((UA_ObjectNode*)&entry->node);
+        size += sizeof(UA_ObjectNode);
         break;
         break;
     case UA_NODECLASS_VARIABLE:
     case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_deleteMembers((UA_VariableNode*)&entry->node);
+        size += sizeof(UA_VariableNode);
         break;
         break;
     case UA_NODECLASS_METHOD:
     case UA_NODECLASS_METHOD:
-        UA_MethodNode_deleteMembers((UA_MethodNode*)&entry->node);
+        size += sizeof(UA_MethodNode);
         break;
         break;
     case UA_NODECLASS_OBJECTTYPE:
     case UA_NODECLASS_OBJECTTYPE:
-        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode*)&entry->node);
+        size += sizeof(UA_ObjectTypeNode);
         break;
         break;
     case UA_NODECLASS_VARIABLETYPE:
     case UA_NODECLASS_VARIABLETYPE:
-        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode*)&entry->node);
+        size += sizeof(UA_VariableTypeNode);
         break;
         break;
     case UA_NODECLASS_REFERENCETYPE:
     case UA_NODECLASS_REFERENCETYPE:
-        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode*)&entry->node);
+        size += sizeof(UA_ReferenceTypeNode);
         break;
         break;
     case UA_NODECLASS_DATATYPE:
     case UA_NODECLASS_DATATYPE:
-        UA_DataTypeNode_deleteMembers((UA_DataTypeNode*)&entry->node);
+        size += sizeof(UA_DataTypeNode);
         break;
         break;
     case UA_NODECLASS_VIEW:
     case UA_NODECLASS_VIEW:
-        UA_ViewNode_deleteMembers((UA_ViewNode*)&entry->node);
+        size += sizeof(UA_ViewNode);
         break;
         break;
     default:
     default:
-        UA_assert(UA_FALSE);
-        break;
+        return NULL;
     }
     }
-    free(entry);
+    struct nodeEntry *entry = UA_calloc(1, size);
+    if(!entry)
+        return NULL;
+    entry->node.nodeClass = class;
+    return entry;
+}
+
+static void deleteEntry(struct rcu_head *head) {
+    struct nodeEntry *entry = container_of(head, struct nodeEntry, rcu_head);
+    UA_Node_deleteMembersAnyNodeClass(&entry->node);
+    UA_free(entry);
 }
 }
 
 
 /* We are in a rcu_read lock. So the node will not be freed under our feet. */
 /* We are in a rcu_read lock. So the node will not be freed under our feet. */
@@ -56,25 +62,16 @@ static int compare(struct cds_lfht_node *htn, const void *orig) {
 }
 }
 
 
 UA_NodeStore * UA_NodeStore_new() {
 UA_NodeStore * UA_NodeStore_new() {
-    UA_NodeStore *ns;
-    if(!(ns = UA_malloc(sizeof(UA_NodeStore))))
-        return NULL;
-
-    /* 32 is the minimum size for the hashtable. */
-    ns->ht = cds_lfht_new(32, 32, 0, CDS_LFHT_AUTO_RESIZE, NULL);
-    if(!ns->ht) {
-        UA_free(ns);
-        ns = NULL;
-    }
-    return ns;
+    /* 64 is the minimum size for the hashtable. */
+    return (UA_NodeStore*)cds_lfht_new(64, 64, 0, CDS_LFHT_AUTO_RESIZE, NULL);
 }
 }
 
 
 /* do not call with read-side critical section held!! */
 /* do not call with read-side critical section held!! */
 void UA_NodeStore_delete(UA_NodeStore *ns) {
 void UA_NodeStore_delete(UA_NodeStore *ns) {
-    struct cds_lfht *ht = ns->ht;
-    struct cds_lfht_iter  iter;
+    UA_ASSERT_RCU_LOCKED();
+    struct cds_lfht *ht = (struct cds_lfht*)ns;
+    struct cds_lfht_iter iter;
     cds_lfht_first(ht, &iter);
     cds_lfht_first(ht, &iter);
-    rcu_read_lock();
     while(iter.node) {
     while(iter.node) {
         if(!cds_lfht_del(ht, iter.node)) {
         if(!cds_lfht_del(ht, iter.node)) {
             /* points to the htn entry, which is first */
             /* points to the htn entry, which is first */
@@ -83,49 +80,26 @@ void UA_NodeStore_delete(UA_NodeStore *ns) {
         }
         }
         cds_lfht_next(ht, &iter);
         cds_lfht_next(ht, &iter);
     }
     }
-    rcu_read_unlock();
     cds_lfht_destroy(ht, NULL);
     cds_lfht_destroy(ht, NULL);
     UA_free(ns);
     UA_free(ns);
 }
 }
 
 
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node **inserted) {
-    size_t nodesize;
-    /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        nodesize = sizeof(UA_ObjectNode);
-        break;
-    case UA_NODECLASS_VARIABLE:
-        nodesize = sizeof(UA_VariableNode);
-        break;
-    case UA_NODECLASS_METHOD:
-        nodesize = sizeof(UA_MethodNode);
-        break;
-    case UA_NODECLASS_OBJECTTYPE:
-        nodesize = sizeof(UA_ObjectTypeNode);
-        break;
-    case UA_NODECLASS_VARIABLETYPE:
-        nodesize = sizeof(UA_VariableTypeNode);
-        break;
-    case UA_NODECLASS_REFERENCETYPE:
-        nodesize = sizeof(UA_ReferenceTypeNode);
-        break;
-    case UA_NODECLASS_DATATYPE:
-        nodesize = sizeof(UA_DataTypeNode);
-        break;
-    case UA_NODECLASS_VIEW:
-        nodesize = sizeof(UA_ViewNode);
-        break;
-    default:
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
+UA_Node * UA_NodeStore_newNode(UA_NodeClass class) {
+    struct nodeEntry *entry = instantiateEntry(class);
+    if(!entry)
+        return NULL;
+    return (UA_Node*)&entry->node;
+}
 
 
-    struct nodeEntry *entry;
-    if(!(entry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    UA_Node *newNode = &entry->node;
-    memcpy(newNode, node, nodesize);
+void UA_NodeStore_deleteNode(UA_Node *node) {
+    struct nodeEntry *entry = container_of(node, struct nodeEntry, node);
+    deleteEntry(&entry->rcu_head);
+}
 
 
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node) {
+    UA_ASSERT_RCU_LOCKED();
+    struct nodeEntry *entry = container_of(node, struct nodeEntry, node);
+    struct cds_lfht *ht = (struct cds_lfht*)ns;
     cds_lfht_node_init(&entry->htn);
     cds_lfht_node_init(&entry->htn);
     struct cds_lfht_node *result;
     struct cds_lfht_node *result;
     //namespace index is assumed to be valid
     //namespace index is assumed to be valid
@@ -134,131 +108,115 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
     tempNodeid.namespaceIndex = 0;
     tempNodeid.namespaceIndex = 0;
     if(!UA_NodeId_isNull(&tempNodeid)) {
     if(!UA_NodeId_isNull(&tempNodeid)) {
         hash_t h = hash(&node->nodeId);
         hash_t h = hash(&node->nodeId);
-        result = cds_lfht_add_unique(ns->ht, h, compare, &newNode->nodeId, &entry->htn);
+        result = cds_lfht_add_unique(ht, h, compare, &node->nodeId, &entry->htn);
         /* If the nodeid exists already */
         /* If the nodeid exists already */
         if(result != &entry->htn) {
         if(result != &entry->htn) {
-            UA_free(entry);
+            deleteEntry(&entry->rcu_head);
             return UA_STATUSCODE_BADNODEIDEXISTS;
             return UA_STATUSCODE_BADNODEIDEXISTS;
         }
         }
     } else {
     } else {
         /* create a unique nodeid */
         /* create a unique nodeid */
-        newNode->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-        if(newNode->nodeId.namespaceIndex == 0) // original request for ns=0 should yield ns=1
-            newNode->nodeId.namespaceIndex = 1;
+        node->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
+        if(node->nodeId.namespaceIndex == 0) // original request for ns=0 should yield ns=1
+            node->nodeId.namespaceIndex = 1;
         /* set namespaceIndex in browseName in case id is generated */
         /* set namespaceIndex in browseName in case id is generated */
-        if(newNode->nodeClass == UA_NODECLASS_VARIABLE)
-        	((UA_VariableNode*)newNode)->browseName.namespaceIndex = newNode->nodeId.namespaceIndex;
+        if(node->nodeClass == UA_NODECLASS_VARIABLE)
+        	((UA_VariableNode*)node)->browseName.namespaceIndex = node->nodeId.namespaceIndex;
 
 
         unsigned long identifier;
         unsigned long identifier;
         long before, after;
         long before, after;
-        cds_lfht_count_nodes(ns->ht, &before, &identifier, &after); // current amount of nodes stored
+        cds_lfht_count_nodes(ht, &before, &identifier, &after); // current amount of nodes stored
         identifier++;
         identifier++;
 
 
-        newNode->nodeId.identifier.numeric = identifier;
+        node->nodeId.identifier.numeric = (UA_UInt32)identifier;
         while(UA_TRUE) {
         while(UA_TRUE) {
-            hash_t h = hash(&newNode->nodeId);
-            result = cds_lfht_add_unique(ns->ht, h, compare, &newNode->nodeId, &entry->htn);
+            hash_t h = hash(&node->nodeId);
+            result = cds_lfht_add_unique(ht, h, compare, &node->nodeId, &entry->htn);
             if(result == &entry->htn)
             if(result == &entry->htn)
                 break;
                 break;
-            newNode->nodeId.identifier.numeric += (identifier * 2654435761);
+            node->nodeId.identifier.numeric += (UA_UInt32)(identifier * 2654435761);
         }
         }
     }
     }
-
-    UA_free(node);
-    if(inserted)
-        *inserted = &entry->node;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_Node *node,
-                                   const UA_Node **inserted) {
+UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, UA_Node *node) {
+    UA_ASSERT_RCU_LOCKED();
+    struct nodeEntry *entry = container_of(node, struct nodeEntry, node);
+    struct cds_lfht *ht = (struct cds_lfht*)ns;
+
     /* Get the current version */
     /* Get the current version */
     hash_t h = hash(&node->nodeId);
     hash_t h = hash(&node->nodeId);
     struct cds_lfht_iter iter;
     struct cds_lfht_iter iter;
-    cds_lfht_lookup(ns->ht, h, compare, &node->nodeId, &iter);
+    cds_lfht_lookup(ht, h, compare, &node->nodeId, &iter);
     if(!iter.node)
     if(!iter.node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
 
     /* We try to replace an obsolete version of the node */
     /* We try to replace an obsolete version of the node */
     struct nodeEntry *oldEntry = (struct nodeEntry*)iter.node;
     struct nodeEntry *oldEntry = (struct nodeEntry*)iter.node;
-    if(&oldEntry->node != oldNode)
+    if(oldEntry != entry->orig)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     
     
-    size_t nodesize;
-    /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        nodesize = sizeof(UA_ObjectNode);
-        break;
-    case UA_NODECLASS_VARIABLE:
-        nodesize = sizeof(UA_VariableNode);
-        break;
-    case UA_NODECLASS_METHOD:
-        nodesize = sizeof(UA_MethodNode);
-        break;
-    case UA_NODECLASS_OBJECTTYPE:
-        nodesize = sizeof(UA_ObjectTypeNode);
-        break;
-    case UA_NODECLASS_VARIABLETYPE:
-        nodesize = sizeof(UA_VariableTypeNode);
-        break;
-    case UA_NODECLASS_REFERENCETYPE:
-        nodesize = sizeof(UA_ReferenceTypeNode);
-        break;
-    case UA_NODECLASS_DATATYPE:
-        nodesize = sizeof(UA_DataTypeNode);
-        break;
-    case UA_NODECLASS_VIEW:
-        nodesize = sizeof(UA_ViewNode);
-        break;
-    default:
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
-
-    struct nodeEntry *newEntry;
-    if(!(newEntry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    memcpy((void*)&newEntry->node, node, nodesize);
-    cds_lfht_node_init(&newEntry->htn);
-
-    if(cds_lfht_replace(ns->ht, &iter, h, compare, &node->nodeId, &newEntry->htn) != 0) {
+    cds_lfht_node_init(&entry->htn);
+    if(cds_lfht_replace(ht, &iter, h, compare, &node->nodeId, &entry->htn) != 0) {
         /* Replacing failed. Maybe the node got replaced just before this thread tried to.*/
         /* Replacing failed. Maybe the node got replaced just before this thread tried to.*/
-        UA_free(newEntry);
+        deleteEntry(&entry->rcu_head);
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
         
         
     /* If an entry got replaced, mark it as dead. */
     /* If an entry got replaced, mark it as dead. */
     call_rcu(&oldEntry->rcu_head, deleteEntry);
     call_rcu(&oldEntry->rcu_head, deleteEntry);
-    UA_free(node);
-
-    if(inserted)
-        *inserted = &newEntry->node;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
+    UA_ASSERT_RCU_LOCKED();
+    struct cds_lfht *ht = (struct cds_lfht*)ns;
     hash_t h = hash(nodeid);
     hash_t h = hash(nodeid);
     struct cds_lfht_iter iter;
     struct cds_lfht_iter iter;
-    cds_lfht_lookup(ns->ht, h, compare, &nodeid, &iter);
-    if(!iter.node || cds_lfht_del(ns->ht, iter.node) != 0)
+    cds_lfht_lookup(ht, h, compare, &nodeid, &iter);
+    if(!iter.node || cds_lfht_del(ht, iter.node) != 0)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
     struct nodeEntry *entry = (struct nodeEntry*)iter.node;
     struct nodeEntry *entry = (struct nodeEntry*)iter.node;
     call_rcu(&entry->rcu_head, deleteEntry);
     call_rcu(&entry->rcu_head, deleteEntry);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-const UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
+const UA_Node * UA_NodeStore_get(UA_NodeStore *ns, const UA_NodeId *nodeid) {
+    UA_ASSERT_RCU_LOCKED();
+    struct cds_lfht *ht = (struct cds_lfht*)ns;
     hash_t h = hash(nodeid);
     hash_t h = hash(nodeid);
     struct cds_lfht_iter iter;
     struct cds_lfht_iter iter;
-    cds_lfht_lookup(ns->ht, h, compare, nodeid, &iter);
+    cds_lfht_lookup(ht, h, compare, nodeid, &iter);
     struct nodeEntry *found_entry = (struct nodeEntry*)iter.node;
     struct nodeEntry *found_entry = (struct nodeEntry*)iter.node;
     if(!found_entry)
     if(!found_entry)
         return NULL;
         return NULL;
     return &found_entry->node;
     return &found_entry->node;
 }
 }
 
 
-void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
-    struct cds_lfht *ht = ns->ht;
+UA_Node * UA_NodeStore_getCopy(UA_NodeStore *ns, const UA_NodeId *nodeid) {
+    UA_ASSERT_RCU_LOCKED();
+    struct cds_lfht *ht = (struct cds_lfht*)ns;
+    hash_t h = hash(nodeid);
+    struct cds_lfht_iter iter;
+    cds_lfht_lookup(ht, h, compare, nodeid, &iter);
+    struct nodeEntry *entry = (struct nodeEntry*)iter.node;
+    if(!entry)
+        return NULL;
+    struct nodeEntry *new = instantiateEntry(entry->node.nodeClass);
+    if(!new)
+        return NULL;
+    if(UA_Node_copyAnyNodeClass(&entry->node, &new->node) != UA_STATUSCODE_GOOD) {
+        deleteEntry(&new->rcu_head);
+        return NULL;
+    }
+    new->orig = entry;
+    return &new->node;
+}
+
+void UA_NodeStore_iterate(UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
+    UA_ASSERT_RCU_LOCKED();
+    struct cds_lfht *ht = (struct cds_lfht*)ns;
     struct cds_lfht_iter iter;
     struct cds_lfht_iter iter;
     cds_lfht_first(ht, &iter);
     cds_lfht_first(ht, &iter);
     while(iter.node != NULL) {
     while(iter.node != NULL) {

+ 10 - 8
src/server/ua_nodestore_hash.inc

@@ -8,7 +8,7 @@ static hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
     if(data == NULL)
     if(data == NULL)
         return 0;
         return 0;
 
 
-    const int32_t   nblocks = len / 4;
+    const int32_t nblocks = (int32_t)(len / 4);
     const uint32_t *blocks;
     const uint32_t *blocks;
     static const uint32_t c1 = 0xcc9e2d51;
     static const uint32_t c1 = 0xcc9e2d51;
     static const uint32_t c2 = 0x1b873593;
     static const uint32_t c2 = 0x1b873593;
@@ -36,12 +36,12 @@ static hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
     }
     }
 
 
     const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
     const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
-    uint32_t       k1   = 0;
+    uint32_t k1 = 0;
     switch(len & 3) {
     switch(len & 3) {
     case 3:
     case 3:
-        k1 ^= tail[2] << 16;
+        k1 ^= (uint32_t)(tail[2] << 16);
     case 2:
     case 2:
-        k1 ^= tail[1] << 8;
+        k1 ^= (uint32_t)(tail[1] << 8);
     case 1:
     case 1:
         k1   ^= tail[0];
         k1   ^= tail[0];
         k1   *= c1;
         k1   *= c1;
@@ -63,13 +63,15 @@ static hash_t hash(const UA_NodeId *n) {
     switch(n->identifierType) {
     switch(n->identifierType) {
     case UA_NODEIDTYPE_NUMERIC:
     case UA_NODEIDTYPE_NUMERIC:
         /*  Knuth's multiplicative hashing */
         /*  Knuth's multiplicative hashing */
-        return (n->identifier.numeric + n->namespaceIndex) * 2654435761;   // mod(2^32) is implicit
+        return (hash_t)((n->identifier.numeric + n->namespaceIndex) * 2654435761); // mod(2^32) is implicit
     case UA_NODEIDTYPE_STRING:
     case UA_NODEIDTYPE_STRING:
-        return hash_array(n->identifier.string.data, n->identifier.string.length, n->namespaceIndex);
+        return hash_array(n->identifier.string.data, (UA_UInt32)n->identifier.string.length,
+                          n->namespaceIndex);
     case UA_NODEIDTYPE_GUID:
     case UA_NODEIDTYPE_GUID:
-        return hash_array((const UA_Byte *)&(n->identifier.guid), sizeof(UA_Guid), n->namespaceIndex);
+        return hash_array((const UA_Byte*)&(n->identifier.guid), sizeof(UA_Guid), n->namespaceIndex);
     case UA_NODEIDTYPE_BYTESTRING:
     case UA_NODEIDTYPE_BYTESTRING:
-        return hash_array((const UA_Byte *)n->identifier.byteString.data, n->identifier.byteString.length, n->namespaceIndex);
+        return hash_array((const UA_Byte*)n->identifier.byteString.data,
+                          (UA_UInt32)n->identifier.byteString.length, n->namespaceIndex);
     default:
     default:
         UA_assert(UA_FALSE);
         UA_assert(UA_FALSE);
         return 0;
         return 0;

+ 4 - 4
src/server/ua_securechannel_manager.h

@@ -13,13 +13,13 @@ typedef struct channel_list_entry {
 
 
 typedef struct UA_SecureChannelManager {
 typedef struct UA_SecureChannelManager {
     LIST_HEAD(channel_list, channel_list_entry) channels; // doubly-linked list of channels
     LIST_HEAD(channel_list, channel_list_entry) channels; // doubly-linked list of channels
-    size_t    maxChannelCount;
+    size_t maxChannelCount;
     size_t currentChannelCount;
     size_t currentChannelCount;
-    UA_DateTime maxChannelLifetime;
+    UA_UInt32 maxChannelLifetime;
     UA_MessageSecurityMode securityMode;
     UA_MessageSecurityMode securityMode;
     UA_DateTime channelLifeTime;
     UA_DateTime channelLifeTime;
-    UA_Int32    lastChannelId;
-    UA_UInt32   lastTokenId;
+    UA_UInt32 lastChannelId;
+    UA_UInt32 lastTokenId;
 } UA_SecureChannelManager;
 } UA_SecureChannelManager;
 
 
 UA_StatusCode
 UA_StatusCode

Diferenças do arquivo suprimidas por serem muito extensas
+ 194 - 256
src/server/ua_server.c


+ 27 - 12
src/server/ua_server_binary.c

@@ -62,6 +62,16 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
     UA_UInt32 secureChannelId;
     UA_UInt32 secureChannelId;
     UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
     UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
 
 
+    //we can check secureChannelId also here -> if we are asked to isse a token it is 0, otherwise we have to renew
+    //issue
+    if(connection->channel == NULL && secureChannelId != 0){
+        retval |= UA_STATUSCODE_BADREQUESTTYPEINVALID;
+    }
+    //renew
+    if(connection->channel != NULL && secureChannelId != connection->channel->securityToken.channelId){
+        retval |= UA_STATUSCODE_BADREQUESTTYPEINVALID;
+    }
+
     UA_AsymmetricAlgorithmSecurityHeader asymHeader;
     UA_AsymmetricAlgorithmSecurityHeader asymHeader;
     retval |= UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, pos, &asymHeader);
     retval |= UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, pos, &asymHeader);
 
 
@@ -83,6 +93,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
         return;
         return;
     }
     }
 
 
+
     UA_OpenSecureChannelResponse p;
     UA_OpenSecureChannelResponse p;
     UA_OpenSecureChannelResponse_init(&p);
     UA_OpenSecureChannelResponse_init(&p);
     Service_OpenSecureChannel(server, connection, &r, &p);
     Service_OpenSecureChannel(server, connection, &r, &p);
@@ -129,7 +140,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
         connection->releaseSendBuffer(connection, &resp_msg);
         connection->releaseSendBuffer(connection, &resp_msg);
         connection->close(connection);
         connection->close(connection);
     } else {
     } else {
-        respHeader.messageHeader.messageSize = tmpPos;
+        respHeader.messageHeader.messageSize = (UA_UInt32)tmpPos;
         tmpPos = 0;
         tmpPos = 0;
         UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
         UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
         resp_msg.length = respHeader.messageHeader.messageSize;
         resp_msg.length = respHeader.messageHeader.messageSize;
@@ -309,7 +320,7 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
     UA_StatusCode retval = UA_UInt32_decodeBinary(msg, pos, &secureChannelId);
     retval |= UA_UInt32_decodeBinary(msg, pos, &tokenId);
     retval |= UA_UInt32_decodeBinary(msg, pos, &tokenId);
     retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader);
     retval |= UA_SequenceHeader_decodeBinary(msg, pos, &sequenceHeader);
-    retval = UA_NodeId_decodeBinary(msg, pos, &requestTypeId);
+    retval |= UA_NodeId_decodeBinary(msg, pos, &requestTypeId);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
         return;
         return;
 
 
@@ -327,7 +338,7 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     if(tokenId != channel->securityToken.tokenId) {
     if(tokenId != channel->securityToken.tokenId) {
         if(tokenId != channel->nextSecurityToken.tokenId) {
         if(tokenId != channel->nextSecurityToken.tokenId) {
             /* close the securechannel but keep the connection open */
             /* close the securechannel but keep the connection open */
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Request with a wrong security token. Closing the SecureChannel %i.",
                         "Request with a wrong security token. Closing the SecureChannel %i.",
                         channel->securityToken.channelId);
                         channel->securityToken.channelId);
             Service_CloseSecureChannel(server, channel->securityToken.channelId);
             Service_CloseSecureChannel(server, channel->securityToken.channelId);
@@ -352,11 +363,12 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     if(!requestType) {
     if(!requestType) {
         /* The service is not supported */
         /* The service is not supported */
         if(requestTypeId.identifier.numeric==787)
         if(requestTypeId.identifier.numeric==787)
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER,
-                        "Client requested a subscription that are not supported, "
-                        "the message will be skipped");
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                        "Client requested a subscription, but those are not enabled "
+                        "in the build. The message will be skipped");
         else
         else
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Unknown request: NodeId(ns=%d, i=%d)",
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                        "Unknown request: NodeId(ns=%d, i=%d)",
                         requestTypeId.namespaceIndex, requestTypeId.identifier.numeric);
                         requestTypeId.namespaceIndex, requestTypeId.identifier.numeric);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
         return;
         return;
@@ -385,6 +397,7 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
         UA_SecureChannel_getSession(channel, &((UA_RequestHeader*)request)->authenticationToken);
         UA_SecureChannel_getSession(channel, &((UA_RequestHeader*)request)->authenticationToken);
     UA_Session anonymousSession;
     UA_Session anonymousSession;
     if(!session) {
     if(!session) {
+        /* session id 0 -> anonymous session */
         UA_Session_init(&anonymousSession);
         UA_Session_init(&anonymousSession);
         anonymousSession.channel = channel;
         anonymousSession.channel = channel;
         anonymousSession.activated = UA_TRUE;
         anonymousSession.activated = UA_TRUE;
@@ -393,14 +406,16 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
 
 
     /* Test if the session is valid */
     /* Test if the session is valid */
     if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) {
     if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) {
-        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service with a non-activated session");
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                    "Client tries to call a service with a non-activated session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         return;
         return;
     }
     }
 #ifndef UA_ENABLE_NONSTANDARD_STATELESS
 #ifndef UA_ENABLE_NONSTANDARD_STATELESS
     if(session == &anonymousSession &&
     if(session == &anonymousSession &&
        requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) {
        requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) {
-        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service without a session");
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                    "Client tries to call a service without a session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
         return;
         return;
     }
     }
@@ -457,7 +472,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
     UA_TcpMessageHeader tcpMessageHeader;
     UA_TcpMessageHeader tcpMessageHeader;
     do {
     do {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader)) {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader)) {
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK, "Decoding of message header failed");
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK, "Decoding of message header failed");
             connection->close(connection);
             connection->close(connection);
             break;
             break;
         }
         }
@@ -484,13 +499,13 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             connection->close(connection);
             connection->close(connection);
             return;
             return;
         default:
         default:
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
                         "Unknown request type on Connection %i", connection->sockfd);
                         "Unknown request type on Connection %i", connection->sockfd);
         }
         }
 
 
         UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
         UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
         if(pos != targetpos) {
         if(pos != targetpos) {
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
                         "Message on Connection %i was not entirely processed. "
                         "Message on Connection %i was not entirely processed. "
                         "Arrived at position %i, skip after the announced length to position %i",
                         "Arrived at position %i, skip after the announced length to position %i",
                         connection->sockfd, pos, targetpos);
                         connection->sockfd, pos, targetpos);

+ 17 - 21
src/server/ua_server_internal.h

@@ -12,7 +12,6 @@
 #include "ua_subscription_manager.h"
 #include "ua_subscription_manager.h"
 #endif
 #endif
 
 
-#define PRODUCT_URI "http://open62541.org"
 #define ANONYMOUS_POLICY "open62541-anonymous-policy"
 #define ANONYMOUS_POLICY "open62541-anonymous-policy"
 #define USERNAME_POLICY "open62541-username-policy"
 #define USERNAME_POLICY "open62541-username-policy"
 
 
@@ -26,24 +25,24 @@ typedef struct UA_ExternalNamespace {
 } UA_ExternalNamespace;
 } UA_ExternalNamespace;
 #endif
 #endif
 
 
-struct UA_Server {
-    /* Config */
-    UA_ServerConfig config;
-    UA_Logger logger;
+#ifdef UA_ENABLE_MULTITHREADING
+typedef struct {
+    UA_Server *server;
+    pthread_t thr;
+    UA_UInt32 counter;
+    volatile UA_Boolean running;
+    char padding[64 - sizeof(void*) - sizeof(pthread_t) -
+                 sizeof(UA_UInt32) - sizeof(UA_Boolean)]; // separate cache lines
+} UA_Worker;
+#endif
 
 
+struct UA_Server {
     /* Meta */
     /* Meta */
     UA_DateTime startTime;
     UA_DateTime startTime;
-    UA_DateTime buildDate;
-    UA_ApplicationDescription description;
     size_t endpointDescriptionsSize;
     size_t endpointDescriptionsSize;
     UA_EndpointDescription *endpointDescriptions;
     UA_EndpointDescription *endpointDescriptions;
 
 
-    /* Communication */
-    size_t networkLayersSize;
-    UA_ServerNetworkLayer **networkLayers;
-
     /* Security */
     /* Security */
-    UA_ByteString serverCertificate;
     UA_SecureChannelManager secureChannelManager;
     UA_SecureChannelManager secureChannelManager;
     UA_SessionManager sessionManager;
     UA_SessionManager sessionManager;
 
 
@@ -63,20 +62,17 @@ struct UA_Server {
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
     /* Dispatch queue head for the worker threads (the tail should not be in the same cache line) */
     /* Dispatch queue head for the worker threads (the tail should not be in the same cache line) */
 	struct cds_wfcq_head dispatchQueue_head;
 	struct cds_wfcq_head dispatchQueue_head;
-
-    UA_Boolean *running;
-    UA_UInt16 nThreads;
-    UA_UInt32 **workerCounters;
-    pthread_t *thr;
-
+    UA_Worker *workers; /* there are nThread workers in a running server */
     struct cds_lfs_stack mainLoopJobs; /* Work that shall be executed only in the main loop and not
     struct cds_lfs_stack mainLoopJobs; /* Work that shall be executed only in the main loop and not
                                           by worker threads */
                                           by worker threads */
     struct DelayedJobs *delayedJobs;
     struct DelayedJobs *delayedJobs;
-
     pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */
     pthread_cond_t dispatchQueue_condition; /* so the workers don't spin if the queue is empty */
-    /* Dispatch queue tail for the worker threads */
-	struct cds_wfcq_tail dispatchQueue_tail;
+	struct cds_wfcq_tail dispatchQueue_tail; /* Dispatch queue tail for the worker threads */
 #endif
 #endif
+
+    /* Config is the last element so that MSVC allows the usernamePasswordLogins
+       field with zero-sized array */
+    UA_ServerConfig config;
 };
 };
 
 
 /* The node is assumed to be "finished", i.e. no instantiation from inheritance is necessary */
 /* The node is assumed to be "finished", i.e. no instantiation from inheritance is necessary */

+ 131 - 150
src/server/ua_server_worker.c

@@ -1,11 +1,6 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_server_internal.h"
 #include "ua_server_internal.h"
 
 
-#if defined(__APPLE__) || defined(__MACH__)
-#include <mach/clock.h>
-#include <mach/mach.h>
-#endif
-
 /**
 /**
  * There are four types of job execution:
  * There are four types of job execution:
  *
  *
@@ -42,13 +37,10 @@
 #define MAXTIMEOUT 50000 // max timeout in microsec until the next main loop iteration
 #define MAXTIMEOUT 50000 // max timeout in microsec until the next main loop iteration
 #define BATCHSIZE 20 // max number of jobs that are dispatched at once to workers
 #define BATCHSIZE 20 // max number of jobs that are dispatched at once to workers
 
 
-/**
- * server:		UA server context
- * jobs: 		pointer to array of jobs or NULL if jobsSize == -1
- * jobsSize: 	nr. of valid jobs or -1
-*/
-static void processJobs(UA_Server *server, UA_Job *jobs, UA_Int32 jobsSize) {
-    for (UA_Int32 i = 0; i < jobsSize; i++) {
+static void processJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
+    UA_ASSERT_RCU_UNLOCKED();
+    UA_RCU_LOCK();
+    for(size_t i = 0; i < jobsSize; i++) {
         UA_Job *job = &jobs[i];
         UA_Job *job = &jobs[i];
         switch(job->type) {
         switch(job->type) {
         case UA_JOBTYPE_NOTHING:
         case UA_JOBTYPE_NOTHING:
@@ -72,10 +64,12 @@ static void processJobs(UA_Server *server, UA_Job *jobs, UA_Int32 jobsSize) {
             job->job.methodCall.method(server, job->job.methodCall.data);
             job->job.methodCall.method(server, job->job.methodCall.data);
             break;
             break;
         default:
         default:
-            UA_LOG_WARNING(server->logger, UA_LOGCATEGORY_SERVER, "Trying to execute a job of unknown type");
+            UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
+                           "Trying to execute a job of unknown type");
             break;
             break;
         }
         }
     }
     }
+    UA_RCU_UNLOCK();
 }
 }
 
 
 /*******************************/
 /*******************************/
@@ -96,8 +90,44 @@ struct DispatchJobsList {
     UA_Job *jobs;
     UA_Job *jobs;
 };
 };
 
 
-/** Dispatch jobs to workers. Slices the job array up if it contains more than BATCHSIZE items. The jobs
-    array is freed in the worker threads. */
+static void * workerLoop(UA_Worker *worker) {
+    UA_Server *server = worker->server;
+    UA_UInt32 *counter = &worker->counter;
+    volatile UA_Boolean *running = &worker->running;
+    
+    /* Initialize the (thread local) random seed with the ram address of worker */
+    UA_random_seed((uintptr_t)worker);
+   	rcu_register_thread();
+
+    pthread_mutex_t mutex; // required for the condition variable
+    pthread_mutex_init(&mutex,0);
+    pthread_mutex_lock(&mutex);
+
+    while(*running) {
+        struct DispatchJobsList *wln = (struct DispatchJobsList*)
+            cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
+        if(!wln) {
+            uatomic_inc(counter);
+            /* sleep until a work arrives (and wakes up all worker threads) */
+            pthread_cond_wait(&server->dispatchQueue_condition, &mutex);
+            continue;
+        }
+        processJobs(server, wln->jobs, wln->jobsSize);
+        UA_free(wln->jobs);
+        UA_free(wln);
+        uatomic_inc(counter);
+    }
+
+    pthread_mutex_unlock(&mutex);
+    pthread_mutex_destroy(&mutex);
+    UA_ASSERT_RCU_UNLOCKED();
+    rcu_barrier(); // wait for all scheduled call_rcu work to complete
+   	rcu_unregister_thread();
+    return NULL;
+}
+
+/** Dispatch jobs to workers. Slices the job array up if it contains more than
+    BATCHSIZE items. The jobs array is freed in the worker threads. */
 static void dispatchJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
 static void dispatchJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
     size_t startIndex = jobsSize; // start at the end
     size_t startIndex = jobsSize; // start at the end
     while(jobsSize > 0) {
     while(jobsSize > 0) {
@@ -121,67 +151,8 @@ static void dispatchJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
     }
     }
 }
 }
 
 
-// throwaway struct to bring data into the worker threads
-struct workerStartData {
-    UA_Server *server;
-    UA_UInt32 **workerCounter;
-};
-
-/** Waits until jobs arrive in the dispatch queue and processes them. */
-static void * workerLoop(struct workerStartData *startInfo) {
-    /* Initialized the (thread local) random seed */
-    UA_random_seed((uintptr_t)startInfo);
-
-   	rcu_register_thread();
-    UA_UInt32 *c = UA_malloc(sizeof(UA_UInt32));
-    uatomic_set(c, 0);
-    *startInfo->workerCounter = c;
-    UA_Server *server = startInfo->server;
-    UA_free(startInfo);
-
-    pthread_mutex_t mutex; // required for the condition variable
-    pthread_mutex_init(&mutex,0);
-    pthread_mutex_lock(&mutex);
-    struct timespec to;
-
-    while(*server->running) {
-        struct DispatchJobsList *wln = (struct DispatchJobsList*)
-            cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
-        if(wln) {
-            UA_RCU_LOCK();
-            processJobs(server, wln->jobs, wln->jobsSize);
-            UA_free(wln->jobs);
-            UA_free(wln);
-            UA_RCU_UNLOCK();
-        } else {
-            /* sleep until a work arrives (and wakes up all worker threads) */
-            #if defined(__APPLE__) || defined(__MACH__) // OS X does not have clock_gettime, use clock_get_time
-              clock_serv_t cclock;
-              mach_timespec_t mts;
-              host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
-              clock_get_time(cclock, &mts);
-              mach_port_deallocate(mach_task_self(), cclock);
-              to.tv_sec = mts.tv_sec;
-              to.tv_nsec = mts.tv_nsec;
-            #else
-              clock_gettime(CLOCK_REALTIME, &to);
-            #endif
-            to.tv_sec += 2;
-            pthread_cond_timedwait(&server->dispatchQueue_condition, &mutex, &to);
-        }
-        uatomic_inc(c); // increase the workerCounter;
-    }
-    pthread_mutex_unlock(&mutex);
-    pthread_mutex_destroy(&mutex);
-
-    rcu_barrier(); // wait for all scheduled call_rcu work to complete
-   	rcu_unregister_thread();
-
-    /* we need to return _something_ for pthreads */
-    return NULL;
-}
-
-static void emptyDispatchQueue(UA_Server *server) {
+static void
+emptyDispatchQueue(UA_Server *server) {
     while(!cds_wfcq_empty(&server->dispatchQueue_head, &server->dispatchQueue_tail)) {
     while(!cds_wfcq_empty(&server->dispatchQueue_head, &server->dispatchQueue_tail)) {
         struct DispatchJobsList *wln = (struct DispatchJobsList*)
         struct DispatchJobsList *wln = (struct DispatchJobsList*)
             cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
             cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
@@ -332,7 +303,8 @@ static UA_UInt16 processRepeatedJobs(UA_Server *server) {
         // copy the entry and insert at the new location
         // copy the entry and insert at the new location
         UA_Job *jobsCopy = UA_malloc(sizeof(UA_Job) * tw->jobsSize);
         UA_Job *jobsCopy = UA_malloc(sizeof(UA_Job) * tw->jobsSize);
         if(!jobsCopy) {
         if(!jobsCopy) {
-            UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Not enough memory to dispatch delayed jobs");
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Not enough memory to dispatch delayed jobs");
             break;
             break;
         }
         }
         for(size_t i=0;i<tw->jobsSize;i++)
         for(size_t i=0;i<tw->jobsSize;i++)
@@ -366,9 +338,9 @@ static UA_UInt16 processRepeatedJobs(UA_Server *server) {
     // check if the next repeated job is sooner than the usual timeout
     // check if the next repeated job is sooner than the usual timeout
     // calc in 32 bit must be ok
     // calc in 32 bit must be ok
     struct RepeatedJobs *first = LIST_FIRST(&server->repeatedJobs);
     struct RepeatedJobs *first = LIST_FIRST(&server->repeatedJobs);
-    UA_UInt32 timeout = MAXTIMEOUT;
+    UA_UInt16 timeout = MAXTIMEOUT;
     if(first) {
     if(first) {
-        timeout = (UA_UInt32)((first->nextTime - current) / 10);
+        timeout = (UA_UInt16)((first->nextTime - current) / 10);
         if(timeout > MAXTIMEOUT)
         if(timeout > MAXTIMEOUT)
             return MAXTIMEOUT;
             return MAXTIMEOUT;
     }
     }
@@ -442,9 +414,9 @@ struct DelayedJobs {
 
 
 /* Dispatched as an ordinary job when the DelayedJobs list is full */
 /* Dispatched as an ordinary job when the DelayedJobs list is full */
 static void getCounters(UA_Server *server, struct DelayedJobs *delayed) {
 static void getCounters(UA_Server *server, struct DelayedJobs *delayed) {
-    UA_UInt32 *counters = UA_malloc(server->nThreads * sizeof(UA_UInt32));
-    for(UA_UInt16 i = 0;i<server->nThreads;i++)
-        counters[i] = *server->workerCounters[i];
+    UA_UInt32 *counters = UA_malloc(server->config.nThreads * sizeof(UA_UInt32));
+    for(UA_UInt16 i = 0; i < server->config.nThreads; i++)
+        counters[i] = server->workers[i].counter;
     delayed->workerCounters = counters;
     delayed->workerCounters = counters;
 }
 }
 
 
@@ -457,7 +429,8 @@ static void addDelayedJob(UA_Server *server, UA_Job *job) {
         /* create a new DelayedJobs and add it to the linked list */
         /* create a new DelayedJobs and add it to the linked list */
         dj = UA_malloc(sizeof(struct DelayedJobs));
         dj = UA_malloc(sizeof(struct DelayedJobs));
         if(!dj) {
         if(!dj) {
-            UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Not enough memory to add a delayed job");
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Not enough memory to add a delayed job");
             return;
             return;
         }
         }
         dj->jobsCount = 0;
         dj->jobsCount = 0;
@@ -509,8 +482,8 @@ static void dispatchDelayedJobs(UA_Server *server, void *data /* not used, but n
             continue;
             continue;
         }
         }
         UA_Boolean allMoved = UA_TRUE;
         UA_Boolean allMoved = UA_TRUE;
-        for(UA_UInt16 i=0;i<server->nThreads;i++) {
-            if(dw->workerCounters[i] == *server->workerCounters[i]) {
+        for(size_t i = 0; i < server->config.nThreads; i++) {
+            if(dw->workerCounters[i] == server->workers[i].counter) {
                 allMoved = UA_FALSE;
                 allMoved = UA_FALSE;
                 break;
                 break;
             }
             }
@@ -521,6 +494,12 @@ static void dispatchDelayedJobs(UA_Server *server, void *data /* not used, but n
         dw = dw->next;
         dw = dw->next;
     }
     }
 
 
+#if (__GNUC__ <= 4 && __GNUC_MINOR__ <= 6)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wextra"
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#pragma GCC diagnostic ignored "-Wunused-value"
+#endif
     /* process and free all delayed jobs from here on */
     /* process and free all delayed jobs from here on */
     while(dw) {
     while(dw) {
         processJobs(server, dw->jobs, dw->jobsCount);
         processJobs(server, dw->jobs, dw->jobsCount);
@@ -529,6 +508,10 @@ static void dispatchDelayedJobs(UA_Server *server, void *data /* not used, but n
         UA_free(dw->workerCounters);
         UA_free(dw->workerCounters);
         dw = next;
         dw = next;
     }
     }
+#if (__GNUC__ <= 4 && __GNUC_MINOR__ <= 6)
+#pragma GCC diagnostic pop
+#endif
+
 }
 }
 
 
 #endif
 #endif
@@ -554,70 +537,71 @@ static void processMainLoopJobs(UA_Server *server) {
 }
 }
 #endif
 #endif
 
 
-UA_StatusCode UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
-UA_StatusCode result = UA_STATUSCODE_GOOD;
-
+UA_StatusCode UA_Server_run_startup(UA_Server *server) {
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
-    /* Prepare the worker threads */
-    server->running = running; // the threads need to access the variable
-    server->nThreads = nThreads;
+    /* Spin up the worker threads */
+    UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                "Spinning up %u worker thread(s)", server->config.nThreads);
     pthread_cond_init(&server->dispatchQueue_condition, 0);
     pthread_cond_init(&server->dispatchQueue_condition, 0);
-    server->thr = UA_malloc(nThreads * sizeof(pthread_t));
-    server->workerCounters = UA_malloc(nThreads * sizeof(UA_UInt32 *));
-    for(UA_UInt32 i=0;i<nThreads;i++) {
-        struct workerStartData *startData = UA_malloc(sizeof(struct workerStartData));
-        startData->server = server;
-        startData->workerCounter = &server->workerCounters[i];
-        pthread_create(&server->thr[i], NULL, (void* (*)(void*))workerLoop, startData);
+    server->workers = UA_malloc(server->config.nThreads * sizeof(UA_Worker));
+    if(!server->workers)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    for(size_t i = 0; i < server->config.nThreads; i++) {
+        UA_Worker *worker = &server->workers[i];
+        worker->server = server;
+        worker->counter = 0;
+        worker->running = true;
+        pthread_create(&worker->thr, NULL, (void* (*)(void*))workerLoop, worker);
     }
     }
 
 
-    /* try to execute the delayed callbacks every 10 sec */
+    /* Try to execute delayed callbacks every 10 sec */
     UA_Job processDelayed = {.type = UA_JOBTYPE_METHODCALL,
     UA_Job processDelayed = {.type = UA_JOBTYPE_METHODCALL,
                              .job.methodCall = {.method = dispatchDelayedJobs, .data = NULL} };
                              .job.methodCall = {.method = dispatchDelayedJobs, .data = NULL} };
     UA_Server_addRepeatedJob(server, processDelayed, 10000, NULL);
     UA_Server_addRepeatedJob(server, processDelayed, 10000, NULL);
 #endif
 #endif
 
 
     /* Start the networklayers */
     /* Start the networklayers */
-    for(size_t i = 0; i < server->networkLayersSize; i++)
-        result |= server->networkLayers[i]->start(server->networkLayers[i], server->logger);
+    UA_StatusCode result = UA_STATUSCODE_GOOD;
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
+        result |= nl->start(nl, server->config.logger);
+        for(size_t j = 0; j < server->endpointDescriptionsSize; j++) {
+            UA_String_copy(&nl->discoveryUrl, &server->endpointDescriptions[j].endpointUrl);
+        }
+    }
 
 
     return result;
     return result;
 }
 }
 
 
-UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
+UA_StatusCode UA_Server_run_iterate(UA_Server *server) {
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
-    /* Run Work in the main loop */
-    processMainLoopJobs(server);
+    processMainLoopJobs(server); /* Run work assigned for the main thread */
 #endif
 #endif
-    /* Process repeated work */
-    UA_UInt16 timeout = processRepeatedJobs(server);
+    UA_UInt16 timeout = processRepeatedJobs(server); /* Process repeated work */
 
 
     /* Get work from the networklayer */
     /* Get work from the networklayer */
-    for(size_t i = 0; i < server->networkLayersSize; i++) {
-        UA_ServerNetworkLayer *nl = server->networkLayers[i];
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
         UA_Job *jobs;
         UA_Job *jobs;
-        UA_Int32 jobsSize;
-        if(*running) {
-            if(i == server->networkLayersSize-1)
-                jobsSize = nl->getJobs(nl, &jobs, timeout);
-            else
-                jobsSize = nl->getJobs(nl, &jobs, 0);
-        } else
-            jobsSize = server->networkLayers[i]->stop(nl, &jobs);
+        size_t jobsSize;
+        if(i == server->config.networkLayersSize-1)
+            /* only the last networklayer waits on the tieout */
+            jobsSize = nl->getJobs(nl, &jobs, timeout);
+        else
+            jobsSize = nl->getJobs(nl, &jobs, 0);
 
 
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
         /* Filter out delayed work */
         /* Filter out delayed work */
-        for(UA_Int32 k=0;k<jobsSize;k++) {
+        for(size_t k = 0; k < jobsSize; k++) {
             if(jobs[k].type != UA_JOBTYPE_METHODCALL_DELAYED)
             if(jobs[k].type != UA_JOBTYPE_METHODCALL_DELAYED)
                 continue;
                 continue;
             addDelayedJob(server, &jobs[k]);
             addDelayedJob(server, &jobs[k]);
             jobs[k].type = UA_JOBTYPE_NOTHING;
             jobs[k].type = UA_JOBTYPE_NOTHING;
         }
         }
 
 
-        /* Dispatch work to the worker threads */
-        dispatchJobs(server, jobs, jobsSize);
+        dispatchJobs(server, jobs, jobsSize); /* Dispatch work to worker threads */
 
 
-        /* Trigger sleeping worker threads */
+        /* Wake up worker threads */
         if(jobsSize > 0)
         if(jobsSize > 0)
             pthread_cond_broadcast(&server->dispatchQueue_condition);
             pthread_cond_broadcast(&server->dispatchQueue_condition);
 #else
 #else
@@ -626,47 +610,44 @@ UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
             UA_free(jobs);
             UA_free(jobs);
 #endif
 #endif
     }
     }
+
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_Server_run_shutdown(UA_Server *server, UA_UInt16 nThreads){
-    UA_Job *stopJobs;
-    for(size_t i = 0; i < server->networkLayersSize; i++) {
-        size_t stopJobsSize = server->networkLayers[i]->stop(server->networkLayers[i], &stopJobs);
+UA_StatusCode UA_Server_run_shutdown(UA_Server *server) {
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
+        UA_Job *stopJobs;
+        size_t stopJobsSize = nl->stop(nl, &stopJobs);
         processJobs(server, stopJobs, stopJobsSize);
         processJobs(server, stopJobs, stopJobsSize);
         UA_free(stopJobs);
         UA_free(stopJobs);
     }
     }
+
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
+    UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                "Shutting down %u worker thread(s)", server->config.nThreads);
     /* Wait for all worker threads to finish */
     /* Wait for all worker threads to finish */
-    for(UA_UInt32 i=0;i<nThreads;i++) {
-        pthread_join(server->thr[i], NULL);
-        UA_free(server->workerCounters[i]);
-    }
-    UA_free(server->workerCounters);
-    UA_free(server->thr);
-
-    /* Manually finish the work still enqueued */
+    for(size_t i = 0; i < server->config.nThreads; i++)
+        server->workers[i].running = false;
+    pthread_cond_broadcast(&server->dispatchQueue_condition);
+    for(size_t i = 0; i < server->config.nThreads; i++)
+        pthread_join(server->workers[i].thr, NULL);
+    UA_free(server->workers);
+
+    /* Manually finish the work still enqueued.
+       This especially contains delayed frees */
     emptyDispatchQueue(server);
     emptyDispatchQueue(server);
-
-    /* Process the remaining delayed work */
-    struct DelayedJobs *dw = server->delayedJobs;
-    while(dw) {
-        processJobs(server, dw->jobs, dw->jobsCount);
-        struct DelayedJobs *next = dw->next;
-        UA_free(dw->workerCounters);
-        UA_free(dw);
-        dw = next;
-    }
+    UA_ASSERT_RCU_UNLOCKED();
+    rcu_barrier(); // wait for all scheduled call_rcu work to complete
 #endif
 #endif
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
-    if(UA_STATUSCODE_GOOD == UA_Server_run_startup(server, nThreads, running)){
-        while(*running) {
-            UA_Server_run_mainloop(server, running);
-        }
-    }
-    UA_Server_run_shutdown(server, nThreads);
-    return UA_STATUSCODE_GOOD;
+UA_StatusCode UA_Server_run(UA_Server *server, volatile UA_Boolean *running) {
+    UA_StatusCode retval = UA_Server_run_startup(server);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    while(*running)
+            UA_Server_run_iterate(server);
+    return UA_Server_run_shutdown(server);
 }
 }

+ 2 - 2
src/server/ua_services.h

@@ -59,7 +59,7 @@ void Service_OpenSecureChannel(UA_Server *server, UA_Connection *connection,
                                UA_OpenSecureChannelResponse *response);
                                UA_OpenSecureChannelResponse *response);
 
 
 /** Used to terminate a SecureChannel. */
 /** Used to terminate a SecureChannel. */
-void Service_CloseSecureChannel(UA_Server *server, UA_Int32 channelId);
+void Service_CloseSecureChannel(UA_Server *server, UA_UInt32 channelId);
 
 
 /** @} */
 /** @} */
 
 
@@ -116,7 +116,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session,
                       const UA_AddNodesRequest *request,
                       const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response);
                       UA_AddNodesResponse *response);
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result);
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback);
 
 
 /** Used to add one or more References to one or more Nodes. */
 /** Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session,
 void Service_AddReferences(UA_Server *server, UA_Session *session,

+ 65 - 60
src/server/ua_services_attribute.c

@@ -9,48 +9,51 @@
 /* Read Attribute */
 /* Read Attribute */
 /******************/
 /******************/
 
 
-static size_t readNumber(UA_Byte *buf, UA_Int32 buflen, UA_UInt32 *number) {
+static size_t
+readNumber(UA_Byte *buf, size_t buflen, UA_UInt32 *number) {
     UA_UInt32 n = 0;
     UA_UInt32 n = 0;
     size_t progress = 0;
     size_t progress = 0;
     /* read numbers until the end or a non-number character appears */
     /* read numbers until the end or a non-number character appears */
     UA_Byte c;
     UA_Byte c;
-    while((UA_Int32)progress < buflen) {
+    while(progress < buflen) {
         c = buf[progress];
         c = buf[progress];
         if('0' > c || '9' < c)
         if('0' > c || '9' < c)
             break;
             break;
-        n = (n*10) + (c-'0');
+        n = (n*10) + (UA_UInt32)(c-'0');
         progress++;
         progress++;
     }
     }
     *number = n;
     *number = n;
     return progress;
     return progress;
 }
 }
 
 
-static size_t readDimension(UA_Byte *buf, UA_Int32 buflen, struct UA_NumericRangeDimension *dim) {
+static size_t
+readDimension(UA_Byte *buf, size_t buflen, struct UA_NumericRangeDimension *dim) {
     size_t progress = readNumber(buf, buflen, &dim->min);
     size_t progress = readNumber(buf, buflen, &dim->min);
     if(progress == 0)
     if(progress == 0)
         return 0;
         return 0;
-    if(buflen <= (UA_Int32)progress || buf[progress] != ':') {
+    if(buflen <= progress || buf[progress] != ':') {
         dim->max = dim->min;
         dim->max = dim->min;
         return progress;
         return progress;
     }
     }
-    size_t progress2 = readNumber(&buf[progress+1], buflen - (progress + 1), &dim->max);
+    progress++;
+    size_t progress2 = readNumber(&buf[progress], buflen - progress, &dim->max);
     if(progress2 == 0)
     if(progress2 == 0)
         return 0;
         return 0;
-    return progress + progress2 + 1;
+    return progress + progress2;
 }
 }
 
 
 #ifndef UA_BUILD_UNIT_TESTS
 #ifndef UA_BUILD_UNIT_TESTS
 static
 static
 #endif
 #endif
 UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
 UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
-    UA_Int32 index = 0;
+    size_t idx = 0;
     size_t dimensionsMax = 0;
     size_t dimensionsMax = 0;
     struct UA_NumericRangeDimension *dimensions = NULL;
     struct UA_NumericRangeDimension *dimensions = NULL;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     size_t pos = 0;
     size_t pos = 0;
     do {
     do {
         /* alloc dimensions */
         /* alloc dimensions */
-        if(index >= (UA_Int32)dimensionsMax) {
+        if(idx >= dimensionsMax) {
             struct UA_NumericRangeDimension *newds;
             struct UA_NumericRangeDimension *newds;
             newds = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2));
             newds = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2));
             if(!newds) {
             if(!newds) {
@@ -62,22 +65,22 @@ UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
         }
         }
 
 
         /* read the dimension */
         /* read the dimension */
-        size_t progress = readDimension(&str->data[pos], str->length - pos, &dimensions[index]);
+        size_t progress = readDimension(&str->data[pos], str->length - pos, &dimensions[idx]);
         if(progress == 0) {
         if(progress == 0) {
             retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
             retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
             break;
             break;
         }
         }
         pos += progress;
         pos += progress;
-        index++;
+        idx++;
 
 
         /* loop into the next dimension */
         /* loop into the next dimension */
         if(pos >= str->length)
         if(pos >= str->length)
             break;
             break;
     } while(str->data[pos] == ',' && pos++);
     } while(str->data[pos] == ',' && pos++);
 
 
-    if(retval == UA_STATUSCODE_GOOD && index > 0) {
+    if(retval == UA_STATUSCODE_GOOD && idx > 0) {
         range->dimensions = dimensions;
         range->dimensions = dimensions;
-        range->dimensionsSize = index;
+        range->dimensionsSize = idx;
     } else
     } else
         UA_free(dimensions);
         UA_free(dimensions);
 
 
@@ -105,9 +108,9 @@ static void handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValu
 }
 }
 
 
 /* force cast for zero-copy reading. ensure that the variant is never written into. */
 /* force cast for zero-copy reading. ensure that the variant is never written into. */
-static void forceVariantSetScalar(UA_Variant *v, const void *p, const UA_DataType *type) {
+static void forceVariantSetScalar(UA_Variant *v, const void *p, const UA_DataType *t) {
     UA_Variant_init(v);
     UA_Variant_init(v);
-    v->type = type;
+    v->type = t;
     v->data = (void*)(uintptr_t)p;
     v->data = (void*)(uintptr_t)p;
     v->storageType = UA_VARIANT_DATA_NODELETE;
     v->storageType = UA_VARIANT_DATA_NODELETE;
 }
 }
@@ -162,10 +165,12 @@ static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataV
         /* Read from the datasource to see the data type */
         /* Read from the datasource to see the data type */
         UA_DataValue val;
         UA_DataValue val;
         UA_DataValue_init(&val);
         UA_DataValue_init(&val);
+        val.hasValue = UA_FALSE; // always assume we are not given a value by userspace
         retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, UA_FALSE, NULL, &val);
         retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, UA_FALSE, NULL, &val);
         if(retval != UA_STATUSCODE_GOOD)
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
             return retval;
-        retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
+        if (val.hasValue && val.value.type != NULL)
+          retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
         UA_DataValue_deleteMembers(&val);
         UA_DataValue_deleteMembers(&val);
     }
     }
     return retval;
     return retval;
@@ -335,7 +340,7 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
 
 
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
 void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request,
                   UA_ReadResponse *response) {
                   UA_ReadResponse *response) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing ReadRequest for Session (ns=%i,i=%i)",
                  "Processing ReadRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
     if(request->nodesToReadSize <= 0) {
     if(request->nodesToReadSize <= 0) {
@@ -433,24 +438,23 @@ UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const U
                                  UA_EditNodeCallback callback, const void *data) {
                                  UA_EditNodeCallback callback, const void *data) {
     UA_StatusCode retval;
     UA_StatusCode retval;
     do {
     do {
-        UA_MT_CONST UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
+#ifndef UA_ENABLE_MULTITHREADING
+        const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
         if(!node)
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
-#ifndef UA_ENABLE_MULTITHREADING
-        retval = callback(server, session, node, data);
+        UA_Node *editNode = (UA_Node*)(uintptr_t)node; // dirty cast. use only here.
+        retval = callback(server, session, editNode, data);
         return retval;
         return retval;
 #else
 #else
-        UA_Node *copy = UA_Node_copyAnyNodeClass(node);
+        UA_Node *copy = UA_NodeStore_getCopy(server->nodestore, nodeId);
         if(!copy)
         if(!copy)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
         retval = callback(server, session, copy, data);
         retval = callback(server, session, copy, data);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
-            UA_Node_deleteAnyNodeClass(copy);
+            UA_NodeStore_deleteNode(copy);
             return retval;
             return retval;
         }
         }
-        retval = UA_NodeStore_replace(server->nodestore, node, copy, NULL);
-        if(retval != UA_STATUSCODE_GOOD)
-            UA_Node_deleteAnyNodeClass(copy);
+        retval = UA_NodeStore_replace(server->nodestore, copy);
 #endif
 #endif
     } while(retval != UA_STATUSCODE_GOOD);
     } while(retval != UA_STATUSCODE_GOOD);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
@@ -502,17 +506,16 @@ enum type_equivalence {
     TYPE_EQUIVALENCE_OPAQUE
     TYPE_EQUIVALENCE_OPAQUE
 };
 };
 
 
-static enum type_equivalence typeEquivalence(const UA_DataType *type) {
-    if(type->membersSize != 1 || !type->members[0].namespaceZero)
+static enum type_equivalence typeEquivalence(const UA_DataType *t) {
+    if(t->membersSize != 1 || !t->members[0].namespaceZero)
         return TYPE_EQUIVALENCE_NONE;
         return TYPE_EQUIVALENCE_NONE;
-    if(type->members[0].memberTypeIndex == UA_TYPES_INT32)
+    if(t->members[0].memberTypeIndex == UA_TYPES_INT32)
         return TYPE_EQUIVALENCE_ENUM;
         return TYPE_EQUIVALENCE_ENUM;
-    if(type->members[0].memberTypeIndex == UA_TYPES_BYTE && type->members[0].isArray)
+    if(t->members[0].memberTypeIndex == UA_TYPES_BYTE && t->members[0].isArray)
         return TYPE_EQUIVALENCE_OPAQUE;
         return TYPE_EQUIVALENCE_OPAQUE;
     return TYPE_EQUIVALENCE_NONE;
     return TYPE_EQUIVALENCE_NONE;
 }
 }
 
 
-/* In the multithreaded case, node is a copy */
 static UA_StatusCode
 static UA_StatusCode
 CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
 CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
@@ -535,27 +538,29 @@ CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
     const UA_Variant *newV = &wvalue->value.value;
     const UA_Variant *newV = &wvalue->value.value;
     UA_Variant *oldV = &node->value.variant.value;
     UA_Variant *oldV = &node->value.variant.value;
     UA_Variant cast_v;
     UA_Variant cast_v;
-    if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
-        cast_v = wvalue->value.value;
-        newV = &cast_v;
-        enum type_equivalence te1 = typeEquivalence(oldV->type);
-        enum type_equivalence te2 = typeEquivalence(newV->type);
-        if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) {
-            /* An enum was sent as an int32, or an opaque type as a bytestring. This is
-               detected with the typeIndex indicated the "true" datatype. */
-            cast_v.type = oldV->type;
-        } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
-                  newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) {
-            /* a string is written to a byte array */
-            UA_ByteString *str = (UA_ByteString*) newV->data;
-            cast_v.arrayLength = str->length;
-            cast_v.data = str->data;
-            cast_v.type = &UA_TYPES[UA_TYPES_BYTE];
-        } else {
-            if(rangeptr)
-                UA_free(range.dimensions);
-            return UA_STATUSCODE_BADTYPEMISMATCH;
-        }
+    if (oldV->type != NULL) { // Don't run NodeId_equal on a NULL pointer (happens if the variable never held a variant)
+      if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
+          cast_v = wvalue->value.value;
+          newV = &cast_v;
+          enum type_equivalence te1 = typeEquivalence(oldV->type);
+          enum type_equivalence te2 = typeEquivalence(newV->type);
+          if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) {
+              /* An enum was sent as an int32, or an opaque type as a bytestring. This is
+                detected with the typeIndex indicated the "true" datatype. */
+              cast_v.type = oldV->type;
+          } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
+                    newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) {
+              /* a string is written to a byte array */
+              UA_ByteString *str = (UA_ByteString*) newV->data;
+              cast_v.arrayLength = str->length;
+              cast_v.data = str->data;
+              cast_v.type = &UA_TYPES[UA_TYPES_BYTE];
+          } else {
+              if(rangeptr)
+                  UA_free(range.dimensions);
+              return UA_STATUSCODE_BADTYPEMISMATCH;
+          }
+      }
     }
     }
     
     
     if(!rangeptr) {
     if(!rangeptr) {
@@ -579,7 +584,7 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 
 
     void *value = wvalue->value.value.data;
     void *value = wvalue->value.value.data;
     void *target = NULL;
     void *target = NULL;
-    const UA_DataType *type = NULL;
+    const UA_DataType *attr_type = NULL;
 
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
 	switch(wvalue->attributeId) {
 	switch(wvalue->attributeId) {
@@ -591,17 +596,17 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 	case UA_ATTRIBUTEID_BROWSENAME:
 	case UA_ATTRIBUTEID_BROWSENAME:
 		CHECK_DATATYPE(QUALIFIEDNAME);
 		CHECK_DATATYPE(QUALIFIEDNAME);
         target = &node->browseName;
         target = &node->browseName;
-        type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
+        attr_type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
 		break;
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
         target = &node->displayName;
         target = &node->displayName;
-        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+        attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
         target = &node->description;
         target = &node->description;
-        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+        attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
 	case UA_ATTRIBUTEID_WRITEMASK:
 		CHECK_DATATYPE(UINT32);
 		CHECK_DATATYPE(UINT32);
@@ -626,7 +631,7 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
         target = &((UA_ReferenceTypeNode*)node)->inverseName;
         target = &((UA_ReferenceTypeNode*)node)->inverseName;
-        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+        attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
@@ -679,9 +684,9 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 		break;
 	}
 	}
-    if(type) {
-        UA_deleteMembers(target, type);
-        retval = UA_copy(value, target, type);
+    if(attr_type) {
+        UA_deleteMembers(target, attr_type);
+        retval = UA_copy(value, target, attr_type);
     }
     }
     return retval;
     return retval;
 }
 }
@@ -693,7 +698,7 @@ UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, const
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
                    UA_WriteResponse *response) {
                    UA_WriteResponse *response) {
     UA_assert(server != NULL && session != NULL && request != NULL && response != NULL);
     UA_assert(server != NULL && session != NULL && request != NULL && response != NULL);
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing WriteRequest for Session (ns=%i,i=%i)",
                  "Processing WriteRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
 
 

+ 1 - 1
src/server/ua_services_call.c

@@ -44,7 +44,7 @@ satisfySignature(const UA_Variant *var, const UA_Argument *arg) {
     /* The dimension 1 is implicit in the array length */
     /* The dimension 1 is implicit in the array length */
     UA_UInt32 fakeDims;
     UA_UInt32 fakeDims;
     if(!scalar && !varDims) {
     if(!scalar && !varDims) {
-        fakeDims = var->arrayLength;
+        fakeDims = (UA_UInt32)var->arrayLength;
         varDims = &fakeDims;
         varDims = &fakeDims;
         varDimsSize = 1;
         varDimsSize = 1;
     }
     }

+ 51 - 11
src/server/ua_services_discovery.c

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

+ 118 - 121
src/server/ua_services_nodemanagement.c

@@ -16,12 +16,14 @@ UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
                           UA_AddNodesResult *result) {
                           UA_AddNodesResult *result) {
     if(node->nodeId.namespaceIndex >= server->namespacesSize) {
     if(node->nodeId.namespaceIndex >= server->namespacesSize) {
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         return;
         return;
     }
     }
 
 
     const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId);
     const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId);
     if(!parent) {
     if(!parent) {
         result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         return;
         return;
     }
     }
 
 
@@ -29,48 +31,34 @@ UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
         (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
         (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
     if(!referenceType) {
     if(!referenceType) {
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         return;
         return;
     }
     }
 
 
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         return;
         return;
     }
     }
 
 
     if(referenceType->isAbstract == UA_TRUE) {
     if(referenceType->isAbstract == UA_TRUE) {
         result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
         result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
+        UA_NodeStore_deleteNode(node);
         return;
         return;
     }
     }
 
 
     // todo: test if the referencetype is hierarchical
     // todo: test if the referencetype is hierarchical
     // todo: namespace index is assumed to be valid
     // todo: namespace index is assumed to be valid
-    UA_MT_CONST UA_Node *managed = NULL;
-    UA_NodeId tempNodeid = node->nodeId;
-    tempNodeid.namespaceIndex = 0;
-    if(UA_NodeId_isNull(&tempNodeid)) {
-        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
-            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-            return;
-        }
-        result->addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
-    } else {
-        if(UA_NodeId_copy(&node->nodeId, &result->addedNodeId) != UA_STATUSCODE_GOOD) {
-            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-            return;
-        }
-
-        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
-            result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS;
-            UA_NodeId_deleteMembers(&result->addedNodeId);
-            return;
-        }
-    }
-    /* Careful. The node is inserted. If the nodestore makes an expand, nodes change their address */
+    result->statusCode = UA_NodeStore_insert(server->nodestore, node);
+    if(result->statusCode == UA_STATUSCODE_GOOD)
+        result->statusCode = UA_NodeId_copy(&node->nodeId, &result->addedNodeId);
+    else
+        return;
     
     
     // reference back to the parent
     // reference back to the parent
     UA_AddReferencesItem item;
     UA_AddReferencesItem item;
     UA_AddReferencesItem_init(&item);
     UA_AddReferencesItem_init(&item);
-    item.sourceNodeId = managed->nodeId;
+    item.sourceNodeId = node->nodeId;
     item.referenceTypeId = *referenceTypeId;
     item.referenceTypeId = *referenceTypeId;
     item.isForward = UA_FALSE;
     item.isForward = UA_FALSE;
     item.targetNodeId.nodeId = *parentNodeId;
     item.targetNodeId.nodeId = *parentNodeId;
@@ -80,16 +68,19 @@ UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
 
 
 static UA_StatusCode
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session,
 instantiateVariableNode(UA_Server *server, UA_Session *session,
-                        const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                        const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                        UA_InstantiationCallback *instantiationCallback);
 static UA_StatusCode
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                      UA_InstantiationCallback *instantiationCallback);
 
 
 /* copy an existing variable under the given parent. then instantiate the
 /* copy an existing variable under the given parent. then instantiate the
    variable for all hastypedefinitions of the original version. */
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 static UA_StatusCode
 copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
 copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                     const UA_NodeId *referenceType, const UA_NodeId *parent) {
+                     const UA_NodeId *referenceType, const UA_NodeId *parent,
+                     UA_InstantiationCallback *instantiationCallback) {
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -127,7 +118,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     // add the new variable
     // add the new variable
     UA_AddNodesResult res;
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_VariableAttributes_deleteMembers(&attr);
     UA_VariableAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
     UA_AddNodesItem_deleteMembers(&item);
 
 
@@ -139,9 +130,12 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
             continue;
             continue;
-        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
     }
-
+    
+    if (instantiationCallback != NULL)
+      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+    
     UA_AddNodesResult_deleteMembers(&res);
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
@@ -150,13 +144,14 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
    variable for all hastypedefinitions of the original version. */
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 static UA_StatusCode
 copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
 copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                   const UA_NodeId *referenceType, const UA_NodeId *parent) {
-    const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);
+                   const UA_NodeId *referenceType, const UA_NodeId *parent, 
+                   UA_InstantiationCallback *instantiationCallback) {
+    const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);  
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(node->nodeClass != UA_NODECLASS_OBJECT)
     if(node->nodeClass != UA_NODECLASS_OBJECT)
         return UA_STATUSCODE_BADNODECLASSINVALID;
         return UA_STATUSCODE_BADNODECLASSINVALID;
-
+    
     // copy the variable attributes
     // copy the variable attributes
     UA_ObjectAttributes attr;
     UA_ObjectAttributes attr;
     UA_ObjectAttributes_init(&attr);
     UA_ObjectAttributes_init(&attr);
@@ -180,7 +175,7 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
     // add the new object
     // add the new object
     UA_AddNodesResult res;
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_ObjectAttributes_deleteMembers(&attr);
     UA_ObjectAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
     UA_AddNodesItem_deleteMembers(&item);
 
 
@@ -192,9 +187,12 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
             continue;
             continue;
-        instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+        instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
     }
-
+    
+    if (instantiationCallback != NULL)
+      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+    
     UA_AddNodesResult_deleteMembers(&res);
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
@@ -209,13 +207,14 @@ setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* n
 
 
 static UA_StatusCode
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId) {
-    const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
-    if(!type)
-        return UA_STATUSCODE_BADNODEIDINVALID;
-    if(type->nodeClass != UA_NODECLASS_OBJECTTYPE)
-        return UA_STATUSCODE_BADNODECLASSINVALID;
-
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                      UA_InstantiationCallback *instantiationCallback) {   
+    const UA_ObjectTypeNode *typenode = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
+    if(!typenode)
+      return UA_STATUSCODE_BADNODEIDINVALID;
+    if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE)
+      return UA_STATUSCODE_BADNODECLASSINVALID;
+    
     /* Add all the child nodes */
     /* Add all the child nodes */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
     UA_BrowseDescription_init(&browseChildren);
@@ -244,9 +243,9 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
             item.targetNodeClass = UA_NODECLASS_METHOD;
             item.targetNodeClass = UA_NODECLASS_METHOD;
             Service_AddReferences_single(server, session, &item);
             Service_AddReferences_single(server, session, &item);
         } else if(rd->nodeClass == UA_NODECLASS_VARIABLE)
         } else if(rd->nodeClass == UA_NODECLASS_VARIABLE)
-            copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+          copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
         else if(rd->nodeClass == UA_NODECLASS_OBJECT)
         else if(rd->nodeClass == UA_NODECLASS_OBJECT)
-            copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+          copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
     }
 
 
     /* add a hastypedefinition reference */
     /* add a hastypedefinition reference */
@@ -260,7 +259,7 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
     Service_AddReferences_single(server, session, &addref);
     Service_AddReferences_single(server, session, &addref);
 
 
     /* call the constructor */
     /* call the constructor */
-    const UA_ObjectLifecycleManagement *olm = &type->lifecycleManagement;
+    const UA_ObjectLifecycleManagement *olm = &typenode->lifecycleManagement;
     if(olm->constructor)
     if(olm->constructor)
         UA_Server_editNode(server, session, nodeId,
         UA_Server_editNode(server, session, nodeId,
                            (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId));
                            (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId));
@@ -269,13 +268,13 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
 
 
 static UA_StatusCode
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
 instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                        const UA_NodeId *typeId) {
-    const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
-    if(!type)
+    const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
+    const UA_ObjectTypeNode *typenode = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
+    if(!typenode)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
-    if(type->nodeClass != UA_NODECLASS_VARIABLETYPE)
+    if(typenode->nodeClass != UA_NODECLASS_VARIABLETYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
         return UA_STATUSCODE_BADNODECLASSINVALID;
-
+    
     /* get the references to child properties */
     /* get the references to child properties */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
     UA_BrowseDescription_init(&browseChildren);
@@ -294,7 +293,7 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     /* add the child properties */
     /* add the child properties */
     for(size_t i = 0; i < browseResult.referencesSize; i++) {
     for(size_t i = 0; i < browseResult.referencesSize; i++) {
         UA_ReferenceDescription *rd = &browseResult.references[i];
         UA_ReferenceDescription *rd = &browseResult.references[i];
-        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
     }
 
 
     /* add a hastypedefinition reference */
     /* add a hastypedefinition reference */
@@ -324,7 +323,7 @@ copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item, const UA_Node
 
 
 static UA_Node *
 static UA_Node *
 variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttributes *attr) {
 variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttributes *attr) {
-    UA_VariableNode *vnode = UA_VariableNode_new();
+    UA_VariableNode *vnode = UA_NodeStore_newVariableNode();
     if(!vnode)
     if(!vnode)
         return NULL;
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
@@ -336,7 +335,7 @@ variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttribu
     vnode->valueRank = attr->valueRank;
     vnode->valueRank = attr->valueRank;
     retval |= UA_Variant_copy(&attr->value, &vnode->value.variant.value);
     retval |= UA_Variant_copy(&attr->value, &vnode->value.variant.value);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        UA_NodeStore_deleteNode((UA_Node*)vnode);
         return NULL;
         return NULL;
     }
     }
     return (UA_Node*)vnode;
     return (UA_Node*)vnode;
@@ -344,13 +343,13 @@ variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttribu
 
 
 static UA_Node *
 static UA_Node *
 objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes *attr) {
 objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes *attr) {
-    UA_ObjectNode *onode = UA_ObjectNode_new();
+    UA_ObjectNode *onode = UA_NodeStore_newObjectNode();
     if(!onode)
     if(!onode)
         return NULL;
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)onode, item, (const UA_NodeAttributes*)attr);
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)onode, item, (const UA_NodeAttributes*)attr);
     onode->eventNotifier = attr->eventNotifier;
     onode->eventNotifier = attr->eventNotifier;
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)onode);
+        UA_NodeStore_deleteNode((UA_Node*)onode);
         return NULL;
         return NULL;
     }
     }
     return (UA_Node*)onode;
     return (UA_Node*)onode;
@@ -358,7 +357,7 @@ objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes
 
 
 static UA_Node *
 static UA_Node *
 referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) {
 referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) {
-    UA_ReferenceTypeNode *rtnode = UA_ReferenceTypeNode_new();
+    UA_ReferenceTypeNode *rtnode = UA_NodeStore_newReferenceTypeNode();
     if(!rtnode)
     if(!rtnode)
         return NULL;
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)rtnode, item, (const UA_NodeAttributes*)attr);
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)rtnode, item, (const UA_NodeAttributes*)attr);
@@ -366,7 +365,7 @@ referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceT
     rtnode->symmetric = attr->symmetric;
     rtnode->symmetric = attr->symmetric;
     retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
     retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)rtnode);
+        UA_NodeStore_deleteNode((UA_Node*)rtnode);
         return NULL;
         return NULL;
     }
     }
     return (UA_Node*)rtnode;
     return (UA_Node*)rtnode;
@@ -374,13 +373,13 @@ referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceT
 
 
 static UA_Node *
 static UA_Node *
 objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAttributes *attr) {
 objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAttributes *attr) {
-    UA_ObjectTypeNode *otnode = UA_ObjectTypeNode_new();
+    UA_ObjectTypeNode *otnode = UA_NodeStore_newObjectTypeNode();
     if(!otnode)
     if(!otnode)
         return NULL;
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)otnode, item, (const UA_NodeAttributes*)attr);
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)otnode, item, (const UA_NodeAttributes*)attr);
     otnode->isAbstract = attr->isAbstract;
     otnode->isAbstract = attr->isAbstract;
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)otnode);
+        UA_NodeStore_deleteNode((UA_Node*)otnode);
         return NULL;
         return NULL;
     }
     }
     return (UA_Node*)otnode;
     return (UA_Node*)otnode;
@@ -388,7 +387,7 @@ objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAtt
 
 
 static UA_Node *
 static UA_Node *
 variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTypeAttributes *attr) {
 variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTypeAttributes *attr) {
-    UA_VariableTypeNode *vtnode = UA_VariableTypeNode_new();
+    UA_VariableTypeNode *vtnode = UA_NodeStore_newVariableTypeNode();
     if(!vtnode)
     if(!vtnode)
         return NULL;
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)vtnode, item, (const UA_NodeAttributes*)attr);
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)vtnode, item, (const UA_NodeAttributes*)attr);
@@ -398,7 +397,7 @@ variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTyp
     // array dimensions are taken from the value
     // array dimensions are taken from the value
     vtnode->isAbstract = attr->isAbstract;
     vtnode->isAbstract = attr->isAbstract;
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)vtnode);
+        UA_NodeStore_deleteNode((UA_Node*)vtnode);
         return NULL;
         return NULL;
     }
     }
     return (UA_Node*)vtnode;
     return (UA_Node*)vtnode;
@@ -406,14 +405,14 @@ variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTyp
 
 
 static UA_Node *
 static UA_Node *
 viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *attr) {
 viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *attr) {
-    UA_ViewNode *vnode = UA_ViewNode_new();
+    UA_ViewNode *vnode = UA_NodeStore_newViewNode();
     if(!vnode)
     if(!vnode)
         return NULL;
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     vnode->containsNoLoops = attr->containsNoLoops;
     vnode->containsNoLoops = attr->containsNoLoops;
     vnode->eventNotifier = attr->eventNotifier;
     vnode->eventNotifier = attr->eventNotifier;
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        UA_NodeStore_deleteNode((UA_Node*)vnode);
         return NULL;
         return NULL;
     }
     }
     return (UA_Node*)vnode;
     return (UA_Node*)vnode;
@@ -421,20 +420,20 @@ viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *att
 
 
 static UA_Node *
 static UA_Node *
 dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttributes *attr) {
 dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttributes *attr) {
-    UA_DataTypeNode *dtnode = UA_DataTypeNode_new();
+    UA_DataTypeNode *dtnode = UA_NodeStore_newDataTypeNode();
     if(!dtnode)
     if(!dtnode)
         return NULL;
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)dtnode, item, (const UA_NodeAttributes*)attr);
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)dtnode, item, (const UA_NodeAttributes*)attr);
     dtnode->isAbstract = attr->isAbstract;
     dtnode->isAbstract = attr->isAbstract;
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)dtnode);
+        UA_NodeStore_deleteNode((UA_Node*)dtnode);
         return NULL;
         return NULL;
     }
     }
     return (UA_Node*)dtnode;
     return (UA_Node*)dtnode;
 }
 }
 
 
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result) {
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback) {
     if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
     if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
        !item->nodeAttributes.content.decoded.type) {
        !item->nodeAttributes.content.decoded.type) {
         result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
         result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -508,19 +507,21 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_Ad
     /* add it to the server */
     /* add it to the server */
     UA_Server_addExistingNode(server, session, node, &item->parentNodeId.nodeId,
     UA_Server_addExistingNode(server, session, node, &item->parentNodeId.nodeId,
                               &item->referenceTypeId, result);
                               &item->referenceTypeId, result);
-    if(result->statusCode != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass(node);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
         return;
-    }
-
+    
     /* instantiate if it has a type */
     /* instantiate if it has a type */
     if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
     if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
+        if (instantiationCallback != NULL)
+          instantiationCallback->method(result->addedNodeId, item->typeDefinition.nodeId,
+                                        instantiationCallback->handle); 
+        
         if(item->nodeClass == UA_NODECLASS_OBJECT)
         if(item->nodeClass == UA_NODECLASS_OBJECT)
             result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
             result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
-                                                       &item->typeDefinition.nodeId);
+                                                       &item->typeDefinition.nodeId, instantiationCallback);
         else if(item->nodeClass == UA_NODECLASS_VARIABLE)
         else if(item->nodeClass == UA_NODECLASS_VARIABLE)
             result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
             result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
-                                                         &item->typeDefinition.nodeId);
+                                                         &item->typeDefinition.nodeId, instantiationCallback);
     }
     }
 
 
     /* if instantiation failed, remove the node */
     /* if instantiation failed, remove the node */
@@ -574,7 +575,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
 #endif
 #endif
-            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i]);
+            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i], NULL);
     }
     }
 }
 }
 
 
@@ -608,7 +609,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
         return result.statusCode;
         return result.statusCode;
     }
     }
 
 
-    UA_VariableNode *node = UA_VariableNode_new();
+    UA_VariableNode *node = UA_NodeStore_newVariableNode();
     if(!node) {
     if(!node) {
         UA_AddNodesItem_deleteMembers(&item);
         UA_AddNodesItem_deleteMembers(&item);
         UA_VariableAttributes_deleteMembers(&attrCopy);
         UA_VariableAttributes_deleteMembers(&attrCopy);
@@ -623,15 +624,13 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     node->historizing = attr.historizing;
     node->historizing = attr.historizing;
     node->minimumSamplingInterval = attr.minimumSamplingInterval;
     node->minimumSamplingInterval = attr.minimumSamplingInterval;
     node->valueRank = attr.valueRank;
     node->valueRank = attr.valueRank;
-
+    UA_RCU_LOCK();
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
                               &item.referenceTypeId, &result);
                               &item.referenceTypeId, &result);
+    UA_RCU_UNLOCK();
     UA_AddNodesItem_deleteMembers(&item);
     UA_AddNodesItem_deleteMembers(&item);
     UA_VariableAttributes_deleteMembers(&attrCopy);
     UA_VariableAttributes_deleteMembers(&attrCopy);
 
 
-    if(result.statusCode != UA_STATUSCODE_GOOD)
-        UA_VariableNode_delete(node);
-
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
         *outNewNodeId = result.addedNodeId;
         *outNewNodeId = result.addedNodeId;
     else
     else
@@ -645,8 +644,8 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                         UA_MethodCallback method, void *handle,
                         UA_MethodCallback method, void *handle,
-                        UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
-                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments,
+                        size_t inputArgumentsSize, const UA_Argument* inputArguments, 
+                        size_t outputArgumentsSize, const UA_Argument* outputArguments,
                         UA_NodeId *outNewNodeId) {
                         UA_NodeId *outNewNodeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
     UA_AddNodesResult_init(&result);
@@ -667,7 +666,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
         return result.statusCode;
         return result.statusCode;
     }
     }
 
 
-    UA_MethodNode *node = UA_MethodNode_new();
+    UA_MethodNode *node = UA_NodeStore_newMethodNode();
     if(!node) {
     if(!node) {
         result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         UA_AddNodesItem_deleteMembers(&item);
         UA_AddNodesItem_deleteMembers(&item);
@@ -683,12 +682,12 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     UA_AddNodesItem_deleteMembers(&item);
     UA_AddNodesItem_deleteMembers(&item);
     UA_MethodAttributes_deleteMembers(&attrCopy);
     UA_MethodAttributes_deleteMembers(&attrCopy);
 
 
+    UA_RCU_LOCK();
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
                               &item.referenceTypeId, &result);
                               &item.referenceTypeId, &result);
-    if(result.statusCode != UA_STATUSCODE_GOOD) {
-        UA_MethodNode_delete(node);
+    UA_RCU_UNLOCK();
+    if(result.statusCode != UA_STATUSCODE_GOOD)
         return result.statusCode;
         return result.statusCode;
-    }
     
     
     UA_ExpandedNodeId parent;
     UA_ExpandedNodeId parent;
     UA_ExpandedNodeId_init(&parent);
     UA_ExpandedNodeId_init(&parent);
@@ -704,42 +703,38 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
      *          This is not a production feature and should be fixed on the compiler side! (@ichrispa)
      *          This is not a production feature and should be fixed on the compiler side! (@ichrispa)
      */
      */
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-    if (inputArgumentsSize >= 0) {
-      UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
-      inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-      inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
-      inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-      inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-      inputArgumentsVariableNode->valueRank = 1;
-      UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
-                              inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-      UA_AddNodesResult inputAddRes;
-      UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
-                                &parent.nodeId, &hasproperty, &inputAddRes);
-      // todo: check if adding succeeded
-      UA_AddNodesResult_deleteMembers(&inputAddRes);
-    }
+    UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
+    inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
+    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
+                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult inputAddRes;
+    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
+                              &parent.nodeId, &hasproperty, &inputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&inputAddRes);
     
     
     /* create OutputArguments */
     /* create OutputArguments */
     /* FIXME:   See comment in inputArguments */
     /* FIXME:   See comment in inputArguments */
-    if (outputArgumentsSize >= 0) {
-      UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
-      outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-      outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
-      outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-      outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-      outputArgumentsVariableNode->valueRank = 1;
-      UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
-                              outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-      UA_AddNodesResult outputAddRes;
-      UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
-                                &parent.nodeId, &hasproperty, &outputAddRes);
-      // todo: check if adding succeeded
-      UA_AddNodesResult_deleteMembers(&outputAddRes);
-    }
+    UA_VariableNode *outputArgumentsVariableNode  = UA_NodeStore_newVariableNode();
+    outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
+    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
+                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult outputAddRes;
+    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
+                              &parent.nodeId, &hasproperty, &outputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&outputAddRes);
     
     
     if(outNewNodeId)
     if(outNewNodeId)
-        *outNewNodeId = result.addedNodeId;
+        *outNewNodeId = result.addedNodeId; // don't deleteMember the result
     else
     else
         UA_AddNodesResult_deleteMembers(&result);
         UA_AddNodesResult_deleteMembers(&result);
     return result.statusCode;
     return result.statusCode;
@@ -853,7 +848,7 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 UA_StatusCode
 UA_StatusCode
 Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
 Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                            UA_Boolean deleteReferences) {
                            UA_Boolean deleteReferences) {
-    UA_MT_CONST UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(deleteReferences == UA_TRUE) {
     if(deleteReferences == UA_TRUE) {
@@ -886,15 +881,15 @@ Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_Node
         for(size_t i = 0; i < result.referencesSize; i++) {
         for(size_t i = 0; i < result.referencesSize; i++) {
             /* call the destructor */
             /* call the destructor */
             UA_ReferenceDescription *rd = &result.references[i];
             UA_ReferenceDescription *rd = &result.references[i];
-            const UA_ObjectTypeNode *type =
+            const UA_ObjectTypeNode *typenode =
                 (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId);
                 (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId);
-            if(!type)
+            if(!typenode)
                 continue;
                 continue;
-            if(type->nodeClass != UA_NODECLASS_OBJECTTYPE || !type->lifecycleManagement.destructor)
+            if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE || !typenode->lifecycleManagement.destructor)
                 continue;
                 continue;
 
 
             /* if there are several types with lifecycle management, call all the destructors */
             /* if there are several types with lifecycle management, call all the destructors */
-            type->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle);
+            typenode->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle);
         }
         }
         UA_BrowseResult_deleteMembers(&result);
         UA_BrowseResult_deleteMembers(&result);
     }
     }
@@ -929,7 +924,9 @@ static UA_StatusCode
 deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
 deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
                       const UA_DeleteReferencesItem *item) {
                       const UA_DeleteReferencesItem *item) {
     UA_Boolean edited = UA_FALSE;
     UA_Boolean edited = UA_FALSE;
-    for(UA_Int32 i = node->referencesSize - 1; i >= 0; i--) {
+    for(size_t i = node->referencesSize - 1; ; i--) {
+        if(i > node->referencesSize)
+            break; /* underflow after i == 0 */
         if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &node->references[i].targetId.nodeId))
         if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &node->references[i].targetId.nodeId))
             continue;
             continue;
         if(!UA_NodeId_equal(&item->referenceTypeId, &node->references[i].referenceTypeId))
         if(!UA_NodeId_equal(&item->referenceTypeId, &node->references[i].referenceTypeId))

+ 6 - 6
src/server/ua_services_securechannel.c

@@ -11,29 +11,29 @@ void Service_OpenSecureChannel(UA_Server *server, UA_Connection *connection,
             UA_SecureChannelManager_open(&server->secureChannelManager, connection, request, response);
             UA_SecureChannelManager_open(&server->secureChannelManager, connection, request, response);
 
 
         if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
         if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
-            UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                          "Opened SecureChannel %i on Connection %i",
                          "Opened SecureChannel %i on Connection %i",
                          response->securityToken.channelId, connection->sockfd);
                          response->securityToken.channelId, connection->sockfd);
         else
         else
-            UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                          "Opening SecureChannel on Connection %i failed", connection->sockfd);
                          "Opening SecureChannel on Connection %i failed", connection->sockfd);
     } else {
     } else {
         response->responseHeader.serviceResult =
         response->responseHeader.serviceResult =
             UA_SecureChannelManager_renew(&server->secureChannelManager, connection, request, response);
             UA_SecureChannelManager_renew(&server->secureChannelManager, connection, request, response);
 
 
         if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
         if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
-            UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                          "Renewed SecureChannel %i on Connection %i",
                          "Renewed SecureChannel %i on Connection %i",
                          response->securityToken.channelId, connection->sockfd);
                          response->securityToken.channelId, connection->sockfd);
         else
         else
-            UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+            UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                          "Renewing SecureChannel on Connection %i failed", connection->sockfd);
                          "Renewing SecureChannel on Connection %i failed", connection->sockfd);
     }
     }
 }
 }
 
 
 /* The server does not send a CloseSecureChannel response */
 /* The server does not send a CloseSecureChannel response */
-void Service_CloseSecureChannel(UA_Server *server, UA_Int32 channelId) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+void Service_CloseSecureChannel(UA_Server *server, UA_UInt32 channelId) {
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                  "Closing SecureChannel %i", channelId);
                  "Closing SecureChannel %i", channelId);
     UA_SecureChannelManager_close(&server->secureChannelManager, channelId);
     UA_SecureChannelManager_close(&server->secureChannelManager, channelId);
 }
 }

+ 13 - 13
src/server/ua_services_session.c

@@ -22,7 +22,7 @@ void Service_CreateSession(UA_Server *server, UA_Session *session,
     response->responseHeader.serviceResult =
     response->responseHeader.serviceResult =
         UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession);
         UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession);
 	if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
 	if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+        UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                      "Processing CreateSessionRequest on SecureChannel %i failed",
                      "Processing CreateSessionRequest on SecureChannel %i failed",
                      channel->securityToken.channelId);
                      channel->securityToken.channelId);
 		return;
 		return;
@@ -41,7 +41,7 @@ void Service_CreateSession(UA_Server *server, UA_Session *session,
         UA_SessionManager_removeSession(&server->sessionManager, server, &newSession->authenticationToken);
         UA_SessionManager_removeSession(&server->sessionManager, server, &newSession->authenticationToken);
          return;
          return;
     }
     }
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing CreateSessionRequest on SecureChannel %i succeeded, created Session (ns=%i,i=%i)",
                  "Processing CreateSessionRequest on SecureChannel %i succeeded, created Session (ns=%i,i=%i)",
                  channel->securityToken.channelId, response->sessionId.namespaceIndex,
                  channel->securityToken.channelId, response->sessionId.namespaceIndex,
                  response->sessionId.identifier.numeric);
                  response->sessionId.identifier.numeric);
@@ -58,14 +58,14 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
 
 
 	if(!foundSession) {
 	if(!foundSession) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
-        UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+        UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                      "Processing ActivateSessionRequest on SecureChannel %i, but no session found for the authentication token",
                      "Processing ActivateSessionRequest on SecureChannel %i, but no session found for the authentication token",
                      channel->securityToken.channelId);
                      channel->securityToken.channelId);
         return;
         return;
 	}
 	}
 
 
     if(foundSession->validTill < UA_DateTime_now()) {
     if(foundSession->validTill < UA_DateTime_now()) {
-        UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+        UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                      "Processing ActivateSessionRequest on SecureChannel %i, but the session has timed out",
                      "Processing ActivateSessionRequest on SecureChannel %i, but the session has timed out",
                      channel->securityToken.channelId);
                      channel->securityToken.channelId);
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
@@ -75,7 +75,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
     if(request->userIdentityToken.encoding < UA_EXTENSIONOBJECT_DECODED ||
     if(request->userIdentityToken.encoding < UA_EXTENSIONOBJECT_DECODED ||
        (request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] &&
        (request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] &&
         request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])) {
         request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])) {
-        UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+        UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                      "Invalided UserIdentityToken on SecureChannel %i for Session (ns=%i,i=%i)",
                      "Invalided UserIdentityToken on SecureChannel %i for Session (ns=%i,i=%i)",
                      channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                      channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                      foundSession->sessionId.identifier.numeric);
                      foundSession->sessionId.identifier.numeric);
@@ -83,7 +83,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
         return;
         return;
     }
     }
 
 
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing ActivateSessionRequest on SecureChannel %i for Session (ns=%i,i=%i)",
                  "Processing ActivateSessionRequest on SecureChannel %i for Session (ns=%i,i=%i)",
                  channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                  channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                  foundSession->sessionId.identifier.numeric);
                  foundSession->sessionId.identifier.numeric);
@@ -99,7 +99,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
     */
     */
 
 
     /* anonymous login */
     /* anonymous login */
-    if(server->config.Login_enableAnonymous &&
+    if(server->config.enableAnonymousLogin &&
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
         const UA_AnonymousIdentityToken *token = request->userIdentityToken.content.decoded.data;
         const UA_AnonymousIdentityToken *token = request->userIdentityToken.content.decoded.data;
         if(token->policyId.data && !UA_String_equal(&token->policyId, &ap)) {
         if(token->policyId.data && !UA_String_equal(&token->policyId, &ap)) {
@@ -115,7 +115,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
     }
     }
 
 
     /* username login */
     /* username login */
-    if(server->config.Login_enableUsernamePassword &&
+    if(server->config.enableUsernamePasswordLogin &&
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
         const UA_UserNameIdentityToken *token = request->userIdentityToken.content.decoded.data;
         const UA_UserNameIdentityToken *token = request->userIdentityToken.content.decoded.data;
         if(!UA_String_equal(&token->policyId, &up)) {
         if(!UA_String_equal(&token->policyId, &up)) {
@@ -128,10 +128,10 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
             return;
             return;
         }
         }
         /* ok, trying to match the username */
         /* ok, trying to match the username */
-        for(size_t i = 0; i < server->config.Login_loginsCount; ++i) {
-            UA_String user = UA_STRING(server->config.Login_usernames[i]);
-            UA_String pw = UA_STRING(server->config.Login_passwords[i]);
-            if(!UA_String_equal(&token->userName, &user) || !UA_String_equal(&token->password, &pw))
+        for(size_t i = 0; i < server->config.usernamePasswordLoginsSize; i++) {
+            UA_String *user = &server->config.usernamePasswordLogins[i].username;
+            UA_String *pw = &server->config.usernamePasswordLogins[i].password;
+            if(!UA_String_equal(&token->userName, user) || !UA_String_equal(&token->password, pw))
                 continue;
                 continue;
             /* success - activate */
             /* success - activate */
             if(foundSession->channel && foundSession->channel != channel)
             if(foundSession->channel && foundSession->channel != channel)
@@ -152,7 +152,7 @@ void
 Service_CloseSession(UA_Server *server, UA_Session *session,
 Service_CloseSession(UA_Server *server, UA_Session *session,
                      const UA_CloseSessionRequest *request,
                      const UA_CloseSessionRequest *request,
                      UA_CloseSessionResponse *response) {
                      UA_CloseSessionResponse *response) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing CloseSessionRequest for Session (ns=%i,i=%i)",
                  "Processing CloseSessionRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
     response->responseHeader.serviceResult =
     response->responseHeader.serviceResult =

+ 8 - 7
src/server/ua_services_subscription.c

@@ -25,7 +25,7 @@ void Service_CreateSubscription(UA_Server *server, UA_Session *session,
     /* set the publishing interval */
     /* set the publishing interval */
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
                                request->requestedPublishingInterval, response->revisedPublishingInterval);
                                request->requestedPublishingInterval, response->revisedPublishingInterval);
-    newSubscription->publishingInterval = (UA_DateTime)response->revisedPublishingInterval;
+    newSubscription->publishingInterval = response->revisedPublishingInterval;
     
     
     /* set the subscription lifetime (deleted when no publish requests arrive within this time) */
     /* set the subscription lifetime (deleted when no publish requests arrive within this time) */
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalLifeTimeCount,
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalLifeTimeCount,
@@ -39,7 +39,7 @@ void Service_CreateSubscription(UA_Server *server, UA_Session *session,
        nothin has happened for n publishing intervals */
        nothin has happened for n publishing intervals */
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalKeepAliveCount,
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalKeepAliveCount,
                                request->requestedMaxKeepAliveCount, response->revisedMaxKeepAliveCount);
                                request->requestedMaxKeepAliveCount, response->revisedMaxKeepAliveCount);
-    newSubscription->keepAliveCount = (UA_Int32_BoundedValue)  {
+    newSubscription->keepAliveCount = (UA_UInt32_BoundedValue)  {
         .minValue=session->subscriptionManager.globalKeepAliveCount.minValue,
         .minValue=session->subscriptionManager.globalKeepAliveCount.minValue,
         .maxValue=session->subscriptionManager.globalKeepAliveCount.maxValue,
         .maxValue=session->subscriptionManager.globalKeepAliveCount.maxValue,
         .currentValue=response->revisedMaxKeepAliveCount};
         .currentValue=response->revisedMaxKeepAliveCount};
@@ -228,9 +228,9 @@ Service_Publish(UA_Server *server, UA_Session *session,
     UA_PublishResponse_deleteMembers(&response);
     UA_PublishResponse_deleteMembers(&response);
 }
 }
 
 
-void Service_ModifySubscription(UA_Server *server, UA_Session *session,
-                                 const UA_ModifySubscriptionRequest *request,
-                                 UA_ModifySubscriptionResponse *response) {
+void
+Service_ModifySubscription(UA_Server *server, UA_Session *session, const UA_ModifySubscriptionRequest *request,
+                           UA_ModifySubscriptionResponse *response) {
     UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(&session->subscriptionManager,
     UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(&session->subscriptionManager,
                                                                    request->subscriptionId);
                                                                    request->subscriptionId);
     if(!sub) {
     if(!sub) {
@@ -240,7 +240,7 @@ void Service_ModifySubscription(UA_Server *server, UA_Session *session,
     
     
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
                                request->requestedPublishingInterval, response->revisedPublishingInterval);
                                request->requestedPublishingInterval, response->revisedPublishingInterval);
-    sub->publishingInterval = (UA_DateTime)response->revisedPublishingInterval;
+    sub->publishingInterval = response->revisedPublishingInterval;
     
     
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalLifeTimeCount,
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalLifeTimeCount,
                                request->requestedLifetimeCount, response->revisedLifetimeCount);
                                request->requestedLifetimeCount, response->revisedLifetimeCount);
@@ -251,7 +251,7 @@ void Service_ModifySubscription(UA_Server *server, UA_Session *session,
         
         
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalKeepAliveCount,
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalKeepAliveCount,
                                 request->requestedMaxKeepAliveCount, response->revisedMaxKeepAliveCount);
                                 request->requestedMaxKeepAliveCount, response->revisedMaxKeepAliveCount);
-    sub->keepAliveCount = (UA_Int32_BoundedValue)  {
+    sub->keepAliveCount = (UA_UInt32_BoundedValue)  {
         .minValue=session->subscriptionManager.globalKeepAliveCount.minValue,
         .minValue=session->subscriptionManager.globalKeepAliveCount.minValue,
         .maxValue=session->subscriptionManager.globalKeepAliveCount.maxValue,
         .maxValue=session->subscriptionManager.globalKeepAliveCount.maxValue,
         .currentValue=response->revisedMaxKeepAliveCount};
         .currentValue=response->revisedMaxKeepAliveCount};
@@ -259,6 +259,7 @@ void Service_ModifySubscription(UA_Server *server, UA_Session *session,
     sub->notificationsPerPublish = request->maxNotificationsPerPublish;
     sub->notificationsPerPublish = request->maxNotificationsPerPublish;
     sub->priority                = request->priority;
     sub->priority                = request->priority;
     
     
+    Subscription_unregisterUpdateJob(server, sub);
     Subscription_registerUpdateJob(server, sub);
     Subscription_registerUpdateJob(server, sub);
     return;
     return;
 }
 }

+ 14 - 14
src/server/ua_services_view.c

@@ -58,7 +58,7 @@ returnRelevantNodeExternal(UA_ExternalNodeStore *ens, const UA_BrowseDescription
                    indicesSize, readNodesResults, UA_FALSE, diagnosticInfos);
                    indicesSize, readNodesResults, UA_FALSE, diagnosticInfos);
 
 
     /* create and fill a dummy nodeStructure */
     /* create and fill a dummy nodeStructure */
-    UA_Node *node = (UA_Node*) UA_ObjectNode_new();
+    UA_Node *node = (UA_Node*) UA_NodeStore_newObjectNode();
     UA_NodeId_copy(&(reference->targetId.nodeId), &(node->nodeId));
     UA_NodeId_copy(&(reference->targetId.nodeId), &(node->nodeId));
     if(readNodesResults[0].status == UA_STATUSCODE_GOOD)
     if(readNodesResults[0].status == UA_STATUSCODE_GOOD)
         UA_NodeClass_copy((UA_NodeClass*)readNodesResults[0].value.data, &(node->nodeClass));
         UA_NodeClass_copy((UA_NodeClass*)readNodesResults[0].value.data, &(node->nodeClass));
@@ -77,7 +77,7 @@ returnRelevantNodeExternal(UA_ExternalNodeStore *ens, const UA_BrowseDescription
     UA_Array_delete(readNodesResults, &UA_TYPES[UA_TYPES_DATAVALUE], 6);
     UA_Array_delete(readNodesResults, &UA_TYPES[UA_TYPES_DATAVALUE], 6);
     UA_Array_delete(diagnosticInfos, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], 6);
     UA_Array_delete(diagnosticInfos, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], 6);
     if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
     if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
-        UA_ObjectNode_delete((UA_ObjectNode*)node);
+        UA_NodeStore_deleteNode(node);
         return NULL;
         return NULL;
     }
     }
     return node;
     return node;
@@ -153,10 +153,10 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
         return retval;
         return retval;
     }
     }
         
         
-    size_t index = 0; // where are we currently in the array?
+    size_t idx = 0; // where are we currently in the array?
     size_t last = 0; // where is the last element in the array?
     size_t last = 0; // where is the last element in the array?
     do {
     do {
-        node = UA_NodeStore_get(ns, &results[index]);
+        node = UA_NodeStore_get(ns, &results[idx]);
         if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
         if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
             continue;
             continue;
         for(size_t i = 0; i < node->referencesSize; i++) {
         for(size_t i = 0; i < node->referencesSize; i++) {
@@ -180,7 +180,7 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
                 break;
                 break;
             }
             }
         }
         }
-    } while(++index <= last && retval == UA_STATUSCODE_GOOD);
+    } while(++idx <= last && retval == UA_STATUSCODE_GOOD);
 
 
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Array_delete(results, last, &UA_TYPES[UA_TYPES_NODEID]);
         UA_Array_delete(results, last, &UA_TYPES[UA_TYPES_NODEID]);
@@ -270,7 +270,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
     }
     }
 
 
     /* how many references can we return at most? */
     /* how many references can we return at most? */
-    UA_UInt32 real_maxrefs = maxrefs;
+    size_t real_maxrefs = maxrefs;
     if(real_maxrefs == 0)
     if(real_maxrefs == 0)
         real_maxrefs = node->referencesSize;
         real_maxrefs = node->referencesSize;
     if(node->referencesSize <= 0)
     if(node->referencesSize <= 0)
@@ -303,7 +303,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
             referencesCount++;
             referencesCount++;
         }
         }
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
-        /* relevant_node returns a node malloced with UA_ObjectNode_new
+        /* relevant_node returns a node malloced by the nodestore.
            if it is external (there is no UA_Node_new function) */
            if it is external (there is no UA_Node_new function) */
         if(isExternal == UA_TRUE)
         if(isExternal == UA_TRUE)
         	UA_ObjectNode_delete((UA_ObjectNode*)(uintptr_t)current);
         	UA_ObjectNode_delete((UA_ObjectNode*)(uintptr_t)current);
@@ -336,7 +336,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
             removeCp(cp, session);
             removeCp(cp, session);
         } else {
         } else {
             /* update the cp and return the cp identifier */
             /* update the cp and return the cp identifier */
-            cp->continuationIndex += referencesCount;
+            cp->continuationIndex += (UA_UInt32)referencesCount;
             UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
             UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
         }
         }
     } else if(maxrefs != 0 && referencesCount >= maxrefs) {
     } else if(maxrefs != 0 && referencesCount >= maxrefs) {
@@ -348,7 +348,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
         }
         }
         UA_BrowseDescription_copy(descr, &cp->browseDescription);
         UA_BrowseDescription_copy(descr, &cp->browseDescription);
         cp->maxReferences = maxrefs;
         cp->maxReferences = maxrefs;
-        cp->continuationIndex = referencesCount;
+        cp->continuationIndex = (UA_UInt32)referencesCount;
         UA_Guid *ident = UA_Guid_new();
         UA_Guid *ident = UA_Guid_new();
         *ident = UA_Guid_random();
         *ident = UA_Guid_random();
         cp->identifier.data = (UA_Byte*)ident;
         cp->identifier.data = (UA_Byte*)ident;
@@ -363,7 +363,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
 
 
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
 void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
                     UA_BrowseResponse *response) {
                     UA_BrowseResponse *response) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing BrowseRequest for Session (ns=%i,i=%i)",
                  "Processing BrowseRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
     if(!UA_NodeId_isNull(&request->view.viewId)) {
     if(!UA_NodeId_isNull(&request->view.viewId)) {
@@ -438,7 +438,7 @@ UA_Server_browseNext_single(UA_Server *server, UA_Session *session, UA_Boolean r
 
 
 void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseNextRequest *request,
 void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseNextRequest *request,
                         UA_BrowseNextResponse *response) {
                         UA_BrowseNextResponse *response) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing BrowseNextRequest for Session (ns=%i,i=%i)",
                  "Processing BrowseNextRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
    if(request->continuationPointsSize <= 0) {
    if(request->continuationPointsSize <= 0) {
@@ -569,7 +569,7 @@ void Service_TranslateBrowsePathsToNodeIds_single(UA_Server *server, UA_Session
 void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
 void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
                                            const UA_TranslateBrowsePathsToNodeIdsRequest *request,
                                            const UA_TranslateBrowsePathsToNodeIdsRequest *request,
                                            UA_TranslateBrowsePathsToNodeIdsResponse *response) {
                                            UA_TranslateBrowsePathsToNodeIdsResponse *response) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing TranslateBrowsePathsToNodeIdsRequest for Session (ns=%i,i=%i)",
                  "Processing TranslateBrowsePathsToNodeIdsRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
 	if(request->browsePathsSize <= 0) {
 	if(request->browsePathsSize <= 0) {
@@ -622,7 +622,7 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
 
 
 void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,
 void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_RegisterNodesRequest *request,
                            UA_RegisterNodesResponse *response) {
                            UA_RegisterNodesResponse *response) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing RegisterNodesRequest for Session (ns=%i,i=%i)",
                  "Processing RegisterNodesRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
 
 
@@ -641,7 +641,7 @@ void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_Regi
 
 
 void Service_UnregisterNodes(UA_Server *server, UA_Session *session, const UA_UnregisterNodesRequest *request,
 void Service_UnregisterNodes(UA_Server *server, UA_Session *session, const UA_UnregisterNodesRequest *request,
                              UA_UnregisterNodesResponse *response) {
                              UA_UnregisterNodesResponse *response) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+    UA_LOG_DEBUG(server->config.logger, UA_LOGCATEGORY_SESSION,
                  "Processing UnRegisterNodesRequest for Session (ns=%i,i=%i)",
                  "Processing UnRegisterNodesRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
 
 

+ 4 - 4
src/server/ua_session_manager.h

@@ -13,10 +13,10 @@ typedef struct session_list_entry {
 
 
 typedef struct UA_SessionManager {
 typedef struct UA_SessionManager {
     LIST_HEAD(session_list, session_list_entry) sessions; // doubly-linked list of sessions
     LIST_HEAD(session_list, session_list_entry) sessions; // doubly-linked list of sessions
-    UA_UInt32    maxSessionCount;
-    UA_Int32     lastSessionId;
-    UA_UInt32    currentSessionCount;
-    UA_DateTime  maxSessionLifeTime;    // time in [ms]
+    UA_UInt32 maxSessionCount;
+    UA_UInt32 lastSessionId;
+    UA_UInt32 currentSessionCount;
+    UA_UInt32 maxSessionLifeTime;    // time in [ms]
 } UA_SessionManager;
 } UA_SessionManager;
 
 
 UA_StatusCode
 UA_StatusCode

+ 21 - 17
src/server/ua_subscription.c

@@ -6,7 +6,7 @@
 /* Subscription */
 /* Subscription */
 /****************/
 /****************/
 
 
-UA_Subscription *UA_Subscription_new(UA_Int32 subscriptionID) {
+UA_Subscription *UA_Subscription_new(UA_UInt32 subscriptionID) {
     UA_Subscription *new = UA_malloc(sizeof(UA_Subscription));
     UA_Subscription *new = UA_malloc(sizeof(UA_Subscription));
     if(!new)
     if(!new)
         return NULL;
         return NULL;
@@ -68,7 +68,8 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
     UA_unpublishedNotification *msg;
     UA_unpublishedNotification *msg;
     UA_UInt32 monItemsChangeT = 0, monItemsStatusT = 0, monItemsEventT = 0;
     UA_UInt32 monItemsChangeT = 0, monItemsStatusT = 0, monItemsEventT = 0;
     
     
-    if(!subscription || subscription->lastPublished + subscription->publishingInterval > UA_DateTime_now())
+    if(!subscription || subscription->lastPublished +
+       (UA_UInt32)(subscription->publishingInterval * UA_MSEC_TO_DATETIME) > UA_DateTime_now())
         return;
         return;
     
     
     // Make sure there is data to be published and establish which message types
     // Make sure there is data to be published and establish which message types
@@ -238,7 +239,8 @@ UA_StatusCode Subscription_registerUpdateJob(UA_Server *server, UA_Subscription
     
     
     /* Practically enough, the client sends a uint32 in ms, which we store as
     /* Practically enough, the client sends a uint32 in ms, which we store as
        datetime, which here is required in as uint32 in ms as the interval */
        datetime, which here is required in as uint32 in ms as the interval */
-    UA_StatusCode retval = UA_Server_addRepeatedJob(server, *sub->timedUpdateJob, sub->publishingInterval,
+    UA_StatusCode retval = UA_Server_addRepeatedJob(server, *sub->timedUpdateJob,
+                                                    (UA_UInt32)sub->publishingInterval,
                                                     &sub->timedUpdateJobGuid);
                                                     &sub->timedUpdateJobGuid);
     if(retval == UA_STATUSCODE_GOOD)
     if(retval == UA_STATUSCODE_GOOD)
         sub->timedUpdateIsRegistered = UA_TRUE;
         sub->timedUpdateIsRegistered = UA_TRUE;
@@ -280,9 +282,9 @@ void MonitoredItem_delete(UA_MonitoredItem *monitoredItem) {
     UA_free(monitoredItem);
     UA_free(monitoredItem);
 }
 }
 
 
-int MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
+UA_UInt32 MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
                                                  UA_MonitoredItem *monitoredItem) {
                                                  UA_MonitoredItem *monitoredItem) {
-    int queueSize = 0;
+    UA_UInt32 queueSize = 0;
     MonitoredItem_queuedValue *queueItem;
     MonitoredItem_queuedValue *queueItem;
   
   
     // Count instead of relying on the items currentValue
     // Count instead of relying on the items currentValue
@@ -381,11 +383,6 @@ UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, cons
                                                NULL, &sourceDataValue) != UA_STATUSCODE_GOOD)
                                                NULL, &sourceDataValue) != UA_STATUSCODE_GOOD)
                     break;
                     break;
                 UA_DataValue_copy(&sourceDataValue, dst);
                 UA_DataValue_copy(&sourceDataValue, dst);
-                if(sourceDataValue.value.data) {
-                    UA_deleteMembers(sourceDataValue.value.data, sourceDataValue.value.type);
-                    UA_free(sourceDataValue.value.data);
-                    sourceDataValue.value.data = NULL;
-                }
                 UA_DataValue_deleteMembers(&sourceDataValue);
                 UA_DataValue_deleteMembers(&sourceDataValue);
                 samplingError = UA_FALSE;
                 samplingError = UA_FALSE;
             }
             }
@@ -467,14 +464,21 @@ void MonitoredItem_QueuePushDataValue(UA_Server *server, UA_MonitoredItem *monit
     }
     }
   
   
     // encode the data to find if its different to the previous
     // encode the data to find if its different to the previous
-    newValueAsByteString.length = 512; // Todo: Hack! We should make a copy of the value, not encode it. UA_calcSizeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE]);
-    newValueAsByteString.data   = UA_malloc(newValueAsByteString.length);
-    UA_StatusCode retval = UA_encodeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE], &newValueAsByteString, &encodingOffset);
-    //FIXME: Stasik0 workaround to fix due to the absence of calcSizeBinary #496, still a better solution is needed to ensure the comparisson works for values greater than 512 bytes
-    newValueAsByteString.length = encodingOffset;
-
-    if(retval != UA_STATUSCODE_GOOD)
+    size_t binsize = UA_calcSizeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE]);
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&newValueAsByteString, binsize);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_DataValue_deleteMembers(&newvalue->value);
+        UA_free(newvalue);
+        return;
+    }
+    
+    retval = UA_encodeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE], &newValueAsByteString, &encodingOffset);
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_ByteString_deleteMembers(&newValueAsByteString);
         UA_ByteString_deleteMembers(&newValueAsByteString);
+        UA_DataValue_deleteMembers(&newvalue->value);
+        UA_free(newvalue);
+        return;
+    }
   
   
     if(!monitoredItem->lastSampledValue.data) { 
     if(!monitoredItem->lastSampledValue.data) { 
         UA_ByteString_copy(&newValueAsByteString, &monitoredItem->lastSampledValue);
         UA_ByteString_copy(&newValueAsByteString, &monitoredItem->lastSampledValue);

+ 7 - 7
src/server/ua_subscription.h

@@ -58,8 +58,8 @@ void MonitoredItem_QueuePushDataValue(UA_Server *server, UA_MonitoredItem *monit
 void MonitoredItem_ClearQueue(UA_MonitoredItem *monitoredItem);
 void MonitoredItem_ClearQueue(UA_MonitoredItem *monitoredItem);
 UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, const UA_Node *src,
 UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, const UA_Node *src,
                                                      UA_DataValue *dst);
                                                      UA_DataValue *dst);
-int MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
-                                                 UA_MonitoredItem *monitoredItem);
+UA_UInt32 MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
+                                                       UA_MonitoredItem *monitoredItem);
 
 
 /****************/
 /****************/
 /* Subscription */
 /* Subscription */
@@ -74,11 +74,11 @@ typedef struct UA_unpublishedNotification {
 typedef struct UA_Subscription {
 typedef struct UA_Subscription {
     LIST_ENTRY(UA_Subscription) listEntry;
     LIST_ENTRY(UA_Subscription) listEntry;
     UA_UInt32_BoundedValue lifeTime;
     UA_UInt32_BoundedValue lifeTime;
-    UA_Int32_BoundedValue keepAliveCount;
-    UA_DateTime publishingInterval;     // [ms] may be UA_Int32
+    UA_UInt32_BoundedValue keepAliveCount;
+    UA_Double publishingInterval;     // [ms] 
     UA_DateTime lastPublished;
     UA_DateTime lastPublished;
-    UA_Int32 subscriptionID;
-    UA_Int32 notificationsPerPublish;
+    UA_UInt32 subscriptionID;
+    UA_UInt32 notificationsPerPublish;
     UA_Boolean publishingMode;
     UA_Boolean publishingMode;
     UA_UInt32 priority;
     UA_UInt32 priority;
     UA_UInt32 sequenceNumber;
     UA_UInt32 sequenceNumber;
@@ -90,7 +90,7 @@ typedef struct UA_Subscription {
     LIST_HEAD(UA_ListOfUAMonitoredItems, UA_MonitoredItem) MonitoredItems;
     LIST_HEAD(UA_ListOfUAMonitoredItems, UA_MonitoredItem) MonitoredItems;
 } UA_Subscription;
 } UA_Subscription;
 
 
-UA_Subscription *UA_Subscription_new(UA_Int32 subscriptionID);
+UA_Subscription *UA_Subscription_new(UA_UInt32 subscriptionID);
 void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *server);
 void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *server);
 void Subscription_updateNotifications(UA_Subscription *subscription);
 void Subscription_updateNotifications(UA_Subscription *subscription);
 UA_UInt32 *Subscription_getAvailableSequenceNumbers(UA_Subscription *sub);
 UA_UInt32 *Subscription_getAvailableSequenceNumbers(UA_Subscription *sub);

+ 11 - 8
src/server/ua_subscription_manager.c

@@ -8,10 +8,10 @@ void SubscriptionManager_init(UA_Session *session) {
 
 
     /* FIXME: These init values are empirical. Maybe they should be part
     /* FIXME: These init values are empirical. Maybe they should be part
      *        of the server config? */
      *        of the server config? */
-    manager->globalPublishingInterval = (UA_Int32_BoundedValue) { .maxValue = 10000, .minValue = 0, .currentValue=0 };
+    manager->globalPublishingInterval = (UA_UInt32_BoundedValue) { .maxValue = 10000, .minValue = 0, .currentValue=0 };
     manager->globalLifeTimeCount = (UA_UInt32_BoundedValue) { .maxValue = 15000, .minValue = 0, .currentValue=0 };
     manager->globalLifeTimeCount = (UA_UInt32_BoundedValue) { .maxValue = 15000, .minValue = 0, .currentValue=0 };
     manager->globalKeepAliveCount = (UA_UInt32_BoundedValue) { .maxValue = 100, .minValue = 0, .currentValue=0 };
     manager->globalKeepAliveCount = (UA_UInt32_BoundedValue) { .maxValue = 100, .minValue = 0, .currentValue=0 };
-    manager->globalNotificationsPerPublish = (UA_Int32_BoundedValue)  { .maxValue = 1000, .minValue = 1, .currentValue=0 };
+    manager->globalNotificationsPerPublish = (UA_UInt32_BoundedValue)  { .maxValue = 1000, .minValue = 1, .currentValue=0 };
     manager->globalSamplingInterval = (UA_UInt32_BoundedValue) { .maxValue = 1000, .minValue = 5, .currentValue=0 };
     manager->globalSamplingInterval = (UA_UInt32_BoundedValue) { .maxValue = 1000, .minValue = 5, .currentValue=0 };
     manager->globalQueueSize = (UA_UInt32_BoundedValue) { .maxValue = 100, .minValue = 0, .currentValue=0 };
     manager->globalQueueSize = (UA_UInt32_BoundedValue) { .maxValue = 100, .minValue = 0, .currentValue=0 };
     LIST_INIT(&manager->serverSubscriptions);
     LIST_INIT(&manager->serverSubscriptions);
@@ -33,8 +33,8 @@ void SubscriptionManager_addSubscription(UA_SubscriptionManager *manager, UA_Sub
     LIST_INSERT_HEAD(&manager->serverSubscriptions, newSubscription, listEntry);
     LIST_INSERT_HEAD(&manager->serverSubscriptions, newSubscription, listEntry);
 }
 }
 
 
-UA_Subscription *SubscriptionManager_getSubscriptionByID(UA_SubscriptionManager *manager,
-                                                         UA_Int32 subscriptionID) {
+UA_Subscription *
+SubscriptionManager_getSubscriptionByID(UA_SubscriptionManager *manager, UA_UInt32 subscriptionID) {
     UA_Subscription *sub;
     UA_Subscription *sub;
     LIST_FOREACH(sub, &manager->serverSubscriptions, listEntry) {
     LIST_FOREACH(sub, &manager->serverSubscriptions, listEntry) {
         if(sub->subscriptionID == subscriptionID)
         if(sub->subscriptionID == subscriptionID)
@@ -43,15 +43,16 @@ UA_Subscription *SubscriptionManager_getSubscriptionByID(UA_SubscriptionManager
     return sub;
     return sub;
 }
 }
 
 
-UA_Int32 SubscriptionManager_deleteMonitoredItem(UA_SubscriptionManager *manager, UA_Int32 subscriptionID,
-                                                 UA_UInt32 monitoredItemID) {
+UA_StatusCode
+SubscriptionManager_deleteMonitoredItem(UA_SubscriptionManager *manager, UA_UInt32 subscriptionID,
+                                        UA_UInt32 monitoredItemID) {
     UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(manager, subscriptionID);
     UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(manager, subscriptionID);
     if(!sub)
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
     
     
     UA_MonitoredItem *mon, *tmp_mon;
     UA_MonitoredItem *mon, *tmp_mon;
     LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, tmp_mon) {
     LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, tmp_mon) {
-        if (mon->itemId == monitoredItemID) {
+        if(mon->itemId == monitoredItemID) {
             LIST_REMOVE(mon, listEntry);
             LIST_REMOVE(mon, listEntry);
             MonitoredItem_delete(mon);
             MonitoredItem_delete(mon);
             return UA_STATUSCODE_GOOD;
             return UA_STATUSCODE_GOOD;
@@ -60,7 +61,9 @@ UA_Int32 SubscriptionManager_deleteMonitoredItem(UA_SubscriptionManager *manager
     return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
     return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
 }
 }
 
 
-UA_Int32 SubscriptionManager_deleteSubscription(UA_Server *server, UA_SubscriptionManager *manager, UA_Int32 subscriptionID) {
+UA_StatusCode
+SubscriptionManager_deleteSubscription(UA_Server *server, UA_SubscriptionManager *manager,
+                                       UA_UInt32 subscriptionID) {
     UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(manager, subscriptionID);    
     UA_Subscription *sub = SubscriptionManager_getSubscriptionByID(manager, subscriptionID);    
     if(!sub)
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;

+ 11 - 8
src/server/ua_subscription_manager.h

@@ -8,13 +8,13 @@
 #include "ua_subscription.h"
 #include "ua_subscription.h"
 
 
 typedef struct UA_SubscriptionManager {
 typedef struct UA_SubscriptionManager {
-    UA_Int32_BoundedValue globalPublishingInterval;
+    UA_UInt32_BoundedValue globalPublishingInterval;
     UA_UInt32_BoundedValue globalLifeTimeCount;
     UA_UInt32_BoundedValue globalLifeTimeCount;
     UA_UInt32_BoundedValue globalKeepAliveCount;
     UA_UInt32_BoundedValue globalKeepAliveCount;
-    UA_Int32_BoundedValue globalNotificationsPerPublish;
+    UA_UInt32_BoundedValue globalNotificationsPerPublish;
     UA_UInt32_BoundedValue globalSamplingInterval;
     UA_UInt32_BoundedValue globalSamplingInterval;
     UA_UInt32_BoundedValue globalQueueSize;
     UA_UInt32_BoundedValue globalQueueSize;
-    UA_Int32 lastSessionID;
+    UA_UInt32 lastSessionID;
     UA_Guid lastJobGuid;
     UA_Guid lastJobGuid;
     LIST_HEAD(UA_ListOfUASubscriptions, UA_Subscription) serverSubscriptions;
     LIST_HEAD(UA_ListOfUASubscriptions, UA_Subscription) serverSubscriptions;
 } UA_SubscriptionManager;
 } UA_SubscriptionManager;
@@ -22,11 +22,14 @@ typedef struct UA_SubscriptionManager {
 void SubscriptionManager_init(UA_Session *session);
 void SubscriptionManager_init(UA_Session *session);
 void SubscriptionManager_deleteMembers(UA_Session *session, UA_Server *server);
 void SubscriptionManager_deleteMembers(UA_Session *session, UA_Server *server);
 void SubscriptionManager_addSubscription(UA_SubscriptionManager *manager, UA_Subscription *subscription);
 void SubscriptionManager_addSubscription(UA_SubscriptionManager *manager, UA_Subscription *subscription);
-UA_Subscription *SubscriptionManager_getSubscriptionByID(UA_SubscriptionManager *manager,
-                                                         UA_Int32 subscriptionID);
-UA_Int32 SubscriptionManager_deleteSubscription(UA_Server *server, UA_SubscriptionManager *manager, UA_Int32 subscriptionID);
-UA_Int32 SubscriptionManager_deleteMonitoredItem(UA_SubscriptionManager *manager, UA_Int32 subscriptionID,
-                                                 UA_UInt32 monitoredItemID);
+UA_Subscription *
+SubscriptionManager_getSubscriptionByID(UA_SubscriptionManager *manager, UA_UInt32 subscriptionID);
+UA_StatusCode
+SubscriptionManager_deleteSubscription(UA_Server *server, UA_SubscriptionManager *manager,
+                                       UA_UInt32 subscriptionID);
+UA_StatusCode
+SubscriptionManager_deleteMonitoredItem(UA_SubscriptionManager *manager, UA_UInt32 subscriptionID,
+                                        UA_UInt32 monitoredItemID);
 
 
 UA_UInt32 SubscriptionManager_getUniqueUIntID(UA_SubscriptionManager *manager);
 UA_UInt32 SubscriptionManager_getUniqueUIntID(UA_SubscriptionManager *manager);
 UA_Guid SubscriptionManager_getUniqueGUID(UA_SubscriptionManager *manager);
 UA_Guid SubscriptionManager_getUniqueGUID(UA_SubscriptionManager *manager);

+ 18 - 5
src/ua_connection.c

@@ -57,7 +57,9 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RES
     size_t pos = 0;
     size_t pos = 0;
     size_t delete_at = current->length-1; // garbled message after this point
     size_t delete_at = current->length-1; // garbled message after this point
     while(current->length - pos >= 16) {
     while(current->length - pos >= 16) {
-        UA_UInt32 msgtype = current->data[pos] + (current->data[pos+1] << 8) + (current->data[pos+2] << 16);
+        UA_UInt32 msgtype = (UA_UInt32)current->data[pos] +
+            ((UA_UInt32)current->data[pos+1] << 8) +
+            ((UA_UInt32)current->data[pos+2] << 16);
         if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
         if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
            msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
            msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
            msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
            msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
@@ -67,10 +69,10 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RES
             delete_at = pos; // throw the remaining message away
             delete_at = pos; // throw the remaining message away
             break;
             break;
         }
         }
-        UA_Int32 length = 0;
+        UA_UInt32 length = 0;
         size_t length_pos = pos + 4;
         size_t length_pos = pos + 4;
-        UA_StatusCode retval = UA_Int32_decodeBinary(current, &length_pos, &length);
-        if(retval != UA_STATUSCODE_GOOD || length < 16 || length > (UA_Int32)connection->localConf.maxMessageSize) {
+        UA_StatusCode retval = UA_UInt32_decodeBinary(current, &length_pos, &length);
+        if(retval != UA_STATUSCODE_GOOD || length < 16 || length > connection->localConf.maxMessageSize) {
             /* the message size is not allowed. throw the remaining bytestring away */
             /* the message size is not allowed. throw the remaining bytestring away */
             delete_at = pos;
             delete_at = pos;
             break;
             break;
@@ -129,6 +131,13 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RES
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
+#if (__GNUC__ <= 4 && __GNUC_MINOR__ <= 6)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wextra"
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#pragma GCC diagnostic ignored "-Wunused-value"
+#endif
+
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
     UA_SecureChannel *channel = connection->channel;
     UA_SecureChannel *channel = connection->channel;
@@ -145,7 +154,7 @@ void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
 void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel) {
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_cmpxchg(&channel->connection, NULL, connection) == NULL)
     if(uatomic_cmpxchg(&channel->connection, NULL, connection) == NULL)
-        uatomic_set(&connection->channel, channel);
+        uatomic_set((void**)&connection->channel, (void*)channel);
 #else
 #else
     if(channel->connection != NULL)
     if(channel->connection != NULL)
         return;
         return;
@@ -153,3 +162,7 @@ void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChann
     connection->channel = channel;
     connection->channel = channel;
 #endif
 #endif
 }
 }
+
+#if (__GNUC__ <= 4 && __GNUC_MINOR__ <= 6)
+#pragma GCC diagnostic pop
+#endif

+ 14 - 3
src/ua_securechannel.c

@@ -23,8 +23,8 @@ void UA_SecureChannel_deleteMembersCleanup(UA_SecureChannel *channel) {
     UA_ByteString_deleteMembers(&channel->serverNonce);
     UA_ByteString_deleteMembers(&channel->serverNonce);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
     UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
     UA_ByteString_deleteMembers(&channel->clientNonce);
     UA_ByteString_deleteMembers(&channel->clientNonce);
-    UA_ChannelSecurityToken_deleteMembers(&channel->securityToken); //FIXME: not really needed
-    UA_ChannelSecurityToken_deleteMembers(&channel->nextSecurityToken); //FIXME: not really needed
+    UA_ChannelSecurityToken_deleteMembers(&channel->securityToken);
+    UA_ChannelSecurityToken_deleteMembers(&channel->nextSecurityToken);
     UA_Connection *c = channel->connection;
     UA_Connection *c = channel->connection;
     if(c) {
     if(c) {
         UA_Connection_detachSecureChannel(c);
         UA_Connection_detachSecureChannel(c);
@@ -50,6 +50,13 @@ UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce) {
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
+#if (__GNUC__ <= 4 && __GNUC_MINOR__ <= 6)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wextra"
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#pragma GCC diagnostic ignored "-Wunused-value"
+#endif
+
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session) {
 void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *session) {
     struct SessionEntry *se = UA_malloc(sizeof(struct SessionEntry));
     struct SessionEntry *se = UA_malloc(sizeof(struct SessionEntry));
     if(!se)
     if(!se)
@@ -70,6 +77,10 @@ void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *sessi
     LIST_INSERT_HEAD(&channel->sessions, se, pointers);
     LIST_INSERT_HEAD(&channel->sessions, se, pointers);
 }
 }
 
 
+#if (__GNUC__ <= 4 && __GNUC_MINOR__ <= 6)
+#pragma GCC diagnostic pop
+#endif
+
 void UA_SecureChannel_detachSession(UA_SecureChannel *channel, UA_Session *session) {
 void UA_SecureChannel_detachSession(UA_SecureChannel *channel, UA_Session *session) {
     if(session)
     if(session)
         session->channel = NULL;
         session->channel = NULL;
@@ -143,7 +154,7 @@ UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_U
     }
     }
 
 
     /* now write the header with the size */
     /* now write the header with the size */
-    respHeader.messageHeader.messageSize = messagePos;
+    respHeader.messageHeader.messageSize = (UA_UInt32)messagePos;
 #ifndef UA_ENABLE_MULTITHREADING
 #ifndef UA_ENABLE_MULTITHREADING
     seqHeader.sequenceNumber = ++channel->sequenceNumber;
     seqHeader.sequenceNumber = ++channel->sequenceNumber;
 #else
 #else

+ 0 - 14
src/ua_session.c

@@ -2,20 +2,6 @@
 #include "ua_session.h"
 #include "ua_session.h"
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
 
 
-UA_Session anonymousSession = {
-    .clientDescription =  {.applicationUri = {0, NULL}, .productUri = {0, NULL},
-                           .applicationName = {.locale = {0, NULL}, .text = {0, NULL}},
-                           .applicationType = UA_APPLICATIONTYPE_CLIENT,
-                           .gatewayServerUri = {0, NULL}, .discoveryProfileUri = {0, NULL},
-                           .discoveryUrlsSize = 0, .discoveryUrls = NULL},
-    .sessionName = {sizeof("Anonymous Session")-1, (UA_Byte*)"Anonymous Session"},
-    .authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
-                            .identifier.numeric = 0}, 
-    .sessionId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0},
-    .maxRequestMessageSize = UA_UINT32_MAX, .maxResponseMessageSize = UA_UINT32_MAX,
-    .timeout = UA_INT64_MAX, .validTill = UA_INT64_MAX, .channel = NULL,
-    .continuationPoints = {NULL}};
-
 UA_Session adminSession = {
 UA_Session adminSession = {
     .clientDescription =  {.applicationUri = {0, NULL}, .productUri = {0, NULL},
     .clientDescription =  {.applicationUri = {0, NULL}, .productUri = {0, NULL},
                            .applicationName = {.locale = {0, NULL}, .text = {0, NULL}},
                            .applicationName = {.locale = {0, NULL}, .text = {0, NULL}},

+ 1 - 2
src/ua_session.h

@@ -22,7 +22,7 @@ struct ContinuationPointEntry {
     LIST_ENTRY(ContinuationPointEntry) pointers;
     LIST_ENTRY(ContinuationPointEntry) pointers;
     UA_ByteString        identifier;
     UA_ByteString        identifier;
     UA_BrowseDescription browseDescription;
     UA_BrowseDescription browseDescription;
-    UA_Int32            continuationIndex;
+    UA_UInt32            continuationIndex;
     UA_UInt32            maxReferences;
     UA_UInt32            maxReferences;
 };
 };
 
 
@@ -44,7 +44,6 @@ struct UA_Session {
     LIST_HEAD(ContinuationPointList, ContinuationPointEntry) continuationPoints;
     LIST_HEAD(ContinuationPointList, ContinuationPointEntry) continuationPoints;
 };
 };
 
 
-extern UA_Session anonymousSession; ///< If anonymous access is allowed, this session is used internally (Session ID: 0)
 extern UA_Session adminSession; ///< Local access to the services (for startup and maintenance) uses this Session with all possible access rights (Session ID: 1)
 extern UA_Session adminSession; ///< Local access to the services (for startup and maintenance) uses this Session with all possible access rights (Session ID: 1)
 
 
 void UA_Session_init(UA_Session *session);
 void UA_Session_init(UA_Session *session);

+ 22 - 11
src/ua_types.c

@@ -20,7 +20,7 @@ UA_EXPORT const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {
 static UA_THREAD_LOCAL pcg32_random_t UA_rng = PCG32_INITIALIZER;
 static UA_THREAD_LOCAL pcg32_random_t UA_rng = PCG32_INITIALIZER;
 
 
 UA_EXPORT void UA_random_seed(UA_UInt64 seed) {
 UA_EXPORT void UA_random_seed(UA_UInt64 seed) {
-    pcg32_srandom_r(&UA_rng, seed, UA_DateTime_now());
+    pcg32_srandom_r(&UA_rng, seed, (uint64_t)UA_DateTime_now());
 }
 }
 
 
 /*****************/
 /*****************/
@@ -79,6 +79,13 @@ UA_DateTime UA_DateTime_nowMonotonic(void) {
     UA_Double ticks2dt = UA_SEC_TO_DATETIME;
     UA_Double ticks2dt = UA_SEC_TO_DATETIME;
     ticks2dt /= freq.QuadPart;
     ticks2dt /= freq.QuadPart;
     return (UA_DateTime)(ticks.QuadPart * ticks2dt);
     return (UA_DateTime)(ticks.QuadPart * ticks2dt);
+#elif defined(__APPLE__) || defined(__MACH__) // OS X does not have clock_gettime, use clock_get_time
+    clock_serv_t cclock;
+    mach_timespec_t mts;
+    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+    clock_get_time(cclock, &mts);
+    mach_port_deallocate(mach_task_self(), cclock);
+    return (mts.tv_sec * UA_SEC_TO_DATETIME) + (mts.tv_nsec / 100);
 #else
 #else
     struct timespec ts;
     struct timespec ts;
     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
@@ -86,15 +93,15 @@ UA_DateTime UA_DateTime_nowMonotonic(void) {
 #endif
 #endif
 }
 }
 
 
-UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
+UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t) {
     /* Calculating the the milli-, micro- and nanoseconds */
     /* Calculating the the milli-, micro- and nanoseconds */
     UA_DateTimeStruct dateTimeStruct;
     UA_DateTimeStruct dateTimeStruct;
-    dateTimeStruct.nanoSec  = (UA_UInt16)((atime % 10) * 100);
-    dateTimeStruct.microSec = (UA_UInt16)((atime % 10000) / 10);
-    dateTimeStruct.milliSec = (UA_UInt16)((atime % 10000000) / 10000);
+    dateTimeStruct.nanoSec  = (UA_UInt16)((t % 10) * 100);
+    dateTimeStruct.microSec = (UA_UInt16)((t % 10000) / 10);
+    dateTimeStruct.milliSec = (UA_UInt16)((t % 10000000) / 10000);
 
 
     /* Calculating the unix time with #include <time.h> */
     /* Calculating the unix time with #include <time.h> */
-    time_t secSinceUnixEpoch = (atime - UA_DATETIME_UNIX_EPOCH) / UA_SEC_TO_DATETIME;
+    time_t secSinceUnixEpoch = (time_t)((t - UA_DATETIME_UNIX_EPOCH) / UA_SEC_TO_DATETIME);
     struct tm ts = *gmtime(&secSinceUnixEpoch);
     struct tm ts = *gmtime(&secSinceUnixEpoch);
     dateTimeStruct.sec    = (UA_UInt16)ts.tm_sec;
     dateTimeStruct.sec    = (UA_UInt16)ts.tm_sec;
     dateTimeStruct.min    = (UA_UInt16)ts.tm_min;
     dateTimeStruct.min    = (UA_UInt16)ts.tm_min;
@@ -107,18 +114,18 @@ UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
 
 
 static void printNumber(UA_UInt16 n, UA_Byte *pos, size_t digits) {
 static void printNumber(UA_UInt16 n, UA_Byte *pos, size_t digits) {
     for(size_t i = digits; i > 0; i--) {
     for(size_t i = digits; i > 0; i--) {
-        pos[i-1] = (n % 10) + '0';
+        pos[i-1] = (UA_Byte)((n % 10) + '0');
         n = n / 10;
         n = n / 10;
     }
     }
 }
 }
 
 
-UA_String UA_DateTime_toString(UA_DateTime time) {
+UA_String UA_DateTime_toString(UA_DateTime t) {
     UA_String str = UA_STRING_NULL;
     UA_String str = UA_STRING_NULL;
     // length of the string is 31 (plus \0 at the end)
     // length of the string is 31 (plus \0 at the end)
     if(!(str.data = UA_malloc(32)))
     if(!(str.data = UA_malloc(32)))
         return str;
         return str;
     str.length = 31;
     str.length = 31;
-    UA_DateTimeStruct tSt = UA_DateTime_toStruct(time);
+    UA_DateTimeStruct tSt = UA_DateTime_toStruct(t);
     printNumber(tSt.month, str.data, 2);
     printNumber(tSt.month, str.data, 2);
     str.data[2] = '/';
     str.data[2] = '/';
     printNumber(tSt.day, &str.data[3], 2);
     printNumber(tSt.day, &str.data[3], 2);
@@ -345,9 +352,13 @@ static UA_StatusCode
 processRangeDefinition(const UA_Variant *v, const UA_NumericRange range, size_t *total,
 processRangeDefinition(const UA_Variant *v, const UA_NumericRange range, size_t *total,
                        size_t *block, size_t *stride, size_t *first) {
                        size_t *block, size_t *stride, size_t *first) {
     /* Test the integrity of the source variant dimensions */
     /* Test the integrity of the source variant dimensions */
-    UA_UInt32 dims_count = 1;
+    size_t dims_count = 1;
     UA_UInt32 elements = 1;
     UA_UInt32 elements = 1;
-    UA_UInt32 arrayLength = v->arrayLength;
+#if(MAX_SIZE > 0xffffffff) /* 64bit only */
+    if(v->arrayLength > UA_UINT32_MAX)
+        return UA_STATUSCODE_BADINTERNALERROR;
+#endif
+    UA_UInt32 arrayLength = (UA_UInt32)v->arrayLength;
     const UA_UInt32 *dims = &arrayLength;
     const UA_UInt32 *dims = &arrayLength;
     if(v->arrayDimensionsSize > 0) {
     if(v->arrayDimensionsSize > 0) {
         dims_count = v->arrayDimensionsSize;
         dims_count = v->arrayDimensionsSize;

Diferenças do arquivo suprimidas por serem muito extensas
+ 624 - 386
src/ua_types_encoding_binary.c


+ 4 - 2
src/ua_types_encoding_binary.h

@@ -4,9 +4,11 @@
 #include "ua_types.h"
 #include "ua_types.h"
 
 
 UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *type, UA_ByteString *dst,
 UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *type, UA_ByteString *dst,
-                              size_t *UA_RESTRICT offset) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
+                              size_t *offset) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
 
-UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t * UA_RESTRICT offset, void *dst,
+UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst,
                               const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
                               const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
 
+size_t UA_calcSizeBinary(void *p, const UA_DataType *type);
+
 #endif /* UA_TYPES_ENCODING_BINARY_H_ */
 #endif /* UA_TYPES_ENCODING_BINARY_H_ */

+ 23 - 9
src/ua_util.h

@@ -44,6 +44,9 @@
 # endif
 # endif
 #endif
 #endif
 
 
+#define container_of(ptr, type, member) \
+    (type *)((uintptr_t)ptr - offsetof(type,member))
+
 /************************/
 /************************/
 /* Thread Local Storage */
 /* Thread Local Storage */
 /************************/
 /************************/
@@ -77,6 +80,11 @@ int gettimeofday(struct timeval *tp, struct timezone *tzp);
 # include <sys/time.h>
 # include <sys/time.h>
 #endif
 #endif
 
 
+#if defined(__APPLE__) || defined(__MACH__)
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
 /*************************/
 /*************************/
 /* External Dependencies */
 /* External Dependencies */
 /*************************/
 /*************************/
@@ -91,22 +99,28 @@ int gettimeofday(struct timeval *tp, struct timezone *tzp);
 # include <urcu/rculfhash.h>
 # include <urcu/rculfhash.h>
 # include <urcu/lfstack.h>
 # include <urcu/lfstack.h>
 # ifdef NDEBUG
 # ifdef NDEBUG
-# define UA_RCU_LOCK() rcu_read_lock()
-# define UA_RCU_UNLOCK() rcu_read_unlock()
+#  define UA_RCU_LOCK() rcu_read_lock()
+#  define UA_RCU_UNLOCK() rcu_read_unlock()
+#  define UA_ASSERT_RCU_LOCKED()
+#  define UA_ASSERT_RCU_UNLOCKED()
 # else
 # else
-extern UA_THREAD_LOCAL bool rcu_locked;
-# define UA_RCU_LOCK() do {     \
-        assert(!rcu_locked);    \
-        rcu_locked = UA_TRUE;   \
+   extern UA_THREAD_LOCAL bool rcu_locked;
+#   define UA_ASSERT_RCU_LOCKED() assert(rcu_locked)
+#   define UA_ASSERT_RCU_UNLOCKED() assert(!rcu_locked)
+#   define UA_RCU_LOCK() do {                     \
+        UA_ASSERT_RCU_UNLOCKED();                 \
+        rcu_locked = UA_TRUE;                     \
         rcu_read_lock(); } while(0)
         rcu_read_lock(); } while(0)
-# define UA_RCU_UNLOCK() do { \
-        assert(rcu_locked);   \
-        rcu_locked = UA_FALSE;    \
+#   define UA_RCU_UNLOCK() do {                   \
+        UA_ASSERT_RCU_LOCKED();                   \
+        rcu_locked = UA_FALSE;                    \
         rcu_read_lock(); } while(0)
         rcu_read_lock(); } while(0)
 # endif
 # endif
 #else
 #else
 # define UA_RCU_LOCK()
 # define UA_RCU_LOCK()
 # define UA_RCU_UNLOCK()
 # define UA_RCU_UNLOCK()
+# define UA_ASSERT_RCU_LOCKED()
+# define UA_ASSERT_RCU_UNLOCKED()
 #endif
 #endif
 
 
 #endif /* UA_UTIL_H_ */
 #endif /* UA_UTIL_H_ */

+ 4 - 4
examples/logger_stdout.c

@@ -6,7 +6,7 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <stdarg.h>
 #include "logger_stdout.h"
 #include "logger_stdout.h"
-#include "ua_types_generated_encoding_binary.h"
+#include "ua_types_generated.h"
 
 
 const char *LogLevelNames[6] = {"trace", "debug", "info", "warning", "error", "fatal"};
 const char *LogLevelNames[6] = {"trace", "debug", "info", "warning", "error", "fatal"};
 const char *LogCategoryNames[6] = {"network", "channel", "session", "server", "client", "userland"};
 const char *LogCategoryNames[6] = {"network", "channel", "session", "server", "client", "userland"};
@@ -17,9 +17,9 @@ const char *LogCategoryNames[6] = {"network", "channel", "session", "server", "c
 #endif
 #endif
 
 
 void Logger_Stdout(UA_LogLevel level, UA_LogCategory category, const char *msg, ...) {
 void Logger_Stdout(UA_LogLevel level, UA_LogCategory category, const char *msg, ...) {
-	UA_String time = UA_DateTime_toString(UA_DateTime_now());
-    printf("[%.23s] %s/%s\t", time.data, LogLevelNames[level], LogCategoryNames[category]);
-	UA_ByteString_deleteMembers(&time);
+	UA_String t = UA_DateTime_toString(UA_DateTime_now());
+    printf("[%.23s] %s/%s\t", t.data, LogLevelNames[level], LogCategoryNames[category]);
+	UA_ByteString_deleteMembers(&t);
     va_list ap;
     va_list ap;
     va_start(ap, msg);
     va_start(ap, msg);
     vprintf(msg, ap);
     vprintf(msg, ap);

examples/logger_stdout.h → src_extra/logger_stdout.h


+ 106 - 79
examples/networklayer_tcp.c

@@ -15,23 +15,39 @@
 # include <winsock2.h>
 # include <winsock2.h>
 # include <ws2tcpip.h>
 # include <ws2tcpip.h>
 # define CLOSESOCKET(S) closesocket(S)
 # define CLOSESOCKET(S) closesocket(S)
+# define ssize_t long
 #else
 #else
 # include <fcntl.h>
 # include <fcntl.h>
 # include <sys/select.h>
 # include <sys/select.h>
 # include <netinet/in.h>
 # include <netinet/in.h>
-#ifndef __CYGWIN__
-    # include <netinet/tcp.h>
-#endif
+# ifndef __CYGWIN__
+#  include <netinet/tcp.h>
+# endif
 # include <sys/ioctl.h>
 # include <sys/ioctl.h>
 # include <netdb.h> //gethostbyname for the client
 # include <netdb.h> //gethostbyname for the client
 # include <unistd.h> // read, write, close
 # include <unistd.h> // read, write, close
 # include <arpa/inet.h>
 # include <arpa/inet.h>
-#ifdef __QNX__
-#include <sys/socket.h>
-#endif
+# ifdef __QNX__
+#  include <sys/socket.h>
+# endif
 # define CLOSESOCKET(S) close(S)
 # define CLOSESOCKET(S) close(S)
 #endif
 #endif
 
 
+/* workaround a glibc bug where an integer conversion is required */
+#if !defined(_WIN32)
+# include <features.h>
+# if defined(__GNU_LIBRARY__) && (__GNU_LIBRARY__ >= 6) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 16)
+#  define fd_set(fd, fds) FD_SET(fd, fds)
+#  define fd_isset(fd, fds) FD_ISSET(fd, fds)
+# else
+#  define fd_set(fd, fds) FD_SET((unsigned int)fd, fds)
+#  define fd_isset(fd, fds) FD_ISSET((unsigned int)fd, fds)
+# endif
+#else
+# define fd_set(fd, fds) FD_SET((unsigned int)fd, fds)
+# define fd_isset(fd, fds) FD_ISSET((unsigned int)fd, fds)
+#endif
+
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
 # include <urcu/uatomic.h>
 # include <urcu/uatomic.h>
 #endif
 #endif
@@ -55,7 +71,7 @@ static UA_StatusCode
 socket_write(UA_Connection *connection, UA_ByteString *buf) {
 socket_write(UA_Connection *connection, UA_ByteString *buf) {
     size_t nWritten = 0;
     size_t nWritten = 0;
     while(buf->length > 0 && nWritten < (size_t)buf->length) {
     while(buf->length > 0 && nWritten < (size_t)buf->length) {
-        UA_Int32 n = 0;
+        ssize_t n = 0;
         do {
         do {
 #ifdef _WIN32
 #ifdef _WIN32
             n = send((SOCKET)connection->sockfd, (const char*)buf->data, (size_t)buf->length, 0);
             n = send((SOCKET)connection->sockfd, (const char*)buf->data, (size_t)buf->length, 0);
@@ -75,8 +91,8 @@ socket_write(UA_Connection *connection, UA_ByteString *buf) {
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
                 return UA_STATUSCODE_BADCONNECTIONCLOSED;
             }
             }
 #endif
 #endif
-        } while (n == -1L);
-        nWritten += n;
+        } while(n == -1L);
+        nWritten += (size_t)n;
     }
     }
     UA_ByteString_deleteMembers(buf);
     UA_ByteString_deleteMembers(buf);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
@@ -93,8 +109,8 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
     if(timeout > 0) {
     if(timeout > 0) {
         /* currently, only the client uses timeouts */
         /* currently, only the client uses timeouts */
 #ifndef _WIN32
 #ifndef _WIN32
-        int timeout_usec = timeout * 1000;
-        struct timeval tmptv = {timeout_usec / 1000000, timeout_usec % 1000000};
+        UA_UInt32 timeout_usec = timeout * 1000;
+        struct timeval tmptv = {(long int)(timeout_usec / 1000000), (long int)(timeout_usec % 1000000)};
         int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tmptv, sizeof(struct timeval));
         int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tmptv, sizeof(struct timeval));
 #else
 #else
         DWORD timeout_dw = timeout;
         DWORD timeout_dw = timeout;
@@ -107,7 +123,7 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
         }
         }
     }
     }
 
 
-    int ret = recv(connection->sockfd, (char*)response->data, connection->localConf.recvBufferSize, 0);
+    ssize_t ret = recv(connection->sockfd, (char*)response->data, connection->localConf.recvBufferSize, 0);
 	if(ret == 0) {
 	if(ret == 0) {
         /* server has closed the connection */
         /* server has closed the connection */
         UA_ByteString_deleteMembers(response);
         UA_ByteString_deleteMembers(response);
@@ -128,7 +144,7 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
         }
         }
     }
     }
-    response->length = ret;
+    response->length = (size_t)ret;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -187,16 +203,12 @@ static void FreeConnectionCallback(UA_Server *server, void *ptr) {
 #define MAXBACKLOG 100
 #define MAXBACKLOG 100
 
 
 typedef struct {
 typedef struct {
-    UA_ServerNetworkLayer layer;
+    UA_ConnectionConfig conf;
+    UA_UInt16 port;
+    UA_Logger logger; // Set during start
     
     
-    /* config */
-    UA_UInt32 port;
-    UA_ConnectionConfig conf; /* todo: rename to localconf. */
-
     /* open sockets and connections */
     /* open sockets and connections */
-    fd_set fdset;
     UA_Int32 serversockfd;
     UA_Int32 serversockfd;
-    UA_Int32 highestfd;
     size_t mappingsSize;
     size_t mappingsSize;
     struct ConnectionMapping {
     struct ConnectionMapping {
         UA_Connection *connection;
         UA_Connection *connection;
@@ -222,19 +234,22 @@ ServerNetworkLayerReleaseRecvBuffer(UA_Connection *connection, UA_ByteString *bu
 }
 }
 
 
 /* after every select, we need to reset the sockets we want to listen on */
 /* after every select, we need to reset the sockets we want to listen on */
-static void setFDSet(ServerNetworkLayerTCP *layer) {
-    FD_ZERO(&layer->fdset);
-    FD_SET((UA_UInt32)layer->serversockfd, &layer->fdset);
-    layer->highestfd = layer->serversockfd;
+static UA_Int32
+setFDSet(ServerNetworkLayerTCP *layer, fd_set *fdset) {
+    FD_ZERO(fdset);
+    fd_set(layer->serversockfd, fdset);
+    UA_Int32 highestfd = layer->serversockfd;
     for(size_t i = 0; i < layer->mappingsSize; i++) {
     for(size_t i = 0; i < layer->mappingsSize; i++) {
-        FD_SET((UA_UInt32)layer->mappings[i].sockfd, &layer->fdset);
-        if(layer->mappings[i].sockfd > layer->highestfd)
-            layer->highestfd = layer->mappings[i].sockfd;
+        fd_set(layer->mappings[i].sockfd, fdset);
+        if(layer->mappings[i].sockfd > highestfd)
+            highestfd = layer->mappings[i].sockfd;
     }
     }
+    return highestfd;
 }
 }
 
 
 /* callback triggered from the server */
 /* callback triggered from the server */
-static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
+static void
+ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_xchg(&connection->state, UA_CONNECTION_CLOSED) == UA_CONNECTION_CLOSED)
     if(uatomic_xchg(&connection->state, UA_CONNECTION_CLOSED) == UA_CONNECTION_CLOSED)
         return;
         return;
@@ -244,7 +259,7 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
     connection->state = UA_CONNECTION_CLOSED;
     connection->state = UA_CONNECTION_CLOSED;
 #endif
 #endif
     ServerNetworkLayerTCP *layer = connection->handle;
     ServerNetworkLayerTCP *layer = connection->handle;
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Closing the Connection %i",
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "Closing the Connection %i",
                 connection->sockfd);
                 connection->sockfd);
     /* only "shutdown" here. this triggers the select, where the socket is
     /* only "shutdown" here. this triggers the select, where the socket is
        "closed" in the mainloop */
        "closed" in the mainloop */
@@ -252,7 +267,8 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
 }
 }
 
 
 /* call only from the single networking thread */
 /* call only from the single networking thread */
-static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
+static UA_StatusCode
+ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
     UA_Connection *c = malloc(sizeof(UA_Connection));
     UA_Connection *c = malloc(sizeof(UA_Connection));
     if(!c)
     if(!c)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -260,7 +276,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     struct sockaddr_in addr;
     struct sockaddr_in addr;
     socklen_t addrlen = sizeof(struct sockaddr_in);
     socklen_t addrlen = sizeof(struct sockaddr_in);
     getsockname(newsockfd, (struct sockaddr*)&addr, &addrlen);
     getsockname(newsockfd, (struct sockaddr*)&addr, &addrlen);
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "New Connection %i over TCP from %s:%d",
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "New Connection %i over TCP from %s:%d",
                 newsockfd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
                 newsockfd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
     UA_Connection_init(c);
     UA_Connection_init(c);
     c->sockfd = newsockfd;
     c->sockfd = newsockfd;
@@ -275,7 +291,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     struct ConnectionMapping *nm;
     struct ConnectionMapping *nm;
     nm = realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
     nm = realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
     if(!nm) {
     if(!nm) {
-        UA_LOG_ERROR(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "No memory for a new Connection");
+        UA_LOG_ERROR(layer->logger, UA_LOGCATEGORY_NETWORK, "No memory for a new Connection");
         free(c);
         free(c);
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
@@ -285,17 +301,35 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger logger) {
-    layer->layer.logger = logger;
+static UA_StatusCode
+ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, UA_Logger logger) {
+    ServerNetworkLayerTCP *layer = nl->handle;
+    layer->logger = logger;
+
+    /* get the discovery url from the hostname */
+    UA_String du = UA_STRING_NULL;
+    char hostname[256];
+    if(gethostname(hostname, 255) == 0) {
+        char discoveryUrl[256];
+#ifndef _MSC_VER
+        du.length = (size_t)snprintf(discoveryUrl, 255, "opc.tcp://%s:%d", hostname, layer->port);
+#else
+        du.length = (size_t)_snprintf_s(discoveryUrl, 255, _TRUNCATE, "opc.tcp://%s:%d", hostname, layer->port);
+#endif
+        du.data = (UA_Byte*)discoveryUrl;
+    }
+    UA_String_copy(&du, &nl->discoveryUrl);
+    
+    /* open the server socket */
 #ifdef _WIN32
 #ifdef _WIN32
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error opening socket, code: %d",
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket, code: %d",
                        WSAGetLastError());
                        WSAGetLastError());
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
 #else
 #else
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
 #endif
 #endif
@@ -305,37 +339,39 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, U
     int optval = 1;
     int optval = 1;
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
                   SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
                        "Error during setting of socket options");
                        "Error during setting of socket options");
         CLOSESOCKET(layer->serversockfd);
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
     if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
     if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
             sizeof(serv_addr)) < 0) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error during socket binding");
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error during socket binding");
         CLOSESOCKET(layer->serversockfd);
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
     socket_set_nonblocking(layer->serversockfd);
     socket_set_nonblocking(layer->serversockfd);
     listen(layer->serversockfd, MAXBACKLOG);
     listen(layer->serversockfd, MAXBACKLOG);
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "TCP network layer listening on %.*s",
-                layer->layer.discoveryUrl.length, layer->layer.discoveryUrl.data);
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "TCP network layer listening on %.*s",
+                nl->discoveryUrl.length, nl->discoveryUrl.data);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 static size_t
 static size_t
-ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UInt16 timeout) {
-    setFDSet(layer);
+ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout) {
+    ServerNetworkLayerTCP *layer = nl->handle;
+    fd_set fdset;
+    UA_Int32 highestfd = setFDSet(layer, &fdset);
     struct timeval tmptv = {0, timeout};
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize;
     UA_Int32 resultsize;
-    resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
+    resultsize = select(highestfd+1, &fdset, NULL, NULL, &tmptv);
     if(resultsize < 0) {
     if(resultsize < 0) {
         *jobs = NULL;
         *jobs = NULL;
         return 0;
         return 0;
     }
     }
 
 
     /* accept new connections (can only be a single one) */
     /* accept new connections (can only be a single one) */
-    if(FD_ISSET(layer->serversockfd, &layer->fdset)) {
+    if(fd_isset(layer->serversockfd, &fdset)) {
         resultsize--;
         resultsize--;
         struct sockaddr_in cli_addr;
         struct sockaddr_in cli_addr;
         socklen_t cli_len = sizeof(cli_addr);
         socklen_t cli_len = sizeof(cli_addr);
@@ -351,7 +387,7 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
     /* alloc enough space for a cleanup-connection and free-connection job per resulted socket */
     /* alloc enough space for a cleanup-connection and free-connection job per resulted socket */
     if(resultsize == 0)
     if(resultsize == 0)
         return 0;
         return 0;
-    UA_Job *js = malloc(sizeof(UA_Job) * resultsize * 2);
+    UA_Job *js = malloc(sizeof(UA_Job) * (size_t)resultsize * 2);
     if(!js)
     if(!js)
         return 0;
         return 0;
 
 
@@ -359,7 +395,7 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
     size_t j = 0;
     size_t j = 0;
     UA_ByteString buf = UA_BYTESTRING_NULL;
     UA_ByteString buf = UA_BYTESTRING_NULL;
     for(size_t i = 0; i < layer->mappingsSize && j < (size_t)resultsize; i++) {
     for(size_t i = 0; i < layer->mappingsSize && j < (size_t)resultsize; i++) {
-        if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
+        if(!fd_isset(layer->mappings[i].sockfd, &fdset))
             continue;
             continue;
         UA_StatusCode retval = socket_recv(layer->mappings[i].connection, &buf, 0);
         UA_StatusCode retval = socket_recv(layer->mappings[i].connection, &buf, 0);
         if(retval == UA_STATUSCODE_GOOD) {
         if(retval == UA_STATUSCODE_GOOD) {
@@ -399,8 +435,9 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
 }
 }
 
 
 static size_t
 static size_t
-ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
+ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Job **jobs) {
+    ServerNetworkLayerTCP *layer = nl->handle;
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
                 "Shutting down the TCP network layer with %d open connection(s)", layer->mappingsSize);
                 "Shutting down the TCP network layer with %d open connection(s)", layer->mappingsSize);
     shutdown(layer->serversockfd,2);
     shutdown(layer->serversockfd,2);
     CLOSESOCKET(layer->serversockfd);
     CLOSESOCKET(layer->serversockfd);
@@ -423,43 +460,37 @@ ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
 }
 }
 
 
 /* run only when the server is stopped */
 /* run only when the server is stopped */
-static void ServerNetworkLayerTCP_deleteMembers(ServerNetworkLayerTCP *layer) {
+static void ServerNetworkLayerTCP_deleteMembers(UA_ServerNetworkLayer *nl) {
+    ServerNetworkLayerTCP *layer = nl->handle;
     free(layer->mappings);
     free(layer->mappings);
+    free(layer);
+    UA_String_deleteMembers(&nl->discoveryUrl);
 }
 }
 
 
-UA_ServerNetworkLayer * ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
+UA_ServerNetworkLayer
+UA_ServerNetworkLayerTCP(UA_ConnectionConfig conf, UA_UInt16 port) {
 #ifdef _WIN32
 #ifdef _WIN32
     WORD wVersionRequested;
     WORD wVersionRequested;
     WSADATA wsaData;
     WSADATA wsaData;
     wVersionRequested = MAKEWORD(2, 2);
     wVersionRequested = MAKEWORD(2, 2);
     WSAStartup(wVersionRequested, &wsaData);
     WSAStartup(wVersionRequested, &wsaData);
 #endif
 #endif
-    ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
+
+    UA_ServerNetworkLayer nl;
+    memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
+    ServerNetworkLayerTCP *layer = calloc(1,sizeof(ServerNetworkLayerTCP));
     if(!layer)
     if(!layer)
-        return NULL;
-    memset(layer, 0, sizeof(ServerNetworkLayerTCP));
+        return nl;
+    
     layer->conf = conf;
     layer->conf = conf;
-    layer->mappingsSize = 0;
-    layer->mappings = NULL;
     layer->port = port;
     layer->port = port;
-    char hostname[256];
-    if(gethostname(hostname, 255) == 0) {
-        char discoveryUrl[256];
-        UA_String str;
-#ifndef _MSC_VER
-        str.length = snprintf(discoveryUrl, 255, "opc.tcp://%s:%d", hostname, port);
-#else
-        str.length = _snprintf_s(discoveryUrl, 255, _TRUNCATE, "opc.tcp://%s:%d", hostname, port);
-#endif
-        str.data = (UA_Byte*)discoveryUrl;
-        UA_String_copy(&str, &layer->layer.discoveryUrl);
-    }
 
 
-    layer->layer.start = (UA_StatusCode(*)(UA_ServerNetworkLayer*,UA_Logger))ServerNetworkLayerTCP_start;
-    layer->layer.getJobs = (size_t(*)(UA_ServerNetworkLayer*,UA_Job**,UA_UInt16))ServerNetworkLayerTCP_getJobs;
-    layer->layer.stop = (size_t(*)(UA_ServerNetworkLayer*, UA_Job**))ServerNetworkLayerTCP_stop;
-    layer->layer.deleteMembers = (void(*)(UA_ServerNetworkLayer*))ServerNetworkLayerTCP_deleteMembers;
-    return &layer->layer;
+    nl.handle = layer;
+    nl.start = ServerNetworkLayerTCP_start;
+    nl.getJobs = ServerNetworkLayerTCP_getJobs;
+    nl.stop = ServerNetworkLayerTCP_stop;
+    nl.deleteMembers = ServerNetworkLayerTCP_deleteMembers;
+    return nl;
 }
 }
 
 
 /***************************/
 /***************************/
@@ -495,7 +526,7 @@ ClientNetworkLayerClose(UA_Connection *connection) {
 
 
 /* we have no networklayer. instead, attach the reusable buffer to the handle */
 /* we have no networklayer. instead, attach the reusable buffer to the handle */
 UA_Connection
 UA_Connection
-ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) {
+UA_ClientConnectionTCP(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) {
     UA_Connection connection;
     UA_Connection connection;
     UA_Connection_init(&connection);
     UA_Connection_init(&connection);
     connection.localConf = localConf;
     connection.localConf = localConf;
@@ -524,12 +555,8 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpoin
         if(endpointUrl[portpos] == ':') {
         if(endpointUrl[portpos] == ':') {
             char *endPtr = NULL;
             char *endPtr = NULL;
             unsigned long int tempulong = strtoul(&endpointUrl[portpos+1], &endPtr, 10);
             unsigned long int tempulong = strtoul(&endpointUrl[portpos+1], &endPtr, 10);
-            if (ERANGE != errno &&
-                tempulong < UINT16_MAX &&
-                endPtr != &endpointUrl[portpos+1])
-            {
+            if (ERANGE != errno && tempulong < UINT16_MAX && endPtr != &endpointUrl[portpos+1])
                 port = (UA_UInt16)tempulong;
                 port = (UA_UInt16)tempulong;
-            }
             break;
             break;
         }
         }
     }
     }
@@ -561,7 +588,7 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpoin
     }
     }
     struct sockaddr_in server_addr;
     struct sockaddr_in server_addr;
     memset(&server_addr, 0, sizeof(server_addr));
     memset(&server_addr, 0, sizeof(server_addr));
-    memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], server->h_length);
+    memcpy((char *)&server_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], (size_t)server->h_length);
     server_addr.sin_family = AF_INET;
     server_addr.sin_family = AF_INET;
     server_addr.sin_port = htons(port);
     server_addr.sin_port = htons(port);
     connection.state = UA_CONNECTION_OPENING;
     connection.state = UA_CONNECTION_OPENING;

+ 3 - 2
examples/networklayer_tcp.h

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

examples/networklayer_udp.c → src_extra/networklayer_udp.c


examples/networklayer_udp.h → src_extra/networklayer_udp.h


+ 2 - 0
tests/CMakeLists.txt

@@ -19,6 +19,8 @@ if(UA_ENABLE_MULTITHREADING)
     list(APPEND LIBS urcu-cds urcu urcu-common)
     list(APPEND LIBS urcu-cds urcu urcu-common)
 endif()
 endif()
 
 
+add_definitions(-Wno-sign-conversion)
+
 # the unit test are built directly on the open62541 object files. so they can
 # the unit test are built directly on the open62541 object files. so they can
 # access symbols that are hidden/not exported to the shared library
 # access symbols that are hidden/not exported to the shared library
 
 

+ 19 - 5
tests/check_builtin.c

@@ -27,6 +27,7 @@ START_TEST(UA_Byte_decodeShallCopyAndAdvancePosition) {
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(pos, 1);
     ck_assert_uint_eq(pos, 1);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_BYTE]));
     ck_assert_uint_eq(dst, 0x08);
     ck_assert_uint_eq(dst, 0x08);
 }
 }
 END_TEST
 END_TEST
@@ -297,6 +298,7 @@ START_TEST(UA_String_decodeShallAllocateMemoryAndCopyString) {
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(dst.length, 8);
     ck_assert_int_eq(dst.length, 8);
     ck_assert_int_eq(dst.data[3], 'L');
     ck_assert_int_eq(dst.data[3], 'L');
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_STRING]));
     // finally
     // finally
     UA_String_deleteMembers(&dst);
     UA_String_deleteMembers(&dst);
 }
 }
@@ -345,6 +347,7 @@ START_TEST(UA_NodeId_decodeTwoByteShallReadTwoBytesAndSetNamespaceToZero) {
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(pos, 2);
     ck_assert_int_eq(pos, 2);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_NODEID]));
     ck_assert_int_eq(dst.identifierType, UA_NODEIDTYPE_NUMERIC);
     ck_assert_int_eq(dst.identifierType, UA_NODEIDTYPE_NUMERIC);
     ck_assert_int_eq(dst.identifier.numeric, 16);
     ck_assert_int_eq(dst.identifier.numeric, 16);
     ck_assert_int_eq(dst.namespaceIndex, 0);
     ck_assert_int_eq(dst.namespaceIndex, 0);
@@ -362,6 +365,7 @@ START_TEST(UA_NodeId_decodeFourByteShallReadFourBytesAndRespectNamespace) {
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(pos, 4);
     ck_assert_int_eq(pos, 4);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_NODEID]));
     ck_assert_int_eq(dst.identifierType, UA_NODEIDTYPE_NUMERIC);
     ck_assert_int_eq(dst.identifierType, UA_NODEIDTYPE_NUMERIC);
     ck_assert_int_eq(dst.identifier.numeric, 256);
     ck_assert_int_eq(dst.identifier.numeric, 256);
     ck_assert_int_eq(dst.namespaceIndex, 1);
     ck_assert_int_eq(dst.namespaceIndex, 1);
@@ -379,6 +383,7 @@ START_TEST(UA_NodeId_decodeStringShallAllocateMemory) {
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(pos, 10);
     ck_assert_int_eq(pos, 10);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_NODEID]));
     ck_assert_int_eq(dst.identifierType, UA_NODEIDTYPE_STRING);
     ck_assert_int_eq(dst.identifierType, UA_NODEIDTYPE_STRING);
     ck_assert_int_eq(dst.namespaceIndex, 1);
     ck_assert_int_eq(dst.namespaceIndex, 1);
     ck_assert_int_eq(dst.identifier.string.length, 3);
     ck_assert_int_eq(dst.identifier.string.length, 3);
@@ -391,14 +396,15 @@ END_TEST
 START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
 START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
     // given
     // given
     size_t pos = 0;
     size_t pos = 0;
-    UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric, 0xFF, 0x00, 0x00, 0x00 };
+    UA_Byte data[] = { (UA_Byte)UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric, 0xFF, 0x00, 0x00, 0x00 };
     UA_ByteString src = { 5, data };
     UA_ByteString src = { 5, data };
     UA_Variant dst;
     UA_Variant dst;
     // when
     // when
     UA_StatusCode retval = UA_Variant_decodeBinary(&src, &pos, &dst);
     UA_StatusCode retval = UA_Variant_decodeBinary(&src, &pos, &dst);
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    ck_assert_int_eq(pos, 5);
+    ck_assert_uint_eq(pos, 5);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_VARIANT]));
     //ck_assert_ptr_eq((const void *)dst.type, (const void *)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     //ck_assert_ptr_eq((const void *)dst.type, (const void *)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
     ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
     ck_assert_int_eq(dst.arrayLength, 0);
     ck_assert_int_eq(dst.arrayLength, 0);
@@ -412,7 +418,8 @@ END_TEST
 START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
 START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
     // given
     // given
     size_t pos = 0;
     size_t pos = 0;
-    UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
+    UA_Byte data[] = { (UA_Byte)(UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric |
+                                 UA_VARIANT_ENCODINGMASKTYPE_ARRAY),
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF,
                        0xFF, 0xFF };
                        0xFF, 0xFF };
     UA_ByteString src = { 13, data };
     UA_ByteString src = { 13, data };
@@ -422,6 +429,7 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(pos, 1+4+2*4);
     ck_assert_int_eq(pos, 1+4+2*4);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_VARIANT]));
     //ck_assert_ptr_eq((const (void*))dst.type, (const void*)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     //ck_assert_ptr_eq((const (void*))dst.type, (const void*)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     ck_assert_int_eq((uintptr_t)dst.type,(uintptr_t)&UA_TYPES[UA_TYPES_INT32]);
     ck_assert_int_eq((uintptr_t)dst.type,(uintptr_t)&UA_TYPES[UA_TYPES_INT32]);
     ck_assert_int_eq(dst.arrayLength, 2);
     ck_assert_int_eq(dst.arrayLength, 2);
@@ -491,7 +499,8 @@ END_TEST
 START_TEST(UA_Variant_decodeWithOutDeleteMembersShallFailInCheckMem) {
 START_TEST(UA_Variant_decodeWithOutDeleteMembersShallFailInCheckMem) {
     // given
     // given
     size_t pos = 0;
     size_t pos = 0;
-    UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
+    UA_Byte data[] = { (UA_Byte)(UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric |
+                                 UA_VARIANT_ENCODINGMASKTYPE_ARRAY),
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
     UA_ByteString src = { 13, data };
     UA_ByteString src = { 13, data };
     UA_Variant dst;
     UA_Variant dst;
@@ -507,7 +516,8 @@ END_TEST
 START_TEST(UA_Variant_decodeWithTooSmallSourceShallReturnWithError) {
 START_TEST(UA_Variant_decodeWithTooSmallSourceShallReturnWithError) {
     // given
     // given
     size_t pos = 0;
     size_t pos = 0;
-    UA_Byte data[] = { UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric | UA_VARIANT_ENCODINGMASKTYPE_ARRAY,
+    UA_Byte data[] = { (UA_Byte)(UA_TYPES[UA_TYPES_INT32].typeId.identifier.numeric |
+                                 UA_VARIANT_ENCODINGMASKTYPE_ARRAY),
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
                        0x02, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
     UA_ByteString src = { 4, data };
     UA_ByteString src = { 4, data };
 
 
@@ -862,6 +872,7 @@ START_TEST(UA_String_encodeShallWorkOnExample) {
     retval = UA_String_encodeBinary(&src, &dst, &pos);
     retval = UA_String_encodeBinary(&src, &dst, &pos);
     // then
     // then
     ck_assert_int_eq(pos, sizeof(UA_Int32)+11);
     ck_assert_int_eq(pos, sizeof(UA_Int32)+11);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_STRING]));
     ck_assert_int_eq(dst.data[0], 11);
     ck_assert_int_eq(dst.data[0], 11);
     ck_assert_int_eq(dst.data[sizeof(UA_Int32)+0], 'A');
     ck_assert_int_eq(dst.data[sizeof(UA_Int32)+0], 'A');
     ck_assert_int_eq(dst.data[sizeof(UA_Int32)+1], 'C');
     ck_assert_int_eq(dst.data[sizeof(UA_Int32)+1], 'C');
@@ -891,6 +902,7 @@ START_TEST(UA_ExpandedNodeId_encodeShallWorkOnExample) {
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(pos, 13);
     ck_assert_int_eq(pos, 13);
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]));
     ck_assert_int_eq(dst.data[0], 0x80); // namespaceuri flag
     ck_assert_int_eq(dst.data[0], 0x80); // namespaceuri flag
 }
 }
 END_TEST
 END_TEST
@@ -914,6 +926,7 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithoutVariant) {
     retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
     retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
     // then
     // then
     ck_assert_int_eq(pos, 9);            // represents the length
     ck_assert_int_eq(pos, 9);            // represents the length
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_DATAVALUE]));
     ck_assert_int_eq(dst.data[0], 0x08); // encodingMask
     ck_assert_int_eq(dst.data[0], 0x08); // encodingMask
     ck_assert_int_eq(dst.data[1], 80);   // 8 Byte serverTimestamp
     ck_assert_int_eq(dst.data[1], 80);   // 8 Byte serverTimestamp
     ck_assert_int_eq(dst.data[2], 0);
     ck_assert_int_eq(dst.data[2], 0);
@@ -951,6 +964,7 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
     retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
     retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
     // then
     // then
     ck_assert_int_eq(pos, 1+(1+4)+8);           // represents the length
     ck_assert_int_eq(pos, 1+(1+4)+8);           // represents the length
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&src, &UA_TYPES[UA_TYPES_DATAVALUE]));
     ck_assert_int_eq(dst.data[0], 0x08 | 0x01); // encodingMask
     ck_assert_int_eq(dst.data[0], 0x08 | 0x01); // encodingMask
     ck_assert_int_eq(dst.data[1], 0x06);        // Variant's Encoding Mask - INT32
     ck_assert_int_eq(dst.data[1], 0x06);        // Variant's Encoding Mask - INT32
     ck_assert_int_eq(dst.data[2], 45);          // the single value
     ck_assert_int_eq(dst.data[2], 45);          // the single value

+ 19 - 0
tests/check_memory.c

@@ -180,6 +180,22 @@ START_TEST(decodeComplexTypeFromRandomBufferShallSurvive) {
 }
 }
 END_TEST
 END_TEST
 
 
+START_TEST(calcSizeBinaryShallBeCorrect) {
+	// given
+	void *obj = UA_new(&UA_TYPES[_i]);
+    size_t predicted_size = UA_calcSizeBinary(obj, &UA_TYPES[_i]);
+    UA_ByteString msg;
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&msg, predicted_size);
+	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+    size_t offset = 0;
+    retval = UA_encodeBinary(obj, &UA_TYPES[_i], &msg, &offset);
+	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+	ck_assert_int_eq(offset, predicted_size);
+    UA_delete(obj, &UA_TYPES[_i]);
+    UA_ByteString_deleteMembers(&msg);
+}
+END_TEST
+
 int main(void) {
 int main(void) {
 	int number_failed = 0;
 	int number_failed = 0;
 	SRunner *sr;
 	SRunner *sr;
@@ -199,6 +215,9 @@ int main(void) {
 	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_TYPES_NODEID, UA_TYPES_COUNT - 1);
 	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_TYPES_NODEID, UA_TYPES_COUNT - 1);
 	suite_add_tcase(s, tc);
 	suite_add_tcase(s, tc);
 
 
+	tc = tcase_create("Test calcSizeBinary");
+	tcase_add_loop_test(tc, calcSizeBinaryShallBeCorrect, UA_TYPES_BOOLEAN, UA_TYPES_COUNT - 1);
+
 	sr = srunner_create(s);
 	sr = srunner_create(s);
 	srunner_set_fork_status(sr, CK_NOFORK);
 	srunner_set_fork_status(sr, CK_NOFORK);
 	srunner_run_all (sr, CK_NORMAL);
 	srunner_run_all (sr, CK_NORMAL);

+ 53 - 48
tests/check_nodestore.c

@@ -24,7 +24,7 @@ static void printVisitor(const UA_Node* node) {
 }
 }
 
 
 static UA_Node* createNode(UA_Int16 nsid, UA_Int32 id) {
 static UA_Node* createNode(UA_Int16 nsid, UA_Int32 id) {
-	UA_Node *p = (UA_Node *)UA_VariableNode_new();
+	UA_Node *p = (UA_Node *)UA_NodeStore_newVariableNode();
 	p->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
 	p->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
 	p->nodeId.namespaceIndex = nsid;
 	p->nodeId.namespaceIndex = nsid;
 	p->nodeId.identifier.numeric = id;
 	p->nodeId.identifier.numeric = id;
@@ -35,10 +35,10 @@ static UA_Node* createNode(UA_Int16 nsid, UA_Int32 id) {
 START_TEST(replaceExistingNode) {
 START_TEST(replaceExistingNode) {
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
-    UA_MT_CONST UA_Node *inserted;
-	UA_NodeStore_insert(ns, n1, &inserted);
-	UA_Node* n2 = createNode(0,2253);
-    UA_StatusCode retval = UA_NodeStore_replace(ns, inserted, n2, NULL);
+	UA_NodeStore_insert(ns, n1);
+    UA_NodeId in1 = UA_NODEID_NUMERIC(0, 2253);
+	UA_Node* n2 = UA_NodeStore_getCopy(ns, &in1);
+    UA_StatusCode retval = UA_NodeStore_replace(ns, n2);
     
     
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     
     
@@ -46,16 +46,22 @@ START_TEST(replaceExistingNode) {
 }
 }
 END_TEST
 END_TEST
 
 
-START_TEST(replaceNonExistingNode) {
+START_TEST(replaceOldNode) {
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
-	UA_Node* n2 = createNode(0,2253);
-    UA_StatusCode retval = UA_NodeStore_replace(ns, n1, n2, NULL);
-    
+	UA_NodeStore_insert(ns, n1);
+    UA_NodeId in1 = UA_NODEID_NUMERIC(0,2253);
+	UA_Node* n2 = UA_NodeStore_getCopy(ns, &in1);
+	UA_Node* n3 = UA_NodeStore_getCopy(ns, &in1);
+
+    /* shall succeed */
+    UA_StatusCode retval = UA_NodeStore_replace(ns, n2);
+	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    /* shall fail */
+    retval = UA_NodeStore_replace(ns, n3);
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
     
     
-    UA_VariableNode_delete((UA_VariableNode*)n1);
-    UA_VariableNode_delete((UA_VariableNode*)n2);
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 }
 }
 END_TEST
 END_TEST
@@ -66,12 +72,12 @@ START_TEST(findNodeInUA_NodeStoreWithSingleEntry) {
 #endif
 #endif
 	// given
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
-    UA_MT_CONST UA_Node *inserted;
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
-	UA_NodeStore_insert(ns, n1, &inserted);
-	const UA_Node* nr = UA_NodeStore_get(ns,&inserted->nodeId);
+	UA_NodeStore_insert(ns, n1);
+    UA_NodeId in1 = UA_NODEID_NUMERIC(0,2253);
+	const UA_Node* nr = UA_NodeStore_get(ns, &in1);
 	// then
 	// then
-	ck_assert_int_eq((uintptr_t)inserted, (uintptr_t)nr);
+	ck_assert_int_eq((uintptr_t)n1, (uintptr_t)nr);
 	// finally
 	// finally
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
@@ -88,15 +94,14 @@ START_TEST(failToFindNodeInOtherUA_NodeStore) {
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
 
 
 	UA_Node* n1 = createNode(0,2255);
 	UA_Node* n1 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 
 
 	// when
 	// when
-	UA_Node* n = createNode(1,2255);
-	const UA_Node* nr = UA_NodeStore_get(ns,&n->nodeId);
+	UA_NodeId in1 = UA_NODEID_NUMERIC(1, 2255);
+	const UA_Node* nr = UA_NodeStore_get(ns, &in1);
 	// then
 	// then
 	ck_assert_int_eq((uintptr_t)nr, 0);
 	ck_assert_int_eq((uintptr_t)nr, 0);
 	// finally
 	// finally
-	UA_VariableNode_delete((UA_VariableNode*)n);
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -111,23 +116,23 @@ START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
 	// given
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 	UA_Node* n2 = createNode(0,2255);
 	UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n2, NULL);
+    UA_NodeStore_insert(ns, n2);
 	UA_Node* n3 = createNode(0,2257);
 	UA_Node* n3 = createNode(0,2257);
-    UA_MT_CONST UA_Node *inserted;
-    UA_NodeStore_insert(ns, n3, &inserted);
+    UA_NodeStore_insert(ns, n3);
 	UA_Node* n4 = createNode(0,2200);
 	UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, n4, NULL);
+    UA_NodeStore_insert(ns, n4);
 	UA_Node* n5 = createNode(0,1);
 	UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, n5, NULL);
+    UA_NodeStore_insert(ns, n5);
 	UA_Node* n6 = createNode(0,12);
 	UA_Node* n6 = createNode(0,12);
-    UA_NodeStore_insert(ns, n6, NULL);
+    UA_NodeStore_insert(ns, n6);
 
 
 	// when
 	// when
-	const UA_Node* nr = UA_NodeStore_get(ns,&inserted->nodeId);
+    UA_NodeId in3 = UA_NODEID_NUMERIC(0, 2257);
+	const UA_Node* nr = UA_NodeStore_get(ns, &in3);
 	// then
 	// then
-	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)inserted);
+	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)n3);
 	// finally
 	// finally
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
@@ -143,17 +148,17 @@ START_TEST(iterateOverUA_NodeStoreShallNotVisitEmptyNodes) {
 	// given
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 	UA_Node* n2 = createNode(0,2255);
 	UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n2, NULL);
+    UA_NodeStore_insert(ns, n2);
 	UA_Node* n3 = createNode(0,2257);
 	UA_Node* n3 = createNode(0,2257);
-    UA_NodeStore_insert(ns, n3, NULL);
+    UA_NodeStore_insert(ns, n3);
 	UA_Node* n4 = createNode(0,2200);
 	UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, n4, NULL);
+    UA_NodeStore_insert(ns, n4);
 	UA_Node* n5 = createNode(0,1);
 	UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, n5, NULL);
+    UA_NodeStore_insert(ns, n5);
 	UA_Node* n6 = createNode(0,12);
 	UA_Node* n6 = createNode(0,12);
-    UA_NodeStore_insert(ns, n6, NULL);
+    UA_NodeStore_insert(ns, n6);
 
 
 	// when
 	// when
 	zeroCnt = 0;
 	zeroCnt = 0;
@@ -180,7 +185,7 @@ START_TEST(findNodeInExpandedNamespace) {
 	UA_Int32 i=0;
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 	for (; i<200; i++) {
 		n = createNode(0,i);
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, n, NULL);
+        UA_NodeStore_insert(ns, n);
 	}
 	}
 	// when
 	// when
 	UA_Node *n2 = createNode(0,25);
 	UA_Node *n2 = createNode(0,25);
@@ -188,7 +193,7 @@ START_TEST(findNodeInExpandedNamespace) {
 	// then
 	// then
 	ck_assert_int_eq(nr->nodeId.identifier.numeric,n2->nodeId.identifier.numeric);
 	ck_assert_int_eq(nr->nodeId.identifier.numeric,n2->nodeId.identifier.numeric);
 	// finally
 	// finally
-	UA_free((void*)n2);
+    UA_NodeStore_deleteNode(n2);
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -206,7 +211,7 @@ START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
 	UA_Int32 i=0;
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 	for (; i<200; i++) {
 		n = createNode(0,i);
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, n, NULL);
+        UA_NodeStore_insert(ns, n);
 	}
 	}
 	// when
 	// when
 	zeroCnt = 0;
 	zeroCnt = 0;
@@ -230,23 +235,23 @@ START_TEST(failToFindNonExistantNodeInUA_NodeStoreWithSeveralEntries) {
 	// given
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 	UA_Node* n2 = createNode(0,2255);
 	UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n2, NULL);
+    UA_NodeStore_insert(ns, n2);
 	UA_Node* n3 = createNode(0,2257);
 	UA_Node* n3 = createNode(0,2257);
-    UA_NodeStore_insert(ns, n3, NULL);
+    UA_NodeStore_insert(ns, n3);
 	UA_Node* n4 = createNode(0,2200);
 	UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, n4, NULL);
+    UA_NodeStore_insert(ns, n4);
 	UA_Node* n5 = createNode(0,1);
 	UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, n5, NULL);
-	UA_Node* n6 = createNode(0,12); 
+    UA_NodeStore_insert(ns, n5);
+
+    UA_NodeId id = UA_NODEID_NUMERIC(0, 12);
 
 
 	// when
 	// when
-	const UA_Node* nr = UA_NodeStore_get(ns, &n6->nodeId);
+	const UA_Node* nr = UA_NodeStore_get(ns, &id);
 	// then
 	// then
 	ck_assert_int_eq((uintptr_t)nr, 0);
 	ck_assert_int_eq((uintptr_t)nr, 0);
 	// finally
 	// finally
-	UA_free((void *)n6);
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 #ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -295,7 +300,7 @@ START_TEST(profileGetDelete) {
 	UA_Node *n;
 	UA_Node *n;
 	for (int i=0; i<N; i++) {
 	for (int i=0; i<N; i++) {
 		n = createNode(0,i);
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, n, NULL);
+        UA_NodeStore_insert(ns, n);
 	}
 	}
 	clock_t begin, end;
 	clock_t begin, end;
 	begin = clock();
 	begin = clock();
@@ -345,7 +350,7 @@ static Suite * namespace_suite (void) {
 
 
 	TCase *tc_replace = tcase_create("Replace");
 	TCase *tc_replace = tcase_create("Replace");
 	tcase_add_test (tc_replace, replaceExistingNode);
 	tcase_add_test (tc_replace, replaceExistingNode);
-	tcase_add_test (tc_replace, replaceNonExistingNode);
+	tcase_add_test (tc_replace, replaceOldNode);
 	suite_add_tcase (s, tc_replace);
 	suite_add_tcase (s, tc_replace);
 
 
 	TCase* tc_iterate = tcase_create ("Iterate");
 	TCase* tc_iterate = tcase_create ("Iterate");
@@ -365,7 +370,7 @@ int main (void) {
 	int number_failed = 0;
 	int number_failed = 0;
 	Suite *s = namespace_suite();
 	Suite *s = namespace_suite();
 	SRunner *sr = srunner_create(s);
 	SRunner *sr = srunner_create(s);
-	//srunner_set_fork_status(sr,CK_NOFORK);
+	srunner_set_fork_status(sr,CK_NOFORK);
 	srunner_run_all(sr, CK_NORMAL);
 	srunner_run_all(sr, CK_NORMAL);
 	number_failed += srunner_ntests_failed (sr);
 	number_failed += srunner_ntests_failed (sr);
 	srunner_free(sr);
 	srunner_free(sr);

+ 46 - 10
tests/check_services_attributes.c

@@ -17,6 +17,15 @@
 #include <urcu.h>
 #include <urcu.h>
 #endif
 #endif
 
 
+UA_StatusCode readCPUTemperature_broken(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+                                        const UA_NumericRange *range, UA_DataValue *dataValue);
+UA_StatusCode readCPUTemperature_broken(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
+                                        const UA_NumericRange *range, UA_DataValue *dataValue) 
+{
+  dataValue->hasValue = UA_TRUE;
+  return UA_STATUSCODE_GOOD;
+}
+
 static UA_Server* makeTestSequence(void) {
 static UA_Server* makeTestSequence(void) {
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
 
 
@@ -34,7 +43,7 @@ static UA_Server* makeTestSequence(void) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
 	
 	
     /* DataSource VariableNode */
     /* DataSource VariableNode */
     UA_VariableAttributes_init(&vattr);
     UA_VariableAttributes_init(&vattr);
@@ -47,8 +56,17 @@ static UA_Server* makeTestSequence(void) {
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
 					UA_QUALIFIEDNAME(1, "cpu temperature"),
 					UA_QUALIFIEDNAME(1, "cpu temperature"),
                                         UA_NODEID_NULL, vattr, temperatureDataSource, NULL);
                                         UA_NODEID_NULL, vattr, temperatureDataSource, NULL);
-
     
     
+    /* DataSource Variable returning no value */
+    UA_DataSource temperatureDataSource1 = (UA_DataSource) {
+                                            .handle = NULL, .read = readCPUTemperature_broken, .write = NULL};
+    vattr.description = UA_LOCALIZEDTEXT("en_US","temperature1");
+    vattr.displayName = UA_LOCALIZEDTEXT("en_US","temperature1");
+    UA_Server_addDataSourceVariableNode(server, UA_NODEID_STRING(1, "cpu.temperature1"),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                        UA_QUALIFIEDNAME(1, "cpu temperature bogus"),
+                                        UA_NODEID_NULL, vattr, temperatureDataSource1, NULL);
     /* VariableNode with array */
     /* VariableNode with array */
     UA_VariableAttributes_init(&vattr);
     UA_VariableAttributes_init(&vattr);
     UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
     UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
@@ -63,7 +81,7 @@ static UA_Server* makeTestSequence(void) {
     parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
 
 
     /* ObjectNode */
     /* ObjectNode */
     UA_ObjectAttributes obj_attr;
     UA_ObjectAttributes obj_attr;
@@ -75,7 +93,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Demo"),
                             UA_QUALIFIEDNAME(1, "Demo"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
-                            obj_attr, NULL);
+                            obj_attr, NULL, NULL);
 
 
     /* ViewNode */
     /* ViewNode */
     UA_ViewAttributes view_attr;
     UA_ViewAttributes view_attr;
@@ -85,7 +103,7 @@ static UA_Server* makeTestSequence(void) {
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL);
+                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL, NULL);
 
 
 #ifdef UA_ENABLE_METHODCALLS
 #ifdef UA_ENABLE_METHODCALLS
 	/* MethodNode */
 	/* MethodNode */
@@ -104,7 +122,7 @@ static UA_Server* makeTestSequence(void) {
 }
 }
 
 
 static UA_VariableNode* makeCompareSequence(void) {
 static UA_VariableNode* makeCompareSequence(void) {
-	UA_VariableNode *node = UA_VariableNode_new();
+	UA_VariableNode *node = UA_NodeStore_newVariableNode();
 
 
 	UA_Int32 myInteger = 42;
 	UA_Int32 myInteger = 42;
 	UA_Variant_setScalarCopy(&node->value.variant.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
 	UA_Variant_setScalarCopy(&node->value.variant.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
@@ -244,7 +262,7 @@ START_TEST(ReadSingleAttributeDisplayNameWithoutTimestamp) {
     UA_Server_delete(server);
     UA_Server_delete(server);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
-    UA_VariableNode_delete(compNode);
+    UA_NodeStore_deleteNode((UA_Node*)compNode);
 } END_TEST
 } END_TEST
 
 
 START_TEST(ReadSingleAttributeDescriptionWithoutTimestamp) {
 START_TEST(ReadSingleAttributeDescriptionWithoutTimestamp) {
@@ -266,7 +284,7 @@ START_TEST(ReadSingleAttributeDescriptionWithoutTimestamp) {
     ck_assert(UA_String_equal(&compNode->description.text, &respval->text));
     ck_assert(UA_String_equal(&compNode->description.text, &respval->text));
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
-    UA_VariableNode_delete(compNode);
+    UA_NodeStore_deleteNode((UA_Node*)compNode);
     UA_Server_delete(server);
     UA_Server_delete(server);
 } END_TEST
 } END_TEST
 
 
@@ -527,7 +545,7 @@ START_TEST(ReadSingleAttributeMinimumSamplingIntervalWithoutTimestamp) {
     ck_assert(*respval == comp);
     ck_assert(*respval == comp);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
-    UA_VariableNode_delete(compNode);
+    UA_NodeStore_deleteNode((UA_Node*)compNode);
     UA_Server_delete(server);
     UA_Server_delete(server);
 } END_TEST
 } END_TEST
 
 
@@ -592,6 +610,23 @@ START_TEST(ReadSingleAttributeUserExecutableWithoutTimestamp) {
 #endif
 #endif
 } END_TEST
 } END_TEST
 
 
+START_TEST(ReadSingleDataSourceAttributeDataTypeWithoutTimestampFromBrokenSource) {
+    UA_Server *server = makeTestSequence();
+    UA_DataValue resp;
+    UA_DataValue_init(&resp);
+    UA_ReadRequest rReq;
+    UA_ReadRequest_init(&rReq);
+    rReq.nodesToRead = UA_ReadValueId_new();
+    rReq.nodesToReadSize = 1;
+    rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "cpu.temperature1");
+    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_DATATYPE;
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    ck_assert_int_eq(UA_STATUSCODE_GOOD, resp.status);
+    UA_Server_delete(server);
+    UA_ReadRequest_deleteMembers(&rReq);
+    UA_DataValue_deleteMembers(&resp);
+} END_TEST
+
 START_TEST(ReadSingleDataSourceAttributeValueWithoutTimestamp) {
 START_TEST(ReadSingleDataSourceAttributeValueWithoutTimestamp) {
     UA_Server *server = makeTestSequence();
     UA_Server *server = makeTestSequence();
     UA_DataValue resp;
     UA_DataValue resp;
@@ -1028,7 +1063,8 @@ static Suite * testSuite_services_attributes(void) {
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeHistorizingWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeHistorizingWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeExecutableWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeExecutableWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeUserExecutableWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeUserExecutableWithoutTimestamp);
-	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeValueWithoutTimestamp);
+        tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestampFromBrokenSource);
+        tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeValueWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeArrayDimensionsWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeArrayDimensionsWithoutTimestamp);
 
 

+ 32 - 3
tests/check_services_nodemanagement.c

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

+ 3 - 3
tools/pyUANamespace/open62541_MacroHelper.py

@@ -137,11 +137,11 @@ class open62541_MacroHelper():
       code.append("       , typeDefinition")
       code.append("       , typeDefinition")
     
     
     if nodetype != "Method":
     if nodetype != "Method":
-      code.append("       , attr, NULL);")
+      code.append("       , attr, NULL, NULL);")
     else:
     else:
       # FIXME:  Semantic of inputArgumentSize = -1 is used to signal the suppression of argument creation.
       # FIXME:  Semantic of inputArgumentSize = -1 is used to signal the suppression of argument creation.
       #         This should be replaced with a properly generated struct for the arguments.
       #         This should be replaced with a properly generated struct for the arguments.
-      code.append("       , attr, (UA_MethodCallback) NULL, NULL, -1, NULL, -1, NULL, NULL);")
+      code.append("       , attr, (UA_MethodCallback) NULL, NULL, 0, NULL, 0, NULL, NULL);")
     return code
     return code
     
     
   def getCreateNodeBootstrap(self, node):
   def getCreateNodeBootstrap(self, node):
@@ -170,7 +170,7 @@ class open62541_MacroHelper():
       code.append("/* undefined nodeclass */")
       code.append("/* undefined nodeclass */")
       return;
       return;
 
 
-    code.append("UA_" + nodetype + "Node *" + node.getCodePrintableID() + " = UA_" + nodetype + "Node_new();")
+    code.append("UA_" + nodetype + "Node *" + node.getCodePrintableID() + " = UA_NodeStore_new" + nodetype + "Node();")
     if not "browsename" in self.supressGenerationOfAttribute:
     if not "browsename" in self.supressGenerationOfAttribute:
       extrNs = node.browseName().split(":")
       extrNs = node.browseName().split(":")
       if len(extrNs) > 1:
       if len(extrNs) > 1:

+ 3 - 3
tools/pyUANamespace/ua_builtin_types.py

@@ -363,7 +363,7 @@ class opcua_value_t():
         else:
         else:
           for v in self.value:
           for v in self.value:
             code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType() + ";")
             code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType() + ";")
-        code.append("UA_Variant_setArrayCopy( &attr.value, &" + valueName +
+        code.append("UA_Variant_setArray( &attr.value, &" + valueName +
                     ", (UA_Int32) " + str(len(self.value)) + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
                     ", (UA_Int32) " + str(len(self.value)) + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
     else:
     else:
       # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
       # User the following strategy for all directly mappable values a la 'UA_Type MyInt = (UA_Type) 23;'
@@ -382,12 +382,12 @@ class opcua_value_t():
         #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
         #code.append("attr.value.type = &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "];")
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
           code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
+          code.append("UA_Variant_setScalar( &attr.value, " + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
           #FIXME: There is no membership definition for extensionObjects generated in this function.
           #FIXME: There is no membership definition for extensionObjects generated in this function.
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
         else:
         else:
           code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
           code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy( &attr.value, &" + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
+          code.append("UA_Variant_setScalar( &attr.value, &" + valueName + ", &UA_TYPES[UA_TYPES_" + self.value[0].stringRepresentation.upper() + "]);")
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(&" + valueName + ");")
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(&" + valueName + ");")
     return code
     return code
 
 

+ 7 - 3
tools/pyUANamespace/ua_node_types.py

@@ -685,7 +685,7 @@ class opcua_node_t:
       code = code + codegen.getCreateNodeBootstrap(self)
       code = code + codegen.getCreateNodeBootstrap(self)
       code = code + self.printOpen62541CCode_Subtype(unPrintedReferences = unPrintedReferences, bootstrapping = True)
       code = code + self.printOpen62541CCode_Subtype(unPrintedReferences = unPrintedReferences, bootstrapping = True)
       code.append("// Parent node does not exist yet. This node will be bootstrapped and linked later.")
       code.append("// Parent node does not exist yet. This node will be bootstrapped and linked later.")
-      code.append("UA_NodeStore_insert(server->nodestore, (UA_Node*) " + self.getCodePrintableID() + ", NULL);")
+      code.append("UA_NodeStore_insert(server->nodestore, (UA_Node*) " + self.getCodePrintableID() + ");")
       
       
     # Try to print all references to nodes that already exist
     # Try to print all references to nodes that already exist
     # Note: we know the reference types exist, because the namespace class made sure they were
     # Note: we know the reference types exist, because the namespace class made sure they were
@@ -1070,7 +1070,8 @@ class opcua_node_variable_t(opcua_node_t):
           code = code + self.value().printOpen62541CCode(bootstrapping)
           code = code + self.value().printOpen62541CCode(bootstrapping)
           return code
           return code
     if(bootstrapping):
     if(bootstrapping):
-      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
+      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_alloca(sizeof(UA_Variant));")
+      code.append("UA_Variant_init(" + self.getCodePrintableID() + "_variant);")
     return code
     return code
   
   
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
@@ -1095,6 +1096,7 @@ class opcua_node_variable_t(opcua_node_t):
     code.append(self.getCodePrintableID() + "->valueRank = (UA_Int32) " + str(self.valueRank()) + ";")
     code.append(self.getCodePrintableID() + "->valueRank = (UA_Int32) " + str(self.valueRank()) + ";")
     # The variant is guaranteed to exist by SubtypeEarly()
     # The variant is guaranteed to exist by SubtypeEarly()
     code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
     code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
+    code.append(self.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
     return code
     return code
 
 
 class opcua_node_method_t(opcua_node_t):
 class opcua_node_method_t(opcua_node_t):
@@ -1325,7 +1327,8 @@ class opcua_node_variableType_t(opcua_node_t):
           code = code + self.value().printOpen62541CCode(bootstrapping)
           code = code + self.value().printOpen62541CCode(bootstrapping)
           return code
           return code
     if(bootstrapping):
     if(bootstrapping):
-      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_Variant_new();")
+      code.append("UA_Variant *" + self.getCodePrintableID() + "_variant = UA_alloca(sizeof(UA_Variant));")
+      code.append("UA_Variant_init(" + self.getCodePrintableID() + "_variant);")
     return code
     return code
   
   
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
   def printOpen62541CCode_Subtype(self, unPrintedReferences=[], bootstrapping = True):
@@ -1348,6 +1351,7 @@ class opcua_node_variableType_t(opcua_node_t):
     
     
     # The variant is guaranteed to exist by SubtypeEarly()
     # The variant is guaranteed to exist by SubtypeEarly()
     code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
     code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
+    code.append(self.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
     return code
     return code
 
 
 class opcua_node_dataType_t(opcua_node_t):
 class opcua_node_dataType_t(opcua_node_t):