Просмотр исходного кода

Merge branch 'master' into client_getEndpoints

Conflicts:
	examples/client.c
Stasik0 лет назад: 9
Родитель
Сommit
a883dc3145
75 измененных файлов с 2560 добавлено и 2375 удалено
  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
 if(CMAKE_COMPILER_IS_GNUCC OR "x${CMAKE_C_COMPILER_ID}" STREQUAL "xClang")
     add_definitions(-std=c99 -pipe -Wall -Wextra -Werror -Wformat -Wno-unused-parameter
-                    -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wreturn-type -Wsign-compare -Wmultichar
-                    -Wcast-qual -Wmissing-prototypes -Wstrict-prototypes #-Wshadow #-Wconversion
+                    -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)
 
   # library linking
   set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") # cmake sets -rdynamic by default
   if(NOT WIN32 AND NOT CYGWIN)
-	add_definitions(-fvisibility=hidden -fPIC)
+	add_definitions(-Wshadow -Wconversion -fvisibility=hidden -fPIC)
     if(NOT APPLE)
       set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none")
     endif()
@@ -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)
 
 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)
 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_client.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
-                     ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h
-                     ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h)
-set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
-                     ${PROJECT_SOURCE_DIR}/deps/queue.h
+                     ${PROJECT_SOURCE_DIR}/src_extra/networklayer_tcp.h
+                     ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.h)
+set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_util.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
@@ -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/client/ua_client.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
-                ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c
-                ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
+                ${PROJECT_SOURCE_DIR}/src_extra/networklayer_tcp.c
+                ${PROJECT_SOURCE_DIR}/src_extra/logger_stdout.c
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
                 ##TODO: make client stuff optional
 
@@ -360,8 +359,9 @@ else()
     add_definitions(-DUA_NO_AMALGAMATION)
     add_library(open62541-object OBJECT ${lib_sources} ${internal_headers} ${exported_headers})
     include_directories(${PROJECT_SOURCE_DIR}/include)
-    include_directories(${PROJECT_SOURCE_DIR}/deps)
     include_directories(${PROJECT_SOURCE_DIR}/src)
+    include_directories(${PROJECT_SOURCE_DIR}/src_extra)
+    include_directories(${PROJECT_SOURCE_DIR}/deps)
 endif()
 target_compile_definitions(open62541-object PRIVATE -DUA_DYNAMIC_LINKING)
 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 "open62541.h"
 
-#define WORKER_THREADS 2 /* if multithreading is enabled */
 #define PORT 16664
 
 UA_Boolean running = UA_TRUE;
-void signalHandler(int sign) {
+void signalHandler(int sig) {
     running = UA_FALSE;
 }
 
@@ -50,18 +49,20 @@ int main(int argc, char** argv)
     signal(SIGINT, signalHandler);
 
     /* 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 */
-    /* 1) set the variable attributes */
+    /* 1) set the variable attributes (no memory allocations here) */
     UA_Int32 myInteger = 42;
     UA_VariableAttributes 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 */
     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");
 
     /* 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 */
-    UA_StatusCode retval = UA_Server_run(server, WORKER_THREADS, &running);
+    UA_StatusCode retval = UA_Server_run(server, &running);
     UA_Server_delete(server);
+    nl.deleteMembers(&nl);
     return retval;
 }
 ```
@@ -91,8 +91,8 @@ int main(int argc, char** argv)
 int main(int argc, char *argv[])
 {
     /* 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");
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
@@ -102,7 +102,7 @@ int main(int argc, char *argv[])
     /* create a readrequest with one entry */
     UA_ReadRequest req;
     UA_ReadRequest_init(&req);
-    req.nodesToRead = UA_ReadValueId_new();
+    req.nodesToRead = UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]);
     req.nodesToReadSize = 1;
     
     /* 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;
 
-// 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
 //     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->inc = (initseq << 1u) | 1u;
     pcg32_random_r(rng);
-    rng->state += initstate;
+    rng->state += initial_state;
     pcg32_random_r(rng);
 }
 
@@ -61,8 +61,8 @@ uint32_t pcg32_random_r(pcg32_random_t* rng)
 {
     uint64_t oldstate = rng->state;
     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));
 }
 

+ 4 - 4
deps/pcg_basic.h

@@ -48,13 +48,13 @@ typedef struct pcg_state_setseq_64 pcg32_random_t;
 
 #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
 //     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);
 
 // 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::
  
   :myApp> rm *.o open62541.*
+  :myApp> cp ../open62541/build/open62541.h include/
   :myApp> ln -s ../open62541/build/*so ./
   :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.
 
@@ -38,24 +44,24 @@ To create a really basic client, navigate back into the myApp folder from the pr
 .. code-block:: c
 
     #include <stdio.h>
-
+    
     #include "ua_types.h"
     #include "ua_server.h"
     #include "logger_stdout.h"
     #include "networklayer_tcp.h"
-
+    
     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) {
         UA_Client_delete(client);
         return retval;
       }
-      
+    
       UA_Client_disconnect(client);
       UA_Client_delete(client);
       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.::
 
@@ -125,31 +131,32 @@ Let us extend the client with with an action reading node's value:
 .. code-block:: c
 
     #include <stdio.h>
-
+    #include <stdio.h>
+    
     #include "ua_types.h"
     #include "ua_server.h"
     #include "logger_stdout.h"
     #include "networklayer_tcp.h"
-
+    
     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) {
         UA_Client_delete(client);
         return retval;
       }
-      
+    
       //variable to store data
       UA_DateTime raw_date = 0;
-
+    
       UA_ReadRequest 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.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
       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 &&
          rResp.resultsSize > 0 && rResp.results[0].hasValue &&
          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;
              printf("raw date is: %" PRId64 "\n", raw_date);
       }
-      
+    
       UA_ReadRequest_deleteMembers(&rReq);
       UA_ReadResponse_deleteMembers(&rResp);
-
+    
       UA_Client_disconnect(client);
       UA_Client_delete(client);
       return 0;
-    } 
+    }
 
 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"
     
     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.

Разница между файлами не показана из-за своего большого размера
+ 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.
 
-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
 --------------------------------------------------------------------------
 
 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
     UA_EndpointDescription* endpointArray = NULL;
     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);
 
     //freeing the endpointArray
@@ -38,14 +38,14 @@ int main(int argc, char *argv[]) {
 
     printf("%i endpoints found\n", (int)endpointArraySize);
     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
     UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
 
     //connect to a server
-    retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
+    retval = UA_Client_connect(client, UA_ClientConnectionTCP,
                                              "opc.tcp://localhost:16664");
 
     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");
     UA_ReadRequest 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.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
@@ -167,12 +167,12 @@ int main(int argc, char *argv[]) {
     UA_Variant_init(&input);
     UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
     
-    UA_Int32 outputSize;
+    size_t outputSize;
     UA_Variant *output;
     retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
     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]);
     } else {
         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) {
     UA_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout);
-    UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect, "opc.tcp://localhost:16664");
+    UA_StatusCode retval = UA_Client_connect(client, UA_ClientConnectionTCP,
+                                             "opc.tcp://localhost:16664");
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Client_delete(client);
         return retval;
@@ -48,5 +49,5 @@ int main(void) {
 
     UA_Client_disconnect(client);
     UA_Client_delete(client);
-    return 0;
+    return UA_STATUSCODE_GOOD;
 }

+ 29 - 16
examples/server.c

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

+ 11 - 7
examples/server.cpp

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

+ 23 - 14
examples/server_datasource.c

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

+ 12 - 12
examples/server_firstSteps.c

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

+ 10 - 6
examples/server_nodeset.c

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

+ 9 - 4
examples/server_readspeed.c

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

+ 8 - 4
examples/server_repeated_job.c

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

+ 10 - 8
examples/server_variable.c

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

+ 2 - 3
include/ua_client.h

@@ -15,9 +15,8 @@ struct UA_Client;
 typedef struct UA_Client UA_Client;
 
 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_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_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 */

+ 7 - 2
include/ua_config.h.in

@@ -55,7 +55,12 @@
 # define le32toh(x) (x)
 # define le64toh(x) (x)
 #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>
 # elif defined(__OpenBSD__)
 #  include <sys/endian.h>
@@ -85,7 +90,7 @@
 #  define le32toh(x) ENDIAN_LE32(x)
 #  define le64toh(x) ENDIAN_LE64(x)
 # endif
-# if ( __BYTE_ORDER != __LITTLE_ENDIAN )
+# if ( __BYTE_ORDER != __LITTLE_ENDIAN ) && (_BYTE_ORDER != _LITTLE_ENDIAN)
 #  define UA_NON_LITTLEENDIAN_ARCHITECTURE
 # endif
 #endif

+ 72 - 67
include/ua_server.h

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

+ 5 - 5
include/ua_types.h

@@ -35,7 +35,7 @@ extern "C" {
 /* Builtin Type Definitions */
 /****************************/
 
-#define UA_BUILTIN_TYPES_COUNT 25
+#define UA_BUILTIN_TYPES_COUNT 25U
 
 /** Boolean: A two-state logical value (true or false) */
 typedef bool UA_Boolean;
@@ -146,9 +146,9 @@ typedef struct UA_DateTimeStruct {
     UA_UInt16 year;
 } 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 */
@@ -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);
 
-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;
     id.identifier.numeric = identifier; return id; }
 
@@ -255,7 +255,7 @@ typedef struct {
     UA_UInt32 serverIndex;
 } 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);
     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 =
     { .timeout = 5000 /* ms receive timout */, .secureChannelLifeTime = 30000,
-      .timeToRenewSecureChannel = 2000,
       {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
        .maxMessageSize = 65536, .maxChunkCount = 1}};
 
@@ -33,7 +32,7 @@ static void UA_Client_init(UA_Client* client, UA_ClientConfig config,
 
     client->logger = logger;
     client->config = config;
-    client->scExpiresAt = 0;
+    client->scRenewAt = 0;
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     client->monitoredItemHandles = 0;
@@ -114,7 +113,7 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
 
     size_t offset = 8;
     retval |= UA_TcpHelloMessage_encodeBinary(&hello, &message, &offset);
-    messageHeader.messageSize = offset;
+    messageHeader.messageSize = (UA_UInt32)offset;
     offset = 0;
     retval |= UA_TcpMessageHeader_encodeBinary(&messageHeader, &message, &offset);
     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) {
     /* 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;
 
     UA_Connection *c = &client->connection;
@@ -178,7 +177,11 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
 
     UA_SecureConversationMessageHeader messageHeader;
     messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
-    messageHeader.secureChannelId = 0;
+    if(renew){
+        messageHeader.secureChannelId = client->channel.securityToken.channelId;
+    }else{
+        messageHeader.secureChannelId = 0;
+    }
 
     UA_SequenceHeader seqHeader;
     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_NodeId_encodeBinary(&requestType, &message, &offset);
     retval |= UA_OpenSecureChannelRequest_encodeBinary(&opnSecRq, &message, &offset);
-    messageHeader.messageHeader.messageSize = offset;
+    messageHeader.messageHeader.messageSize = (UA_UInt32)offset;
     offset = 0;
     retval |= UA_SecureConversationMessageHeader_encodeBinary(&messageHeader, &message, &offset);
 
@@ -282,7 +285,9 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
         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;
 
     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_encodeBinary(&request, &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST], &message, &offset);
 
-    msgHeader.messageHeader.messageSize = offset;
+    msgHeader.messageHeader.messageSize = (UA_UInt32)offset;
     offset = 0;
     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;
     for(size_t i = 0; i < response.results[0].value.arrayLength; i++){
         if(UA_String_equal(namespaceUri, &ns[i])) {
-            *namespaceIndex = i;
+            *namespaceIndex = (UA_UInt16)i;
             retval = UA_STATUSCODE_GOOD;
             break;
         }
@@ -178,8 +178,8 @@ __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass, const UA_No
 /********/
 
 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_init(&request);
     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]) {
             // This is a dataChangeNotification
             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
                 LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
                     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;
 
 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;
 } UA_Client_MonitoredItem;
 
 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_HEAD(UA_ListOfClientMonitoredItems, UA_Client_MonitoredItem_s) MonitoredItems;
 } UA_Client_Subscription;
@@ -69,7 +69,7 @@ struct UA_Client {
     UA_UInt32 requestHandle;
     
 #ifdef UA_ENABLE_SUBSCRIPTIONS
-    UA_Int32 monitoredItemHandles;
+    UA_UInt32 monitoredItemHandles;
     LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
     LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;
 #endif
@@ -77,7 +77,7 @@ struct UA_Client {
     /* Config */
     UA_Logger logger;
     UA_ClientConfig config;
-    UA_DateTime scExpiresAt;
+    UA_DateTime scRenewAt;
 };
 
 #endif /* UA_CLIENT_INTERNAL_H_ */

+ 109 - 345
src/server/ua_nodes.c

@@ -1,233 +1,63 @@
 #include "ua_nodes.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) {
+    /* 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) {
     case UA_NODECLASS_OBJECT:
-        UA_ObjectNode_deleteMembers((UA_ObjectNode*)node);
-        break;
-    case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_deleteMembers((UA_VariableNode*)node);
         break;
     case UA_NODECLASS_METHOD:
-        UA_MethodNode_deleteMembers((UA_MethodNode*)node);
         break;
     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;
     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;
-    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;
+    }
     case UA_NODECLASS_DATATYPE:
-        newNode = (UA_NewNodeFunction)UA_DataTypeNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_DataTypeNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_DataTypeNode_delete;
         break;
     case UA_NODECLASS_VIEW:
-        newNode = (UA_NewNodeFunction)UA_ViewNode_new;
-        copyNode = (UA_CopyNodeFunction)UA_ViewNode_copy;
-        deleteNode = (UA_DeleteNodeFunction)UA_ViewNode_delete;
         break;
     default:
-        return NULL;
         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->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->valueSource = src->valueSource;
     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;
     } else
         dst->value.dataSource = src->value.dataSource;
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_VariableNode_deleteMembers(dst);
-        return retval;
-    }
     dst->accessLevel = src->accessLevel;
     dst->userAccessLevel = src->accessLevel;
     dst->minimumSamplingInterval = src->minimumSamplingInterval;
@@ -235,178 +65,112 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
     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->valueSource = src->valueSource;
     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;
     } else
         dst->value.dataSource = src->value.dataSource;
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_VariableTypeNode_deleteMembers(dst);
-        return retval;
-    }
     dst->isAbstract = src->isAbstract;
     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->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;
 }
 
-/* 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->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_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                 \
     UA_NodeId nodeId;                           \
@@ -27,9 +26,8 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
 } UA_Node;
 
-void UA_Node_deleteAnyNodeClass(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 */
@@ -40,7 +38,6 @@ typedef struct {
     UA_Byte eventNotifier;
     void *instanceHandle;
 } UA_ObjectNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectNode)
 
 /******************/
 /* ObjectTypeNode */
@@ -51,7 +48,6 @@ typedef struct {
     UA_Boolean isAbstract;
     UA_ObjectLifecycleManagement lifecycleManagement;
 } UA_ObjectTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 
 typedef enum {
     UA_VALUESOURCE_VARIANT,
@@ -83,9 +79,6 @@ typedef struct {
     UA_Double minimumSamplingInterval;
     UA_Boolean historizing;
 } 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 */
@@ -105,7 +98,6 @@ typedef struct {
     /* <--- similar to variablenodes up to there--->*/
     UA_Boolean isAbstract;
 } UA_VariableTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_VariableTypeNode)
 
 /*********************/
 /* ReferenceTypeNode */
@@ -117,7 +109,6 @@ typedef struct {
     UA_Boolean symmetric;
     UA_LocalizedText inverseName;
 } UA_ReferenceTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ReferenceTypeNode)
 
 /**************/
 /* MethodNode */
@@ -127,12 +118,9 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_Boolean executable;
     UA_Boolean userExecutable;
-#ifdef UA_ENABLE_METHODCALLS
     void *methodHandle;
     UA_MethodCallback attachedMethod;
-#endif
 } UA_MethodNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_MethodNode)
 
 /************/
 /* ViewNode */
@@ -144,7 +132,6 @@ typedef struct {
     /* <-- the same as objectnode until here --> */
     UA_Boolean containsNoLoops;
 } UA_ViewNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_ViewNode)
 
 /****************/
 /* DataTypeNode */
@@ -154,6 +141,5 @@ typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_Boolean isAbstract;
 } UA_DataTypeNode;
-UA_TYPE_HANDLING_FUNCTIONS(UA_DataTypeNode)
 
 #endif /* UA_NODES_H_ */

+ 141 - 126
src/server/ua_nodestore.c

@@ -1,26 +1,17 @@
 #include "ua_nodestore.h"
 #include "ua_util.h"
 #include "ua_statuscodes.h"
+#include <stdio.h>
 
 #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;
 
 struct UA_NodeStore {
-    UA_NodeStoreEntry *entries;
+    UA_NodeStoreEntry **entries;
     UA_UInt32 size;
     UA_UInt32 count;
     UA_UInt32 sizePrimeIndex;
@@ -38,50 +29,92 @@ static hash_t const primes[] = {
     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 high = sizeof(primes) / sizeof(hash_t);
+    UA_UInt16 high = (UA_UInt16)(sizeof(primes) / sizeof(hash_t));
     while(low != high) {
-        UA_UInt16 mid = low + (high - low) / 2;
+        UA_UInt16 mid = (UA_UInt16)(low + ((high - low) / 2));
         if(n > primes[mid])
-            low = mid + 1;
+            low = (UA_UInt16)(mid + 1);
         else
             high = mid;
     }
     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
    false and sets slot to a pointer to the next free slot. */
 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;
     }
 
-    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;
     }
 
     hash_t hash2 = mod2(h, size);
     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;
         }
-        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;
         }
     }
@@ -90,33 +123,31 @@ containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, UA_NodeStoreEntr
     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) {
     UA_UInt32 osize = ns->size;
     UA_UInt32 count = ns->count;
-    /* Resize only when table after removal of unused elements is either too full or too empty.  */
+    /* 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))
         return UA_STATUSCODE_GOOD;
 
+    UA_NodeStoreEntry **oentries = ns->entries;
     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;
 
-    UA_NodeStoreEntry *oentries = ns->entries;
     ns->entries = nentries;
-    ns->size    = nsize;
+    ns->size = nsize;
     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++) {
-        if(!oentries[i].taken)
+        if(!oentries[i])
             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];
         j++;
     }
@@ -125,49 +156,6 @@ static UA_StatusCode expand(UA_NodeStore *ns) {
     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 */
 /**********************/
@@ -179,7 +167,7 @@ UA_NodeStore * UA_NodeStore_new(void) {
     ns->sizePrimeIndex = higher_prime_index(UA_NODESTORE_MINSIZE);
     ns->size = primes[ns->sizePrimeIndex];
     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);
         return NULL;
     }
@@ -188,31 +176,42 @@ UA_NodeStore * UA_NodeStore_new(void) {
 
 void UA_NodeStore_delete(UA_NodeStore *ns) {
     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);
 }
 
-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(expand(ns) != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADINTERNALERROR;
     }
 
-    UA_NodeStoreEntry *entry;
     UA_NodeId tempNodeid;
     tempNodeid = node->nodeId;
     tempNodeid.namespaceIndex = 0;
+    UA_NodeStoreEntry **entry;
     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;
-        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);
         while(UA_TRUE) {
             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;
         }
     } else {
-        if(containsNodeId(ns, &node->nodeId, &entry))
+        if(containsNodeId(ns, &node->nodeId, &entry)) {
+            deleteEntry(container_of(node, UA_NodeStoreEntry, node));
             return UA_STATUSCODE_BADNODEIDEXISTS;
+        }
     }
 
-    fillEntry(entry, node);
+    *entry = container_of(node, UA_NodeStoreEntry, node);
     ns->count++;
-    if(inserted)
-        *inserted = &entry->node.node;
     return UA_STATUSCODE_GOOD;
 }
 
 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;
-    /* 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;
 }
 
-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))
         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_NodeStoreEntry *slot;
+    UA_NodeStoreEntry **slot;
     if(!containsNodeId(ns, nodeid, &slot))
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
-    deleteEntry(slot);
+    deleteEntry(*slot);
+    *slot = NULL;
     ns->count--;
     /* Downsize the hashmap if it is very empty */
     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;
 }
 
-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"
 
 /**
- * @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;
 typedef struct UA_NodeStore UA_NodeStore;
 
@@ -42,37 +19,46 @@ UA_NodeStore * UA_NodeStore_new(void);
     critical section (multithreading). */
 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
- * 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);
 
 /**
- * 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
@@ -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);
 
 /** 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_ */

+ 96 - 138
src/server/ua_nodestore_concurrent.c

@@ -4,47 +4,53 @@
 struct nodeEntry {
     struct cds_lfht_node htn; ///< Contains the next-ptr for urcu-hashmap
     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!
 };
 
-struct UA_NodeStore {
-    struct cds_lfht *ht;
-};
-
 #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:
-        UA_ObjectNode_deleteMembers((UA_ObjectNode*)&entry->node);
+        size += sizeof(UA_ObjectNode);
         break;
     case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_deleteMembers((UA_VariableNode*)&entry->node);
+        size += sizeof(UA_VariableNode);
         break;
     case UA_NODECLASS_METHOD:
-        UA_MethodNode_deleteMembers((UA_MethodNode*)&entry->node);
+        size += sizeof(UA_MethodNode);
         break;
     case UA_NODECLASS_OBJECTTYPE:
-        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode*)&entry->node);
+        size += sizeof(UA_ObjectTypeNode);
         break;
     case UA_NODECLASS_VARIABLETYPE:
-        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode*)&entry->node);
+        size += sizeof(UA_VariableTypeNode);
         break;
     case UA_NODECLASS_REFERENCETYPE:
-        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode*)&entry->node);
+        size += sizeof(UA_ReferenceTypeNode);
         break;
     case UA_NODECLASS_DATATYPE:
-        UA_DataTypeNode_deleteMembers((UA_DataTypeNode*)&entry->node);
+        size += sizeof(UA_DataTypeNode);
         break;
     case UA_NODECLASS_VIEW:
-        UA_ViewNode_deleteMembers((UA_ViewNode*)&entry->node);
+        size += sizeof(UA_ViewNode);
         break;
     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. */
@@ -56,25 +62,16 @@ static int compare(struct cds_lfht_node *htn, const void *orig) {
 }
 
 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!! */
 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);
-    rcu_read_lock();
     while(iter.node) {
         if(!cds_lfht_del(ht, iter.node)) {
             /* points to the htn entry, which is first */
@@ -83,49 +80,26 @@ void UA_NodeStore_delete(UA_NodeStore *ns) {
         }
         cds_lfht_next(ht, &iter);
     }
-    rcu_read_unlock();
     cds_lfht_destroy(ht, NULL);
     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);
     struct cds_lfht_node *result;
     //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;
     if(!UA_NodeId_isNull(&tempNodeid)) {
         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(result != &entry->htn) {
-            UA_free(entry);
+            deleteEntry(&entry->rcu_head);
             return UA_STATUSCODE_BADNODEIDEXISTS;
         }
     } else {
         /* 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 */
-        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;
         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++;
 
-        newNode->nodeId.identifier.numeric = identifier;
+        node->nodeId.identifier.numeric = (UA_UInt32)identifier;
         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)
                 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;
 }
 
-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 */
     hash_t h = hash(&node->nodeId);
     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)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
     /* We try to replace an obsolete version of the node */
     struct nodeEntry *oldEntry = (struct nodeEntry*)iter.node;
-    if(&oldEntry->node != oldNode)
+    if(oldEntry != entry->orig)
         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.*/
-        UA_free(newEntry);
+        deleteEntry(&entry->rcu_head);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
         
     /* If an entry got replaced, mark it as dead. */
     call_rcu(&oldEntry->rcu_head, deleteEntry);
-    UA_free(node);
-
-    if(inserted)
-        *inserted = &newEntry->node;
     return UA_STATUSCODE_GOOD;
 }
 
 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);
     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;
     struct nodeEntry *entry = (struct nodeEntry*)iter.node;
     call_rcu(&entry->rcu_head, deleteEntry);
     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);
     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;
     if(!found_entry)
         return NULL;
     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;
     cds_lfht_first(ht, &iter);
     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)
         return 0;
 
-    const int32_t   nblocks = len / 4;
+    const int32_t nblocks = (int32_t)(len / 4);
     const uint32_t *blocks;
     static const uint32_t c1 = 0xcc9e2d51;
     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);
-    uint32_t       k1   = 0;
+    uint32_t k1 = 0;
     switch(len & 3) {
     case 3:
-        k1 ^= tail[2] << 16;
+        k1 ^= (uint32_t)(tail[2] << 16);
     case 2:
-        k1 ^= tail[1] << 8;
+        k1 ^= (uint32_t)(tail[1] << 8);
     case 1:
         k1   ^= tail[0];
         k1   *= c1;
@@ -63,13 +63,15 @@ static hash_t hash(const UA_NodeId *n) {
     switch(n->identifierType) {
     case UA_NODEIDTYPE_NUMERIC:
         /*  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:
-        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:
-        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:
-        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:
         UA_assert(UA_FALSE);
         return 0;

+ 4 - 4
src/server/ua_securechannel_manager.h

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

Разница между файлами не показана из-за своего большого размера
+ 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_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;
     retval |= UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(msg, pos, &asymHeader);
 
@@ -83,6 +93,7 @@ static void processOPN(UA_Connection *connection, UA_Server *server, const UA_By
         return;
     }
 
+
     UA_OpenSecureChannelResponse p;
     UA_OpenSecureChannelResponse_init(&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->close(connection);
     } else {
-        respHeader.messageHeader.messageSize = tmpPos;
+        respHeader.messageHeader.messageSize = (UA_UInt32)tmpPos;
         tmpPos = 0;
         UA_SecureConversationMessageHeader_encodeBinary(&respHeader, &resp_msg, &tmpPos);
         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);
     retval |= UA_UInt32_decodeBinary(msg, pos, &tokenId);
     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)
         return;
 
@@ -327,7 +338,7 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     if(tokenId != channel->securityToken.tokenId) {
         if(tokenId != channel->nextSecurityToken.tokenId) {
             /* close the securechannel but keep the connection open */
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SECURECHANNEL,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Request with a wrong security token. Closing the SecureChannel %i.",
                         channel->securityToken.channelId);
             Service_CloseSecureChannel(server, channel->securityToken.channelId);
@@ -352,11 +363,12 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
     if(!requestType) {
         /* The service is not supported */
         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
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Unknown request: NodeId(ns=%d, i=%d)",
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                        "Unknown request: NodeId(ns=%d, i=%d)",
                         requestTypeId.namespaceIndex, requestTypeId.identifier.numeric);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
         return;
@@ -385,6 +397,7 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
         UA_SecureChannel_getSession(channel, &((UA_RequestHeader*)request)->authenticationToken);
     UA_Session anonymousSession;
     if(!session) {
+        /* session id 0 -> anonymous session */
         UA_Session_init(&anonymousSession);
         anonymousSession.channel = channel;
         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 */
     if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) {
-        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service with a non-activated session");
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                    "Client tries to call a service with a non-activated session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         return;
     }
 #ifndef UA_ENABLE_NONSTANDARD_STATELESS
     if(session == &anonymousSession &&
        requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) {
-        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service without a session");
+        UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                    "Client tries to call a service without a session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
         return;
     }
@@ -457,7 +472,7 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
     UA_TcpMessageHeader tcpMessageHeader;
     do {
         if(UA_TcpMessageHeader_decodeBinary(msg, &pos, &tcpMessageHeader)) {
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK, "Decoding of message header failed");
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK, "Decoding of message header failed");
             connection->close(connection);
             break;
         }
@@ -484,13 +499,13 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
             connection->close(connection);
             return;
         default:
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
                         "Unknown request type on Connection %i", connection->sockfd);
         }
 
         UA_TcpMessageHeader_deleteMembers(&tcpMessageHeader);
         if(pos != targetpos) {
-            UA_LOG_INFO(server->logger, UA_LOGCATEGORY_NETWORK,
+            UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_NETWORK,
                         "Message on Connection %i was not entirely processed. "
                         "Arrived at position %i, skip after the announced length to position %i",
                         connection->sockfd, pos, targetpos);

+ 17 - 21
src/server/ua_server_internal.h

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

+ 131 - 150
src/server/ua_server_worker.c

@@ -1,11 +1,6 @@
 #include "ua_util.h"
 #include "ua_server_internal.h"
 
-#if defined(__APPLE__) || defined(__MACH__)
-#include <mach/clock.h>
-#include <mach/mach.h>
-#endif
-
 /**
  * There are four types of job execution:
  *
@@ -42,13 +37,10 @@
 #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
 
-/**
- * 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];
         switch(job->type) {
         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);
             break;
         default:
-            UA_LOG_WARNING(server->logger, UA_LOGCATEGORY_SERVER, "Trying to execute a job of unknown type");
+            UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
+                           "Trying to execute a job of unknown type");
             break;
         }
     }
+    UA_RCU_UNLOCK();
 }
 
 /*******************************/
@@ -96,8 +90,44 @@ struct DispatchJobsList {
     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) {
     size_t startIndex = jobsSize; // start at the end
     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)) {
         struct DispatchJobsList *wln = (struct DispatchJobsList*)
             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
         UA_Job *jobsCopy = UA_malloc(sizeof(UA_Job) * tw->jobsSize);
         if(!jobsCopy) {
-            UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Not enough memory to dispatch delayed jobs");
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Not enough memory to dispatch delayed jobs");
             break;
         }
         for(size_t i=0;i<tw->jobsSize;i++)
@@ -366,9 +338,9 @@ static UA_UInt16 processRepeatedJobs(UA_Server *server) {
     // check if the next repeated job is sooner than the usual timeout
     // calc in 32 bit must be ok
     struct RepeatedJobs *first = LIST_FIRST(&server->repeatedJobs);
-    UA_UInt32 timeout = MAXTIMEOUT;
+    UA_UInt16 timeout = MAXTIMEOUT;
     if(first) {
-        timeout = (UA_UInt32)((first->nextTime - current) / 10);
+        timeout = (UA_UInt16)((first->nextTime - current) / 10);
         if(timeout > MAXTIMEOUT)
             return MAXTIMEOUT;
     }
@@ -442,9 +414,9 @@ struct DelayedJobs {
 
 /* Dispatched as an ordinary job when the DelayedJobs list is full */
 static void getCounters(UA_Server *server, struct DelayedJobs *delayed) {
-    UA_UInt32 *counters = UA_malloc(server->nThreads * sizeof(UA_UInt32));
-    for(UA_UInt16 i = 0;i<server->nThreads;i++)
-        counters[i] = *server->workerCounters[i];
+    UA_UInt32 *counters = UA_malloc(server->config.nThreads * sizeof(UA_UInt32));
+    for(UA_UInt16 i = 0; i < server->config.nThreads; i++)
+        counters[i] = server->workers[i].counter;
     delayed->workerCounters = counters;
 }
 
@@ -457,7 +429,8 @@ static void addDelayedJob(UA_Server *server, UA_Job *job) {
         /* create a new DelayedJobs and add it to the linked list */
         dj = UA_malloc(sizeof(struct DelayedJobs));
         if(!dj) {
-            UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Not enough memory to add a delayed job");
+            UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "Not enough memory to add a delayed job");
             return;
         }
         dj->jobsCount = 0;
@@ -509,8 +482,8 @@ static void dispatchDelayedJobs(UA_Server *server, void *data /* not used, but n
             continue;
         }
         UA_Boolean allMoved = UA_TRUE;
-        for(UA_UInt16 i=0;i<server->nThreads;i++) {
-            if(dw->workerCounters[i] == *server->workerCounters[i]) {
+        for(size_t i = 0; i < server->config.nThreads; i++) {
+            if(dw->workerCounters[i] == server->workers[i].counter) {
                 allMoved = UA_FALSE;
                 break;
             }
@@ -521,6 +494,12 @@ static void dispatchDelayedJobs(UA_Server *server, void *data /* not used, but n
         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 */
     while(dw) {
         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);
         dw = next;
     }
+#if (__GNUC__ <= 4 && __GNUC_MINOR__ <= 6)
+#pragma GCC diagnostic pop
+#endif
+
 }
 
 #endif
@@ -554,70 +537,71 @@ static void processMainLoopJobs(UA_Server *server) {
 }
 #endif
 
-UA_StatusCode UA_Server_run_startup(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *running) {
-UA_StatusCode result = UA_STATUSCODE_GOOD;
-
+UA_StatusCode UA_Server_run_startup(UA_Server *server) {
 #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);
-    server->thr = UA_malloc(nThreads * sizeof(pthread_t));
-    server->workerCounters = UA_malloc(nThreads * sizeof(UA_UInt32 *));
-    for(UA_UInt32 i=0;i<nThreads;i++) {
-        struct workerStartData *startData = UA_malloc(sizeof(struct workerStartData));
-        startData->server = server;
-        startData->workerCounter = &server->workerCounters[i];
-        pthread_create(&server->thr[i], NULL, (void* (*)(void*))workerLoop, startData);
+    server->workers = UA_malloc(server->config.nThreads * sizeof(UA_Worker));
+    if(!server->workers)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    for(size_t i = 0; i < server->config.nThreads; i++) {
+        UA_Worker *worker = &server->workers[i];
+        worker->server = server;
+        worker->counter = 0;
+        worker->running = true;
+        pthread_create(&worker->thr, NULL, (void* (*)(void*))workerLoop, worker);
     }
 
-    /* try to execute the delayed callbacks every 10 sec */
+    /* Try to execute delayed callbacks every 10 sec */
     UA_Job processDelayed = {.type = UA_JOBTYPE_METHODCALL,
                              .job.methodCall = {.method = dispatchDelayedJobs, .data = NULL} };
     UA_Server_addRepeatedJob(server, processDelayed, 10000, NULL);
 #endif
 
     /* Start the networklayers */
-    for(size_t i = 0; i < server->networkLayersSize; i++)
-        result |= server->networkLayers[i]->start(server->networkLayers[i], server->logger);
+    UA_StatusCode result = UA_STATUSCODE_GOOD;
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
+        result |= nl->start(nl, server->config.logger);
+        for(size_t j = 0; j < server->endpointDescriptionsSize; j++) {
+            UA_String_copy(&nl->discoveryUrl, &server->endpointDescriptions[j].endpointUrl);
+        }
+    }
 
     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
-    /* Run Work in the main loop */
-    processMainLoopJobs(server);
+    processMainLoopJobs(server); /* Run work assigned for the main thread */
 #endif
-    /* Process repeated work */
-    UA_UInt16 timeout = processRepeatedJobs(server);
+    UA_UInt16 timeout = processRepeatedJobs(server); /* Process repeated work */
 
     /* Get work from the networklayer */
-    for(size_t i = 0; i < server->networkLayersSize; i++) {
-        UA_ServerNetworkLayer *nl = server->networkLayers[i];
+    for(size_t i = 0; i < server->config.networkLayersSize; i++) {
+        UA_ServerNetworkLayer *nl = &server->config.networkLayers[i];
         UA_Job *jobs;
-        UA_Int32 jobsSize;
-        if(*running) {
-            if(i == server->networkLayersSize-1)
-                jobsSize = nl->getJobs(nl, &jobs, timeout);
-            else
-                jobsSize = nl->getJobs(nl, &jobs, 0);
-        } else
-            jobsSize = server->networkLayers[i]->stop(nl, &jobs);
+        size_t jobsSize;
+        if(i == server->config.networkLayersSize-1)
+            /* only the last networklayer waits on the tieout */
+            jobsSize = nl->getJobs(nl, &jobs, timeout);
+        else
+            jobsSize = nl->getJobs(nl, &jobs, 0);
 
 #ifdef UA_ENABLE_MULTITHREADING
         /* Filter out delayed work */
-        for(UA_Int32 k=0;k<jobsSize;k++) {
+        for(size_t k = 0; k < jobsSize; k++) {
             if(jobs[k].type != UA_JOBTYPE_METHODCALL_DELAYED)
                 continue;
             addDelayedJob(server, &jobs[k]);
             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)
             pthread_cond_broadcast(&server->dispatchQueue_condition);
 #else
@@ -626,47 +610,44 @@ UA_StatusCode UA_Server_run_mainloop(UA_Server *server, UA_Boolean *running) {
             UA_free(jobs);
 #endif
     }
+
     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);
         UA_free(stopJobs);
     }
+
 #ifdef UA_ENABLE_MULTITHREADING
+    UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_SERVER,
+                "Shutting down %u worker thread(s)", server->config.nThreads);
     /* Wait for all worker threads to finish */
-    for(UA_UInt32 i=0;i<nThreads;i++) {
-        pthread_join(server->thr[i], NULL);
-        UA_free(server->workerCounters[i]);
-    }
-    UA_free(server->workerCounters);
-    UA_free(server->thr);
-
-    /* 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);
-
-    /* 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
     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);
 
 /** 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,
                       UA_AddNodesResponse *response);
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result);
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback);
 
 /** Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session,

+ 65 - 60
src/server/ua_services_attribute.c

@@ -9,48 +9,51 @@
 /* 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;
     size_t progress = 0;
     /* read numbers until the end or a non-number character appears */
     UA_Byte c;
-    while((UA_Int32)progress < buflen) {
+    while(progress < buflen) {
         c = buf[progress];
         if('0' > c || '9' < c)
             break;
-        n = (n*10) + (c-'0');
+        n = (n*10) + (UA_UInt32)(c-'0');
         progress++;
     }
     *number = n;
     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);
     if(progress == 0)
         return 0;
-    if(buflen <= (UA_Int32)progress || buf[progress] != ':') {
+    if(buflen <= progress || buf[progress] != ':') {
         dim->max = dim->min;
         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)
         return 0;
-    return progress + progress2 + 1;
+    return progress + progress2;
 }
 
 #ifndef UA_BUILD_UNIT_TESTS
 static
 #endif
 UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
-    UA_Int32 index = 0;
+    size_t idx = 0;
     size_t dimensionsMax = 0;
     struct UA_NumericRangeDimension *dimensions = NULL;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     size_t pos = 0;
     do {
         /* alloc dimensions */
-        if(index >= (UA_Int32)dimensionsMax) {
+        if(idx >= dimensionsMax) {
             struct UA_NumericRangeDimension *newds;
             newds = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2));
             if(!newds) {
@@ -62,22 +65,22 @@ UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
         }
 
         /* 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) {
             retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
             break;
         }
         pos += progress;
-        index++;
+        idx++;
 
         /* loop into the next dimension */
         if(pos >= str->length)
             break;
     } while(str->data[pos] == ',' && pos++);
 
-    if(retval == UA_STATUSCODE_GOOD && index > 0) {
+    if(retval == UA_STATUSCODE_GOOD && idx > 0) {
         range->dimensions = dimensions;
-        range->dimensionsSize = index;
+        range->dimensionsSize = idx;
     } else
         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. */
-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);
-    v->type = type;
+    v->type = t;
     v->data = (void*)(uintptr_t)p;
     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 */
         UA_DataValue 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);
         if(retval != UA_STATUSCODE_GOOD)
             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);
     }
     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,
                   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)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
     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_StatusCode retval;
     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)
             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;
 #else
-        UA_Node *copy = UA_Node_copyAnyNodeClass(node);
+        UA_Node *copy = UA_NodeStore_getCopy(server->nodestore, nodeId);
         if(!copy)
             return UA_STATUSCODE_BADOUTOFMEMORY;
         retval = callback(server, session, copy, data);
         if(retval != UA_STATUSCODE_GOOD) {
-            UA_Node_deleteAnyNodeClass(copy);
+            UA_NodeStore_deleteNode(copy);
             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
     } while(retval != UA_STATUSCODE_GOOD);
     return UA_STATUSCODE_GOOD;
@@ -502,17 +506,16 @@ enum type_equivalence {
     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;
-    if(type->members[0].memberTypeIndex == UA_TYPES_INT32)
+    if(t->members[0].memberTypeIndex == UA_TYPES_INT32)
         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_NONE;
 }
 
-/* In the multithreaded case, node is a copy */
 static UA_StatusCode
 CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
     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;
     UA_Variant *oldV = &node->value.variant.value;
     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) {
@@ -579,7 +584,7 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 
     void *value = wvalue->value.value.data;
     void *target = NULL;
-    const UA_DataType *type = NULL;
+    const UA_DataType *attr_type = NULL;
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
 	switch(wvalue->attributeId) {
@@ -591,17 +596,17 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 	case UA_ATTRIBUTEID_BROWSENAME:
 		CHECK_DATATYPE(QUALIFIEDNAME);
         target = &node->browseName;
-        type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
+        attr_type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
         target = &node->displayName;
-        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+        attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
         target = &node->description;
-        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+        attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
 		CHECK_DATATYPE(UINT32);
@@ -626,7 +631,7 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
         target = &((UA_ReferenceTypeNode*)node)->inverseName;
-        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+        attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
@@ -679,9 +684,9 @@ CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
 		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		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;
 }
@@ -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,
                    UA_WriteResponse *response) {
     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)",
                  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 */
     UA_UInt32 fakeDims;
     if(!scalar && !varDims) {
-        fakeDims = var->arrayLength;
+        fakeDims = (UA_UInt32)var->arrayLength;
         varDims = &fakeDims;
         varDimsSize = 1;
     }

+ 51 - 11
src/server/ua_services_discovery.c

@@ -4,31 +4,67 @@
 
 void Service_FindServers(UA_Server *server, UA_Session *session,
                          const UA_FindServersRequest *request, UA_FindServersResponse *response) {
-    response->servers = UA_malloc(sizeof(UA_ApplicationDescription));
-    if(!response->servers) {
+    /* copy ApplicationDescription from the config */
+    UA_ApplicationDescription *descr = UA_malloc(sizeof(UA_ApplicationDescription));
+    if(!descr) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
-    if(UA_ApplicationDescription_copy(&server->description, response->servers) != UA_STATUSCODE_GOOD) {
-        UA_free(response->servers);
+    response->responseHeader.serviceResult =
+        UA_ApplicationDescription_copy(&server->config.applicationDescription, descr);
+    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
+        UA_free(descr);
+        return;
+    }
+
+    /* add the discoveryUrls from the networklayers */
+    UA_String *disc = UA_realloc(descr->discoveryUrls, sizeof(UA_String) *
+                                 (descr->discoveryUrlsSize + server->config.networkLayersSize));
+    if(!disc) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+        UA_ApplicationDescription_delete(descr);
         return;
     }
-	response->serversSize = 1;
+    size_t 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 */
 #ifdef NO_ALLOCA
 	UA_Boolean relevant_endpoints[server->endpointDescriptionsSize];
 #else
-	UA_Boolean *relevant_endpoints = UA_alloca(sizeof(UA_Boolean)*server->endpointDescriptionsSize);
-#endif /*NO_ALLOCA */
+	UA_Boolean *relevant_endpoints = UA_alloca(sizeof(UA_Byte) * server->endpointDescriptionsSize);
+#endif
     size_t relevant_count = 0;
     for(size_t j = 0; j < server->endpointDescriptionsSize; j++) {
         relevant_endpoints[j] = UA_FALSE;
-        if(request->profileUrisSize <= 0) {
+        if(request->profileUrisSize == 0) {
             relevant_endpoints[j] = UA_TRUE;
             relevant_count++;
             continue;
@@ -56,9 +92,13 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
     size_t k = 0;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(size_t j = 0; j < server->endpointDescriptionsSize && retval == UA_STATUSCODE_GOOD; j++) {
-        if(relevant_endpoints[j] != UA_TRUE)
+        if(!relevant_endpoints[j])
             continue;
         retval = UA_EndpointDescription_copy(&server->endpointDescriptions[j], &response->endpoints[k]);
+        if(retval != UA_STATUSCODE_GOOD)
+            break;
+        UA_String_deleteMembers(&response->endpoints[k].endpointUrl);
+        retval = UA_String_copy(&request->endpointUrl, &response->endpoints[k].endpointUrl);
         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) {
     if(node->nodeId.namespaceIndex >= server->namespacesSize) {
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         return;
     }
 
     const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId);
     if(!parent) {
         result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         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);
     if(!referenceType) {
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         return;
     }
 
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+        UA_NodeStore_deleteNode(node);
         return;
     }
 
     if(referenceType->isAbstract == UA_TRUE) {
         result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
+        UA_NodeStore_deleteNode(node);
         return;
     }
 
     // todo: test if the referencetype is hierarchical
     // 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
     UA_AddReferencesItem item;
     UA_AddReferencesItem_init(&item);
-    item.sourceNodeId = managed->nodeId;
+    item.sourceNodeId = node->nodeId;
     item.referenceTypeId = *referenceTypeId;
     item.isForward = UA_FALSE;
     item.targetNodeId.nodeId = *parentNodeId;
@@ -80,16 +68,19 @@ UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session,
-                        const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                        const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                        UA_InstantiationCallback *instantiationCallback);
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId);
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
+                      UA_InstantiationCallback *instantiationCallback);
 
 /* copy an existing variable under the given parent. then instantiate the
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                     const UA_NodeId *referenceType, const UA_NodeId *parent) {
+                     const UA_NodeId *referenceType, const UA_NodeId *parent,
+                     UA_InstantiationCallback *instantiationCallback) {
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -127,7 +118,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     // add the new variable
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_VariableAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
 
@@ -139,9 +130,12 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
             continue;
-        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+        instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
-
+    
+    if (instantiationCallback != NULL)
+      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+    
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
 }
@@ -150,13 +144,14 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                   const UA_NodeId *referenceType, const UA_NodeId *parent) {
-    const UA_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)
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(node->nodeClass != UA_NODECLASS_OBJECT)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-
+    
     // copy the variable attributes
     UA_ObjectAttributes attr;
     UA_ObjectAttributes_init(&attr);
@@ -180,7 +175,7 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
     // add the new object
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, &res);
+    Service_AddNodes_single(server, session, &item, &res, instantiationCallback);
     UA_ObjectAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
 
@@ -192,9 +187,12 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
         const UA_NodeId hasTypeDef = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
         if(!UA_NodeId_equal(&rn->referenceTypeId, &hasTypeDef))
             continue;
-        instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId);
+        instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
-
+    
+    if (instantiationCallback != NULL)
+      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+    
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
 }
@@ -209,13 +207,14 @@ setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* n
 
 static UA_StatusCode
 instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId) {
-    const UA_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 */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
@@ -244,9 +243,9 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
             item.targetNodeClass = UA_NODECLASS_METHOD;
             Service_AddReferences_single(server, session, &item);
         } else if(rd->nodeClass == UA_NODECLASS_VARIABLE)
-            copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+          copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
         else if(rd->nodeClass == UA_NODECLASS_OBJECT)
-            copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+          copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
 
     /* add a hastypedefinition reference */
@@ -260,7 +259,7 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
     Service_AddReferences_single(server, session, &addref);
 
     /* call the constructor */
-    const UA_ObjectLifecycleManagement *olm = &type->lifecycleManagement;
+    const UA_ObjectLifecycleManagement *olm = &typenode->lifecycleManagement;
     if(olm->constructor)
         UA_Server_editNode(server, session, nodeId,
                            (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId));
@@ -269,13 +268,13 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                        const UA_NodeId *typeId) {
-    const UA_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;
-    if(type->nodeClass != UA_NODECLASS_VARIABLETYPE)
+    if(typenode->nodeClass != UA_NODECLASS_VARIABLETYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-
+    
     /* get the references to child properties */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
@@ -294,7 +293,7 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     /* add the child properties */
     for(size_t i = 0; i < browseResult.referencesSize; i++) {
         UA_ReferenceDescription *rd = &browseResult.references[i];
-        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
+        copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId, instantiationCallback);
     }
 
     /* add a hastypedefinition reference */
@@ -324,7 +323,7 @@ copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item, const UA_Node
 
 static UA_Node *
 variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttributes *attr) {
-    UA_VariableNode *vnode = UA_VariableNode_new();
+    UA_VariableNode *vnode = UA_NodeStore_newVariableNode();
     if(!vnode)
         return NULL;
     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;
     retval |= UA_Variant_copy(&attr->value, &vnode->value.variant.value);
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        UA_NodeStore_deleteNode((UA_Node*)vnode);
         return NULL;
     }
     return (UA_Node*)vnode;
@@ -344,13 +343,13 @@ variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttribu
 
 static UA_Node *
 objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes *attr) {
-    UA_ObjectNode *onode = UA_ObjectNode_new();
+    UA_ObjectNode *onode = UA_NodeStore_newObjectNode();
     if(!onode)
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)onode, item, (const UA_NodeAttributes*)attr);
     onode->eventNotifier = attr->eventNotifier;
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)onode);
+        UA_NodeStore_deleteNode((UA_Node*)onode);
         return NULL;
     }
     return (UA_Node*)onode;
@@ -358,7 +357,7 @@ objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes
 
 static UA_Node *
 referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) {
-    UA_ReferenceTypeNode *rtnode = UA_ReferenceTypeNode_new();
+    UA_ReferenceTypeNode *rtnode = UA_NodeStore_newReferenceTypeNode();
     if(!rtnode)
         return NULL;
     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;
     retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)rtnode);
+        UA_NodeStore_deleteNode((UA_Node*)rtnode);
         return NULL;
     }
     return (UA_Node*)rtnode;
@@ -374,13 +373,13 @@ referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceT
 
 static UA_Node *
 objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAttributes *attr) {
-    UA_ObjectTypeNode *otnode = UA_ObjectTypeNode_new();
+    UA_ObjectTypeNode *otnode = UA_NodeStore_newObjectTypeNode();
     if(!otnode)
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)otnode, item, (const UA_NodeAttributes*)attr);
     otnode->isAbstract = attr->isAbstract;
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)otnode);
+        UA_NodeStore_deleteNode((UA_Node*)otnode);
         return NULL;
     }
     return (UA_Node*)otnode;
@@ -388,7 +387,7 @@ objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAtt
 
 static UA_Node *
 variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTypeAttributes *attr) {
-    UA_VariableTypeNode *vtnode = UA_VariableTypeNode_new();
+    UA_VariableTypeNode *vtnode = UA_NodeStore_newVariableTypeNode();
     if(!vtnode)
         return NULL;
     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
     vtnode->isAbstract = attr->isAbstract;
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)vtnode);
+        UA_NodeStore_deleteNode((UA_Node*)vtnode);
         return NULL;
     }
     return (UA_Node*)vtnode;
@@ -406,14 +405,14 @@ variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTyp
 
 static UA_Node *
 viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *attr) {
-    UA_ViewNode *vnode = UA_ViewNode_new();
+    UA_ViewNode *vnode = UA_NodeStore_newViewNode();
     if(!vnode)
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     vnode->containsNoLoops = attr->containsNoLoops;
     vnode->eventNotifier = attr->eventNotifier;
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        UA_NodeStore_deleteNode((UA_Node*)vnode);
         return NULL;
     }
     return (UA_Node*)vnode;
@@ -421,20 +420,20 @@ viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *att
 
 static UA_Node *
 dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttributes *attr) {
-    UA_DataTypeNode *dtnode = UA_DataTypeNode_new();
+    UA_DataTypeNode *dtnode = UA_NodeStore_newDataTypeNode();
     if(!dtnode)
         return NULL;
     UA_StatusCode retval = copyStandardAttributes((UA_Node*)dtnode, item, (const UA_NodeAttributes*)attr);
     dtnode->isAbstract = attr->isAbstract;
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass((UA_Node*)dtnode);
+        UA_NodeStore_deleteNode((UA_Node*)dtnode);
         return NULL;
     }
     return (UA_Node*)dtnode;
 }
 
 void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                             UA_AddNodesResult *result) {
+                             UA_AddNodesResult *result, UA_InstantiationCallback *instantiationCallback) {
     if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
        !item->nodeAttributes.content.decoded.type) {
         result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
@@ -508,19 +507,21 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_Ad
     /* add it to the server */
     UA_Server_addExistingNode(server, session, node, &item->parentNodeId.nodeId,
                               &item->referenceTypeId, result);
-    if(result->statusCode != UA_STATUSCODE_GOOD) {
-        UA_Node_deleteAnyNodeClass(node);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
-    }
-
+    
     /* instantiate if it has a type */
     if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
+        if (instantiationCallback != NULL)
+          instantiationCallback->method(result->addedNodeId, item->typeDefinition.nodeId,
+                                        instantiationCallback->handle); 
+        
         if(item->nodeClass == UA_NODECLASS_OBJECT)
             result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
-                                                       &item->typeDefinition.nodeId);
+                                                       &item->typeDefinition.nodeId, instantiationCallback);
         else if(item->nodeClass == UA_NODECLASS_VARIABLE)
             result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
-                                                         &item->typeDefinition.nodeId);
+                                                         &item->typeDefinition.nodeId, instantiationCallback);
     }
 
     /* if instantiation failed, remove the node */
@@ -574,7 +575,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
-            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i]);
+            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i], NULL);
     }
 }
 
@@ -608,7 +609,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
         return result.statusCode;
     }
 
-    UA_VariableNode *node = UA_VariableNode_new();
+    UA_VariableNode *node = UA_NodeStore_newVariableNode();
     if(!node) {
         UA_AddNodesItem_deleteMembers(&item);
         UA_VariableAttributes_deleteMembers(&attrCopy);
@@ -623,15 +624,13 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     node->historizing = attr.historizing;
     node->minimumSamplingInterval = attr.minimumSamplingInterval;
     node->valueRank = attr.valueRank;
-
+    UA_RCU_LOCK();
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
                               &item.referenceTypeId, &result);
+    UA_RCU_UNLOCK();
     UA_AddNodesItem_deleteMembers(&item);
     UA_VariableAttributes_deleteMembers(&attrCopy);
 
-    if(result.statusCode != UA_STATUSCODE_GOOD)
-        UA_VariableNode_delete(node);
-
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
         *outNewNodeId = result.addedNodeId;
     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_QualifiedName browseName, const UA_MethodAttributes attr,
                         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_AddNodesResult result;
     UA_AddNodesResult_init(&result);
@@ -667,7 +666,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
         return result.statusCode;
     }
 
-    UA_MethodNode *node = UA_MethodNode_new();
+    UA_MethodNode *node = UA_NodeStore_newMethodNode();
     if(!node) {
         result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         UA_AddNodesItem_deleteMembers(&item);
@@ -683,12 +682,12 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     UA_AddNodesItem_deleteMembers(&item);
     UA_MethodAttributes_deleteMembers(&attrCopy);
 
+    UA_RCU_LOCK();
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
                               &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;
-    }
     
     UA_ExpandedNodeId 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)
      */
     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 */
     /* 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)
-        *outNewNodeId = result.addedNodeId;
+        *outNewNodeId = result.addedNodeId; // don't deleteMember the result
     else
         UA_AddNodesResult_deleteMembers(&result);
     return result.statusCode;
@@ -853,7 +848,7 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 UA_StatusCode
 Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                            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)
         return UA_STATUSCODE_BADNODEIDINVALID;
     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++) {
             /* call the destructor */
             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);
-            if(!type)
+            if(!typenode)
                 continue;
-            if(type->nodeClass != UA_NODECLASS_OBJECTTYPE || !type->lifecycleManagement.destructor)
+            if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE || !typenode->lifecycleManagement.destructor)
                 continue;
 
             /* 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);
     }
@@ -929,7 +924,9 @@ static UA_StatusCode
 deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
                       const UA_DeleteReferencesItem *item) {
     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))
             continue;
         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);
 
         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",
                          response->securityToken.channelId, connection->sockfd);
         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);
     } else {
         response->responseHeader.serviceResult =
             UA_SecureChannelManager_renew(&server->secureChannelManager, connection, request, response);
 
         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",
                          response->securityToken.channelId, connection->sockfd);
         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);
     }
 }
 
 /* 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);
     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 =
         UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession);
 	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",
                      channel->securityToken.channelId);
 		return;
@@ -41,7 +41,7 @@ void Service_CreateSession(UA_Server *server, UA_Session *session,
         UA_SessionManager_removeSession(&server->sessionManager, server, &newSession->authenticationToken);
          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)",
                  channel->securityToken.channelId, response->sessionId.namespaceIndex,
                  response->sessionId.identifier.numeric);
@@ -58,14 +58,14 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
 
 	if(!foundSession) {
         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",
                      channel->securityToken.channelId);
         return;
 	}
 
     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",
                      channel->securityToken.channelId);
         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 ||
        (request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] &&
         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)",
                      channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                      foundSession->sessionId.identifier.numeric);
@@ -83,7 +83,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
         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)",
                  channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                  foundSession->sessionId.identifier.numeric);
@@ -99,7 +99,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
     */
 
     /* anonymous login */
-    if(server->config.Login_enableAnonymous &&
+    if(server->config.enableAnonymousLogin &&
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
         const UA_AnonymousIdentityToken *token = request->userIdentityToken.content.decoded.data;
         if(token->policyId.data && !UA_String_equal(&token->policyId, &ap)) {
@@ -115,7 +115,7 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
     }
 
     /* username login */
-    if(server->config.Login_enableUsernamePassword &&
+    if(server->config.enableUsernamePasswordLogin &&
        request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
         const UA_UserNameIdentityToken *token = request->userIdentityToken.content.decoded.data;
         if(!UA_String_equal(&token->policyId, &up)) {
@@ -128,10 +128,10 @@ Service_ActivateSession(UA_Server *server, UA_Session *session,
             return;
         }
         /* ok, trying to match the username */
-        for(size_t i = 0; i < server->config.Login_loginsCount; ++i) {
-            UA_String user = UA_STRING(server->config.Login_usernames[i]);
-            UA_String pw = UA_STRING(server->config.Login_passwords[i]);
-            if(!UA_String_equal(&token->userName, &user) || !UA_String_equal(&token->password, &pw))
+        for(size_t i = 0; i < server->config.usernamePasswordLoginsSize; i++) {
+            UA_String *user = &server->config.usernamePasswordLogins[i].username;
+            UA_String *pw = &server->config.usernamePasswordLogins[i].password;
+            if(!UA_String_equal(&token->userName, user) || !UA_String_equal(&token->password, pw))
                 continue;
             /* success - activate */
             if(foundSession->channel && foundSession->channel != channel)
@@ -152,7 +152,7 @@ void
 Service_CloseSession(UA_Server *server, UA_Session *session,
                      const UA_CloseSessionRequest *request,
                      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)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
     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 */
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
                                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) */
     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 */
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalKeepAliveCount,
                                request->requestedMaxKeepAliveCount, response->revisedMaxKeepAliveCount);
-    newSubscription->keepAliveCount = (UA_Int32_BoundedValue)  {
+    newSubscription->keepAliveCount = (UA_UInt32_BoundedValue)  {
         .minValue=session->subscriptionManager.globalKeepAliveCount.minValue,
         .maxValue=session->subscriptionManager.globalKeepAliveCount.maxValue,
         .currentValue=response->revisedMaxKeepAliveCount};
@@ -228,9 +228,9 @@ Service_Publish(UA_Server *server, UA_Session *session,
     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,
                                                                    request->subscriptionId);
     if(!sub) {
@@ -240,7 +240,7 @@ void Service_ModifySubscription(UA_Server *server, UA_Session *session,
     
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
                                request->requestedPublishingInterval, response->revisedPublishingInterval);
-    sub->publishingInterval = (UA_DateTime)response->revisedPublishingInterval;
+    sub->publishingInterval = response->revisedPublishingInterval;
     
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalLifeTimeCount,
                                request->requestedLifetimeCount, response->revisedLifetimeCount);
@@ -251,7 +251,7 @@ void Service_ModifySubscription(UA_Server *server, UA_Session *session,
         
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalKeepAliveCount,
                                 request->requestedMaxKeepAliveCount, response->revisedMaxKeepAliveCount);
-    sub->keepAliveCount = (UA_Int32_BoundedValue)  {
+    sub->keepAliveCount = (UA_UInt32_BoundedValue)  {
         .minValue=session->subscriptionManager.globalKeepAliveCount.minValue,
         .maxValue=session->subscriptionManager.globalKeepAliveCount.maxValue,
         .currentValue=response->revisedMaxKeepAliveCount};
@@ -259,6 +259,7 @@ void Service_ModifySubscription(UA_Server *server, UA_Session *session,
     sub->notificationsPerPublish = request->maxNotificationsPerPublish;
     sub->priority                = request->priority;
     
+    Subscription_unregisterUpdateJob(server, sub);
     Subscription_registerUpdateJob(server, sub);
     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);
 
     /* 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));
     if(readNodesResults[0].status == UA_STATUSCODE_GOOD)
         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(diagnosticInfos, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], 6);
     if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
-        UA_ObjectNode_delete((UA_ObjectNode*)node);
+        UA_NodeStore_deleteNode(node);
         return NULL;
     }
     return node;
@@ -153,10 +153,10 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
         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?
     do {
-        node = UA_NodeStore_get(ns, &results[index]);
+        node = UA_NodeStore_get(ns, &results[idx]);
         if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
             continue;
         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;
             }
         }
-    } while(++index <= last && retval == UA_STATUSCODE_GOOD);
+    } while(++idx <= last && retval == UA_STATUSCODE_GOOD);
 
     if(retval != UA_STATUSCODE_GOOD) {
         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? */
-    UA_UInt32 real_maxrefs = maxrefs;
+    size_t real_maxrefs = maxrefs;
     if(real_maxrefs == 0)
         real_maxrefs = node->referencesSize;
     if(node->referencesSize <= 0)
@@ -303,7 +303,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
             referencesCount++;
         }
 #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(isExternal == UA_TRUE)
         	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);
         } else {
             /* update the cp and return the cp identifier */
-            cp->continuationIndex += referencesCount;
+            cp->continuationIndex += (UA_UInt32)referencesCount;
             UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
         }
     } 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);
         cp->maxReferences = maxrefs;
-        cp->continuationIndex = referencesCount;
+        cp->continuationIndex = (UA_UInt32)referencesCount;
         UA_Guid *ident = UA_Guid_new();
         *ident = UA_Guid_random();
         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,
                     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)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
     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,
                         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)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
    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,
                                            const UA_TranslateBrowsePathsToNodeIdsRequest *request,
                                            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)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
 	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,
                            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)",
                  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,
                              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)",
                  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 {
     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_StatusCode

+ 21 - 17
src/server/ua_subscription.c

@@ -6,7 +6,7 @@
 /* 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));
     if(!new)
         return NULL;
@@ -68,7 +68,8 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
     UA_unpublishedNotification *msg;
     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;
     
     // 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
        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);
     if(retval == UA_STATUSCODE_GOOD)
         sub->timedUpdateIsRegistered = UA_TRUE;
@@ -280,9 +282,9 @@ void MonitoredItem_delete(UA_MonitoredItem *monitoredItem) {
     UA_free(monitoredItem);
 }
 
-int MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
+UA_UInt32 MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
                                                  UA_MonitoredItem *monitoredItem) {
-    int queueSize = 0;
+    UA_UInt32 queueSize = 0;
     MonitoredItem_queuedValue *queueItem;
   
     // 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)
                     break;
                 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);
                 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
-    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_DataValue_deleteMembers(&newvalue->value);
+        UA_free(newvalue);
+        return;
+    }
   
     if(!monitoredItem->lastSampledValue.data) { 
         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);
 UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, const UA_Node *src,
                                                      UA_DataValue *dst);
-int MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
-                                                 UA_MonitoredItem *monitoredItem);
+UA_UInt32 MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *dst,
+                                                       UA_MonitoredItem *monitoredItem);
 
 /****************/
 /* Subscription */
@@ -74,11 +74,11 @@ typedef struct UA_unpublishedNotification {
 typedef struct UA_Subscription {
     LIST_ENTRY(UA_Subscription) listEntry;
     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_Int32 subscriptionID;
-    UA_Int32 notificationsPerPublish;
+    UA_UInt32 subscriptionID;
+    UA_UInt32 notificationsPerPublish;
     UA_Boolean publishingMode;
     UA_UInt32 priority;
     UA_UInt32 sequenceNumber;
@@ -90,7 +90,7 @@ typedef struct UA_Subscription {
     LIST_HEAD(UA_ListOfUAMonitoredItems, UA_MonitoredItem) MonitoredItems;
 } 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 Subscription_updateNotifications(UA_Subscription *subscription);
 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
      *        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->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->globalQueueSize = (UA_UInt32_BoundedValue) { .maxValue = 100, .minValue = 0, .currentValue=0 };
     LIST_INIT(&manager->serverSubscriptions);
@@ -33,8 +33,8 @@ void SubscriptionManager_addSubscription(UA_SubscriptionManager *manager, UA_Sub
     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;
     LIST_FOREACH(sub, &manager->serverSubscriptions, listEntry) {
         if(sub->subscriptionID == subscriptionID)
@@ -43,15 +43,16 @@ UA_Subscription *SubscriptionManager_getSubscriptionByID(UA_SubscriptionManager
     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);
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
     
     UA_MonitoredItem *mon, *tmp_mon;
     LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, tmp_mon) {
-        if (mon->itemId == monitoredItemID) {
+        if(mon->itemId == monitoredItemID) {
             LIST_REMOVE(mon, listEntry);
             MonitoredItem_delete(mon);
             return UA_STATUSCODE_GOOD;
@@ -60,7 +61,9 @@ UA_Int32 SubscriptionManager_deleteMonitoredItem(UA_SubscriptionManager *manager
     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);    
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;

+ 11 - 8
src/server/ua_subscription_manager.h

@@ -8,13 +8,13 @@
 #include "ua_subscription.h"
 
 typedef struct UA_SubscriptionManager {
-    UA_Int32_BoundedValue globalPublishingInterval;
+    UA_UInt32_BoundedValue globalPublishingInterval;
     UA_UInt32_BoundedValue globalLifeTimeCount;
     UA_UInt32_BoundedValue globalKeepAliveCount;
-    UA_Int32_BoundedValue globalNotificationsPerPublish;
+    UA_UInt32_BoundedValue globalNotificationsPerPublish;
     UA_UInt32_BoundedValue globalSamplingInterval;
     UA_UInt32_BoundedValue globalQueueSize;
-    UA_Int32 lastSessionID;
+    UA_UInt32 lastSessionID;
     UA_Guid lastJobGuid;
     LIST_HEAD(UA_ListOfUASubscriptions, UA_Subscription) serverSubscriptions;
 } UA_SubscriptionManager;
@@ -22,11 +22,14 @@ typedef struct UA_SubscriptionManager {
 void SubscriptionManager_init(UA_Session *session);
 void SubscriptionManager_deleteMembers(UA_Session *session, UA_Server *server);
 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_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 delete_at = current->length-1; // garbled message after this point
     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)) &&
            msgtype != ('O' + ('P' << 8) + ('N' << 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
             break;
         }
-        UA_Int32 length = 0;
+        UA_UInt32 length = 0;
         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 */
             delete_at = pos;
             break;
@@ -129,6 +131,13 @@ UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RES
     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) {
 #ifdef UA_ENABLE_MULTITHREADING
     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) {
 #ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_cmpxchg(&channel->connection, NULL, connection) == NULL)
-        uatomic_set(&connection->channel, channel);
+        uatomic_set((void**)&connection->channel, (void*)channel);
 #else
     if(channel->connection != NULL)
         return;
@@ -153,3 +162,7 @@ void UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChann
     connection->channel = channel;
 #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_AsymmetricAlgorithmSecurityHeader_deleteMembers(&channel->clientAsymAlgSettings);
     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;
     if(c) {
         UA_Connection_detachSecureChannel(c);
@@ -50,6 +50,13 @@ UA_StatusCode UA_SecureChannel_generateNonce(UA_ByteString *nonce) {
     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) {
     struct SessionEntry *se = UA_malloc(sizeof(struct SessionEntry));
     if(!se)
@@ -70,6 +77,10 @@ void UA_SecureChannel_attachSession(UA_SecureChannel *channel, UA_Session *sessi
     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) {
     if(session)
         session->channel = NULL;
@@ -143,7 +154,7 @@ UA_StatusCode UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_U
     }
 
     /* now write the header with the size */
-    respHeader.messageHeader.messageSize = messagePos;
+    respHeader.messageHeader.messageSize = (UA_UInt32)messagePos;
 #ifndef UA_ENABLE_MULTITHREADING
     seqHeader.sequenceNumber = ++channel->sequenceNumber;
 #else

+ 0 - 14
src/ua_session.c

@@ -2,20 +2,6 @@
 #include "ua_session.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 = {
     .clientDescription =  {.applicationUri = {0, NULL}, .productUri = {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;
     UA_ByteString        identifier;
     UA_BrowseDescription browseDescription;
-    UA_Int32            continuationIndex;
+    UA_UInt32            continuationIndex;
     UA_UInt32            maxReferences;
 };
 
@@ -44,7 +44,6 @@ struct UA_Session {
     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)
 
 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;
 
 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;
     ticks2dt /= freq.QuadPart;
     return (UA_DateTime)(ticks.QuadPart * ticks2dt);
+#elif defined(__APPLE__) || defined(__MACH__) // OS X does not have clock_gettime, use clock_get_time
+    clock_serv_t cclock;
+    mach_timespec_t mts;
+    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
+    clock_get_time(cclock, &mts);
+    mach_port_deallocate(mach_task_self(), cclock);
+    return (mts.tv_sec * UA_SEC_TO_DATETIME) + (mts.tv_nsec / 100);
 #else
     struct timespec ts;
     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
@@ -86,15 +93,15 @@ UA_DateTime UA_DateTime_nowMonotonic(void) {
 #endif
 }
 
-UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
+UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime t) {
     /* Calculating the the milli-, micro- and nanoseconds */
     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> */
-    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);
     dateTimeStruct.sec    = (UA_UInt16)ts.tm_sec;
     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) {
     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;
     }
 }
 
-UA_String UA_DateTime_toString(UA_DateTime time) {
+UA_String UA_DateTime_toString(UA_DateTime t) {
     UA_String str = UA_STRING_NULL;
     // length of the string is 31 (plus \0 at the end)
     if(!(str.data = UA_malloc(32)))
         return str;
     str.length = 31;
-    UA_DateTimeStruct tSt = UA_DateTime_toStruct(time);
+    UA_DateTimeStruct tSt = UA_DateTime_toStruct(t);
     printNumber(tSt.month, str.data, 2);
     str.data[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,
                        size_t *block, size_t *stride, size_t *first) {
     /* Test the integrity of the source variant dimensions */
-    UA_UInt32 dims_count = 1;
+    size_t dims_count = 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;
     if(v->arrayDimensionsSize > 0) {
         dims_count = v->arrayDimensionsSize;

Разница между файлами не показана из-за своего большого размера
+ 624 - 386
src/ua_types_encoding_binary.c


+ 4 - 2
src/ua_types_encoding_binary.h

@@ -4,9 +4,11 @@
 #include "ua_types.h"
 
 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;
 
+size_t UA_calcSizeBinary(void *p, const UA_DataType *type);
+
 #endif /* UA_TYPES_ENCODING_BINARY_H_ */

+ 23 - 9
src/ua_util.h

@@ -44,6 +44,9 @@
 # endif
 #endif
 
+#define container_of(ptr, type, member) \
+    (type *)((uintptr_t)ptr - offsetof(type,member))
+
 /************************/
 /* Thread Local Storage */
 /************************/
@@ -77,6 +80,11 @@ int gettimeofday(struct timeval *tp, struct timezone *tzp);
 # include <sys/time.h>
 #endif
 
+#if defined(__APPLE__) || defined(__MACH__)
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
 /*************************/
 /* External Dependencies */
 /*************************/
@@ -91,22 +99,28 @@ int gettimeofday(struct timeval *tp, struct timezone *tzp);
 # include <urcu/rculfhash.h>
 # include <urcu/lfstack.h>
 # 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
-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)
-# 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)
 # endif
 #else
 # define UA_RCU_LOCK()
 # define UA_RCU_UNLOCK()
+# define UA_ASSERT_RCU_LOCKED()
+# define UA_ASSERT_RCU_UNLOCKED()
 #endif
 
 #endif /* UA_UTIL_H_ */

+ 4 - 4
examples/logger_stdout.c

@@ -6,7 +6,7 @@
 #include <stdio.h>
 #include <stdarg.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 *LogCategoryNames[6] = {"network", "channel", "session", "server", "client", "userland"};
@@ -17,9 +17,9 @@ const char *LogCategoryNames[6] = {"network", "channel", "session", "server", "c
 #endif
 
 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_start(ap, msg);
     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 <ws2tcpip.h>
 # define CLOSESOCKET(S) closesocket(S)
+# define ssize_t long
 #else
 # include <fcntl.h>
 # include <sys/select.h>
 # include <netinet/in.h>
-#ifndef __CYGWIN__
-    # include <netinet/tcp.h>
-#endif
+# ifndef __CYGWIN__
+#  include <netinet/tcp.h>
+# endif
 # include <sys/ioctl.h>
 # include <netdb.h> //gethostbyname for the client
 # include <unistd.h> // read, write, close
 # include <arpa/inet.h>
-#ifdef __QNX__
-#include <sys/socket.h>
-#endif
+# ifdef __QNX__
+#  include <sys/socket.h>
+# endif
 # define CLOSESOCKET(S) close(S)
 #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
 # include <urcu/uatomic.h>
 #endif
@@ -55,7 +71,7 @@ static UA_StatusCode
 socket_write(UA_Connection *connection, UA_ByteString *buf) {
     size_t nWritten = 0;
     while(buf->length > 0 && nWritten < (size_t)buf->length) {
-        UA_Int32 n = 0;
+        ssize_t n = 0;
         do {
 #ifdef _WIN32
             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;
             }
 #endif
-        } while (n == -1L);
-        nWritten += n;
+        } while(n == -1L);
+        nWritten += (size_t)n;
     }
     UA_ByteString_deleteMembers(buf);
     return UA_STATUSCODE_GOOD;
@@ -93,8 +109,8 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
     if(timeout > 0) {
         /* currently, only the client uses timeouts */
 #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));
 #else
         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) {
         /* server has closed the connection */
         UA_ByteString_deleteMembers(response);
@@ -128,7 +144,7 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
         }
     }
-    response->length = ret;
+    response->length = (size_t)ret;
     return UA_STATUSCODE_GOOD;
 }
 
@@ -187,16 +203,12 @@ static void FreeConnectionCallback(UA_Server *server, void *ptr) {
 #define MAXBACKLOG 100
 
 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 */
-    fd_set fdset;
     UA_Int32 serversockfd;
-    UA_Int32 highestfd;
     size_t mappingsSize;
     struct ConnectionMapping {
         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 */
-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++) {
-        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 */
-static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
+static void
+ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
 #ifdef UA_ENABLE_MULTITHREADING
     if(uatomic_xchg(&connection->state, UA_CONNECTION_CLOSED) == UA_CONNECTION_CLOSED)
         return;
@@ -244,7 +259,7 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
     connection->state = UA_CONNECTION_CLOSED;
 #endif
     ServerNetworkLayerTCP *layer = connection->handle;
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Closing the Connection %i",
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "Closing the Connection %i",
                 connection->sockfd);
     /* only "shutdown" here. this triggers the select, where the socket is
        "closed" in the mainloop */
@@ -252,7 +267,8 @@ static void ServerNetworkLayerTCP_closeConnection(UA_Connection *connection) {
 }
 
 /* call only from the single networking thread */
-static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
+static UA_StatusCode
+ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_Int32 newsockfd) {
     UA_Connection *c = malloc(sizeof(UA_Connection));
     if(!c)
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -260,7 +276,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     struct sockaddr_in addr;
     socklen_t addrlen = sizeof(struct sockaddr_in);
     getsockname(newsockfd, (struct sockaddr*)&addr, &addrlen);
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "New Connection %i over TCP from %s:%d",
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "New Connection %i over TCP from %s:%d",
                 newsockfd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
     UA_Connection_init(c);
     c->sockfd = newsockfd;
@@ -275,7 +291,7 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     struct ConnectionMapping *nm;
     nm = realloc(layer->mappings, sizeof(struct ConnectionMapping)*(layer->mappingsSize+1));
     if(!nm) {
-        UA_LOG_ERROR(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "No memory for a new Connection");
+        UA_LOG_ERROR(layer->logger, UA_LOGCATEGORY_NETWORK, "No memory for a new Connection");
         free(c);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
@@ -285,17 +301,35 @@ static UA_StatusCode ServerNetworkLayerTCP_add(ServerNetworkLayerTCP *layer, UA_
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, UA_Logger logger) {
-    layer->layer.logger = logger;
+static UA_StatusCode
+ServerNetworkLayerTCP_start(UA_ServerNetworkLayer *nl, 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
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM,0)) == (UA_Int32)INVALID_SOCKET) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error opening socket, code: %d",
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket, code: %d",
                        WSAGetLastError());
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 #else
     if((layer->serversockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error opening socket");
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 #endif
@@ -305,37 +339,39 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, U
     int optval = 1;
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
                   SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK,
                        "Error during setting of socket options");
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     if(bind(layer->serversockfd, (const struct sockaddr *)&serv_addr,
             sizeof(serv_addr)) < 0) {
-        UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "Error during socket binding");
+        UA_LOG_WARNING(layer->logger, UA_LOGCATEGORY_NETWORK, "Error during socket binding");
         CLOSESOCKET(layer->serversockfd);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     socket_set_nonblocking(layer->serversockfd);
     listen(layer->serversockfd, MAXBACKLOG);
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK, "TCP network layer listening on %.*s",
-                layer->layer.discoveryUrl.length, layer->layer.discoveryUrl.data);
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK, "TCP network layer listening on %.*s",
+                nl->discoveryUrl.length, nl->discoveryUrl.data);
     return UA_STATUSCODE_GOOD;
 }
 
 static size_t
-ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UInt16 timeout) {
-    setFDSet(layer);
+ServerNetworkLayerTCP_getJobs(UA_ServerNetworkLayer *nl, UA_Job **jobs, UA_UInt16 timeout) {
+    ServerNetworkLayerTCP *layer = nl->handle;
+    fd_set fdset;
+    UA_Int32 highestfd = setFDSet(layer, &fdset);
     struct timeval tmptv = {0, timeout};
     UA_Int32 resultsize;
-    resultsize = select(layer->highestfd+1, &layer->fdset, NULL, NULL, &tmptv);
+    resultsize = select(highestfd+1, &fdset, NULL, NULL, &tmptv);
     if(resultsize < 0) {
         *jobs = NULL;
         return 0;
     }
 
     /* accept new connections (can only be a single one) */
-    if(FD_ISSET(layer->serversockfd, &layer->fdset)) {
+    if(fd_isset(layer->serversockfd, &fdset)) {
         resultsize--;
         struct sockaddr_in cli_addr;
         socklen_t cli_len = sizeof(cli_addr);
@@ -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 */
     if(resultsize == 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)
         return 0;
 
@@ -359,7 +395,7 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
     size_t j = 0;
     UA_ByteString buf = UA_BYTESTRING_NULL;
     for(size_t i = 0; i < layer->mappingsSize && j < (size_t)resultsize; i++) {
-        if(!(FD_ISSET(layer->mappings[i].sockfd, &layer->fdset)))
+        if(!fd_isset(layer->mappings[i].sockfd, &fdset))
             continue;
         UA_StatusCode retval = socket_recv(layer->mappings[i].connection, &buf, 0);
         if(retval == UA_STATUSCODE_GOOD) {
@@ -399,8 +435,9 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
 }
 
 static size_t
-ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
-    UA_LOG_INFO(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
+ServerNetworkLayerTCP_stop(UA_ServerNetworkLayer *nl, UA_Job **jobs) {
+    ServerNetworkLayerTCP *layer = nl->handle;
+    UA_LOG_INFO(layer->logger, UA_LOGCATEGORY_NETWORK,
                 "Shutting down the TCP network layer with %d open connection(s)", layer->mappingsSize);
     shutdown(layer->serversockfd,2);
     CLOSESOCKET(layer->serversockfd);
@@ -423,43 +460,37 @@ ServerNetworkLayerTCP_stop(ServerNetworkLayerTCP *layer, UA_Job **jobs) {
 }
 
 /* run only when the server is stopped */
-static void ServerNetworkLayerTCP_deleteMembers(ServerNetworkLayerTCP *layer) {
+static void ServerNetworkLayerTCP_deleteMembers(UA_ServerNetworkLayer *nl) {
+    ServerNetworkLayerTCP *layer = nl->handle;
     free(layer->mappings);
+    free(layer);
+    UA_String_deleteMembers(&nl->discoveryUrl);
 }
 
-UA_ServerNetworkLayer * ServerNetworkLayerTCP_new(UA_ConnectionConfig conf, UA_UInt32 port) {
+UA_ServerNetworkLayer
+UA_ServerNetworkLayerTCP(UA_ConnectionConfig conf, UA_UInt16 port) {
 #ifdef _WIN32
     WORD wVersionRequested;
     WSADATA wsaData;
     wVersionRequested = MAKEWORD(2, 2);
     WSAStartup(wVersionRequested, &wsaData);
 #endif
-    ServerNetworkLayerTCP *layer = malloc(sizeof(ServerNetworkLayerTCP));
+
+    UA_ServerNetworkLayer nl;
+    memset(&nl, 0, sizeof(UA_ServerNetworkLayer));
+    ServerNetworkLayerTCP *layer = calloc(1,sizeof(ServerNetworkLayerTCP));
     if(!layer)
-        return NULL;
-    memset(layer, 0, sizeof(ServerNetworkLayerTCP));
+        return nl;
+    
     layer->conf = conf;
-    layer->mappingsSize = 0;
-    layer->mappings = NULL;
     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 */
 UA_Connection
-ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) {
+UA_ClientConnectionTCP(UA_ConnectionConfig localConf, const char *endpointUrl, UA_Logger logger) {
     UA_Connection connection;
     UA_Connection_init(&connection);
     connection.localConf = localConf;
@@ -524,12 +555,8 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpoin
         if(endpointUrl[portpos] == ':') {
             char *endPtr = NULL;
             unsigned long int tempulong = strtoul(&endpointUrl[portpos+1], &endPtr, 10);
-            if (ERANGE != errno &&
-                tempulong < UINT16_MAX &&
-                endPtr != &endpointUrl[portpos+1])
-            {
+            if (ERANGE != errno && tempulong < UINT16_MAX && endPtr != &endpointUrl[portpos+1])
                 port = (UA_UInt16)tempulong;
-            }
             break;
         }
     }
@@ -561,7 +588,7 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpoin
     }
     struct sockaddr_in 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_port = htons(port);
     connection.state = UA_CONNECTION_OPENING;

+ 3 - 2
examples/networklayer_tcp.h

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

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)
 endif()
 
+add_definitions(-Wno-sign-conversion)
+
 # 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
 

+ 19 - 5
tests/check_builtin.c

@@ -27,6 +27,7 @@ START_TEST(UA_Byte_decodeShallCopyAndAdvancePosition) {
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     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);
 }
 END_TEST
@@ -297,6 +298,7 @@ START_TEST(UA_String_decodeShallAllocateMemoryAndCopyString) {
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(dst.length, 8);
     ck_assert_int_eq(dst.data[3], 'L');
+    ck_assert_uint_eq(pos, UA_calcSizeBinary(&dst, &UA_TYPES[UA_TYPES_STRING]));
     // finally
     UA_String_deleteMembers(&dst);
 }
@@ -345,6 +347,7 @@ START_TEST(UA_NodeId_decodeTwoByteShallReadTwoBytesAndSetNamespaceToZero) {
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     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.identifier.numeric, 16);
     ck_assert_int_eq(dst.namespaceIndex, 0);
@@ -362,6 +365,7 @@ START_TEST(UA_NodeId_decodeFourByteShallReadFourBytesAndRespectNamespace) {
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     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.identifier.numeric, 256);
     ck_assert_int_eq(dst.namespaceIndex, 1);
@@ -379,6 +383,7 @@ START_TEST(UA_NodeId_decodeStringShallAllocateMemory) {
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     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.namespaceIndex, 1);
     ck_assert_int_eq(dst.identifier.string.length, 3);
@@ -391,14 +396,15 @@ END_TEST
 START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
     // given
     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_Variant dst;
     // when
     UA_StatusCode retval = UA_Variant_decodeBinary(&src, &pos, &dst);
     // then
     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_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
     ck_assert_int_eq(dst.arrayLength, 0);
@@ -412,7 +418,8 @@ END_TEST
 START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray) {
     // given
     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 };
     UA_ByteString src = { 13, data };
@@ -422,6 +429,7 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     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_int_eq((uintptr_t)dst.type,(uintptr_t)&UA_TYPES[UA_TYPES_INT32]);
     ck_assert_int_eq(dst.arrayLength, 2);
@@ -491,7 +499,8 @@ END_TEST
 START_TEST(UA_Variant_decodeWithOutDeleteMembersShallFailInCheckMem) {
     // given
     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 };
     UA_ByteString src = { 13, data };
     UA_Variant dst;
@@ -507,7 +516,8 @@ END_TEST
 START_TEST(UA_Variant_decodeWithTooSmallSourceShallReturnWithError) {
     // given
     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 };
     UA_ByteString src = { 4, data };
 
@@ -862,6 +872,7 @@ START_TEST(UA_String_encodeShallWorkOnExample) {
     retval = UA_String_encodeBinary(&src, &dst, &pos);
     // then
     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[sizeof(UA_Int32)+0], 'A');
     ck_assert_int_eq(dst.data[sizeof(UA_Int32)+1], 'C');
@@ -891,6 +902,7 @@ START_TEST(UA_ExpandedNodeId_encodeShallWorkOnExample) {
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     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
 }
 END_TEST
@@ -914,6 +926,7 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithoutVariant) {
     retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
     // then
     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[1], 80);   // 8 Byte serverTimestamp
     ck_assert_int_eq(dst.data[2], 0);
@@ -951,6 +964,7 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
     retval = UA_DataValue_encodeBinary(&src, &dst, &pos);
     // then
     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[1], 0x06);        // Variant's Encoding Mask - INT32
     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
 
+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 number_failed = 0;
 	SRunner *sr;
@@ -199,6 +215,9 @@ int main(void) {
 	tcase_add_loop_test(tc, decodeComplexTypeFromRandomBufferShallSurvive, UA_TYPES_NODEID, UA_TYPES_COUNT - 1);
 	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);
 	srunner_set_fork_status(sr, CK_NOFORK);
 	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) {
-	UA_Node *p = (UA_Node *)UA_VariableNode_new();
+	UA_Node *p = (UA_Node *)UA_NodeStore_newVariableNode();
 	p->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
 	p->nodeId.namespaceIndex = nsid;
 	p->nodeId.identifier.numeric = id;
@@ -35,10 +35,10 @@ static UA_Node* createNode(UA_Int16 nsid, UA_Int32 id) {
 START_TEST(replaceExistingNode) {
 	UA_NodeStore *ns = UA_NodeStore_new();
 	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);
     
@@ -46,16 +46,22 @@ START_TEST(replaceExistingNode) {
 }
 END_TEST
 
-START_TEST(replaceNonExistingNode) {
+START_TEST(replaceOldNode) {
 	UA_NodeStore *ns = UA_NodeStore_new();
 	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);
     
-    UA_VariableNode_delete((UA_VariableNode*)n1);
-    UA_VariableNode_delete((UA_VariableNode*)n2);
 	UA_NodeStore_delete(ns);
 }
 END_TEST
@@ -66,12 +72,12 @@ START_TEST(findNodeInUA_NodeStoreWithSingleEntry) {
 #endif
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
-    UA_MT_CONST UA_Node *inserted;
 	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
-	ck_assert_int_eq((uintptr_t)inserted, (uintptr_t)nr);
+	ck_assert_int_eq((uintptr_t)n1, (uintptr_t)nr);
 	// finally
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
@@ -88,15 +94,14 @@ START_TEST(failToFindNodeInOtherUA_NodeStore) {
 	UA_NodeStore *ns = UA_NodeStore_new();
 
 	UA_Node* n1 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 
 	// 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
 	ck_assert_int_eq((uintptr_t)nr, 0);
 	// finally
-	UA_VariableNode_delete((UA_VariableNode*)n);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
@@ -111,23 +116,23 @@ START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 	UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n2, NULL);
+    UA_NodeStore_insert(ns, n2);
 	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_NodeStore_insert(ns, n4, NULL);
+    UA_NodeStore_insert(ns, n4);
 	UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, n5, NULL);
+    UA_NodeStore_insert(ns, n5);
 	UA_Node* n6 = createNode(0,12);
-    UA_NodeStore_insert(ns, n6, NULL);
+    UA_NodeStore_insert(ns, n6);
 
 	// 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
-	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)inserted);
+	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)n3);
 	// finally
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
@@ -143,17 +148,17 @@ START_TEST(iterateOverUA_NodeStoreShallNotVisitEmptyNodes) {
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 	UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n2, NULL);
+    UA_NodeStore_insert(ns, n2);
 	UA_Node* n3 = createNode(0,2257);
-    UA_NodeStore_insert(ns, n3, NULL);
+    UA_NodeStore_insert(ns, n3);
 	UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, n4, NULL);
+    UA_NodeStore_insert(ns, n4);
 	UA_Node* n5 = createNode(0,1);
-    UA_NodeStore_insert(ns, n5, NULL);
+    UA_NodeStore_insert(ns, n5);
 	UA_Node* n6 = createNode(0,12);
-    UA_NodeStore_insert(ns, n6, NULL);
+    UA_NodeStore_insert(ns, n6);
 
 	// when
 	zeroCnt = 0;
@@ -180,7 +185,7 @@ START_TEST(findNodeInExpandedNamespace) {
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, n, NULL);
+        UA_NodeStore_insert(ns, n);
 	}
 	// when
 	UA_Node *n2 = createNode(0,25);
@@ -188,7 +193,7 @@ START_TEST(findNodeInExpandedNamespace) {
 	// then
 	ck_assert_int_eq(nr->nodeId.identifier.numeric,n2->nodeId.identifier.numeric);
 	// finally
-	UA_free((void*)n2);
+    UA_NodeStore_deleteNode(n2);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
@@ -206,7 +211,7 @@ START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, n, NULL);
+        UA_NodeStore_insert(ns, n);
 	}
 	// when
 	zeroCnt = 0;
@@ -230,23 +235,23 @@ START_TEST(failToFindNonExistantNodeInUA_NodeStoreWithSeveralEntries) {
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
-    UA_NodeStore_insert(ns, n1, NULL);
+    UA_NodeStore_insert(ns, n1);
 	UA_Node* n2 = createNode(0,2255);
-    UA_NodeStore_insert(ns, n2, NULL);
+    UA_NodeStore_insert(ns, n2);
 	UA_Node* n3 = createNode(0,2257);
-    UA_NodeStore_insert(ns, n3, NULL);
+    UA_NodeStore_insert(ns, n3);
 	UA_Node* n4 = createNode(0,2200);
-    UA_NodeStore_insert(ns, n4, NULL);
+    UA_NodeStore_insert(ns, n4);
 	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
-	const UA_Node* nr = UA_NodeStore_get(ns, &n6->nodeId);
+	const UA_Node* nr = UA_NodeStore_get(ns, &id);
 	// then
 	ck_assert_int_eq((uintptr_t)nr, 0);
 	// finally
-	UA_free((void *)n6);
 	UA_NodeStore_delete(ns);
 #ifdef UA_ENABLE_MULTITHREADING
 	rcu_unregister_thread();
@@ -295,7 +300,7 @@ START_TEST(profileGetDelete) {
 	UA_Node *n;
 	for (int i=0; i<N; i++) {
 		n = createNode(0,i);
-        UA_NodeStore_insert(ns, n, NULL);
+        UA_NodeStore_insert(ns, n);
 	}
 	clock_t begin, end;
 	begin = clock();
@@ -345,7 +350,7 @@ static Suite * namespace_suite (void) {
 
 	TCase *tc_replace = tcase_create("Replace");
 	tcase_add_test (tc_replace, replaceExistingNode);
-	tcase_add_test (tc_replace, replaceNonExistingNode);
+	tcase_add_test (tc_replace, replaceOldNode);
 	suite_add_tcase (s, tc_replace);
 
 	TCase* tc_iterate = tcase_create ("Iterate");
@@ -365,7 +370,7 @@ int main (void) {
 	int number_failed = 0;
 	Suite *s = namespace_suite();
 	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);
 	number_failed += srunner_ntests_failed (sr);
 	srunner_free(sr);

+ 46 - 10
tests/check_services_attributes.c

@@ -17,6 +17,15 @@
 #include <urcu.h>
 #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) {
     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_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
 	
     /* DataSource VariableNode */
     UA_VariableAttributes_init(&vattr);
@@ -47,8 +56,17 @@ static UA_Server* makeTestSequence(void) {
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
 					UA_QUALIFIEDNAME(1, "cpu temperature"),
                                         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 */
     UA_VariableAttributes_init(&vattr);
     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);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, vattr, NULL);
+                              UA_NODEID_NULL, vattr, NULL, NULL);
 
     /* ObjectNode */
     UA_ObjectAttributes obj_attr;
@@ -75,7 +93,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                             UA_QUALIFIEDNAME(1, "Demo"),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
-                            obj_attr, NULL);
+                            obj_attr, NULL, NULL);
 
     /* ViewNode */
     UA_ViewAttributes view_attr;
@@ -85,7 +103,7 @@ static UA_Server* makeTestSequence(void) {
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL);
+                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL, NULL);
 
 #ifdef UA_ENABLE_METHODCALLS
 	/* MethodNode */
@@ -104,7 +122,7 @@ static UA_Server* makeTestSequence(void) {
 }
 
 static UA_VariableNode* makeCompareSequence(void) {
-	UA_VariableNode *node = UA_VariableNode_new();
+	UA_VariableNode *node = UA_NodeStore_newVariableNode();
 
 	UA_Int32 myInteger = 42;
 	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_ReadRequest_deleteMembers(&rReq);
     UA_DataValue_deleteMembers(&resp);
-    UA_VariableNode_delete(compNode);
+    UA_NodeStore_deleteNode((UA_Node*)compNode);
 } END_TEST
 
 START_TEST(ReadSingleAttributeDescriptionWithoutTimestamp) {
@@ -266,7 +284,7 @@ START_TEST(ReadSingleAttributeDescriptionWithoutTimestamp) {
     ck_assert(UA_String_equal(&compNode->description.text, &respval->text));
     UA_ReadRequest_deleteMembers(&rReq);
     UA_DataValue_deleteMembers(&resp);
-    UA_VariableNode_delete(compNode);
+    UA_NodeStore_deleteNode((UA_Node*)compNode);
     UA_Server_delete(server);
 } END_TEST
 
@@ -527,7 +545,7 @@ START_TEST(ReadSingleAttributeMinimumSamplingIntervalWithoutTimestamp) {
     ck_assert(*respval == comp);
     UA_DataValue_deleteMembers(&resp);
     UA_ReadRequest_deleteMembers(&rReq);
-    UA_VariableNode_delete(compNode);
+    UA_NodeStore_deleteNode((UA_Node*)compNode);
     UA_Server_delete(server);
 } END_TEST
 
@@ -592,6 +610,23 @@ START_TEST(ReadSingleAttributeUserExecutableWithoutTimestamp) {
 #endif
 } 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) {
     UA_Server *server = makeTestSequence();
     UA_DataValue resp;
@@ -1028,7 +1063,8 @@ static Suite * testSuite_services_attributes(void) {
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeHistorizingWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeExecutableWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeUserExecutableWithoutTimestamp);
-	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeValueWithoutTimestamp);
+        tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestampFromBrokenSource);
+        tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeValueWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeDataTypeWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleDataSourceAttributeArrayDimensionsWithoutTimestamp);
 

+ 32 - 3
tests/check_services_nodemanagement.c

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

+ 3 - 3
tools/pyUANamespace/open62541_MacroHelper.py

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

+ 3 - 3
tools/pyUANamespace/ua_builtin_types.py

@@ -363,7 +363,7 @@ class opcua_value_t():
         else:
           for v in self.value:
             code.append(valueName + "[" + str(self.value.index(v)) + "] = " + v.printOpen62541CCode_SubType() + ";")
-        code.append("UA_Variant_setArrayCopy( &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() + "]);")
     else:
       # 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() + "];")
         if self.value[0].__binTypeId__ == BUILTINTYPE_TYPEID_EXTENSIONOBJECT:
           code.append("UA_" + self.value[0].stringRepresentation + " *" + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy( &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.
           code.append("UA_" + self.value[0].stringRepresentation + "_deleteMembers(" + valueName + ");")
         else:
           code.append("UA_" + self.value[0].stringRepresentation + " " + valueName + " = " + self.value[0].printOpen62541CCode_SubType() + ";")
-          code.append("UA_Variant_setScalarCopy( &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 + ");")
     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 + 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("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
     # 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)
           return code
     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
   
   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()) + ";")
     # The variant is guaranteed to exist by SubtypeEarly()
     code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
+    code.append(self.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
     return code
 
 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)
           return code
     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
   
   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()
     code.append(self.getCodePrintableID() + "->value.variant.value = *" + self.getCodePrintableID() + "_variant;")
+    code.append(self.getCodePrintableID() + "->valueSource = UA_VALUESOURCE_VARIANT;")
     return code
 
 class opcua_node_dataType_t(opcua_node_t):