瀏覽代碼

Merge pull request #461 from acplt/unsigned_array_size

Merge unsigned_array_size branch
Julius Pfrommer 9 年之前
父節點
當前提交
2f4a056607
共有 50 個文件被更改,包括 3096 次插入4259 次删除
  1. 3 0
      CMakeLists.txt
  2. 21 10
      README.md
  3. 40 3
      doc/datatypes.rst
  4. 2 2
      examples/CMakeLists.txt
  5. 10 10
      examples/client.c
  6. 5 5
      examples/client_firstSteps.c
  7. 2 2
      examples/logger_stdout.c
  8. 32 16
      examples/networklayer_tcp.c
  9. 16 28
      examples/server.c
  10. 3 3
      examples/server_method.c
  11. 21 20
      examples/server_readspeed.c
  12. 21 5
      include/ua_connection.h
  13. 3 6
      include/ua_server.h
  14. 315 490
      include/ua_types.h
  15. 65 33
      src/client/ua_client.c
  16. 43 55
      src/client/ua_client_highlevel.c
  17. 41 44
      src/client/ua_client_highlevel_subscriptions.c
  18. 36 68
      src/server/ua_nodes.c
  19. 5 4
      src/server/ua_nodes.h
  20. 79 164
      src/server/ua_nodestore.c
  21. 16 12
      src/server/ua_nodestore.h
  22. 65 138
      src/server/ua_nodestore_concurrent.c
  23. 36 49
      src/server/ua_securechannel_manager.c
  24. 134 153
      src/server/ua_server.c
  25. 13 9
      src/server/ua_server_binary.c
  26. 1 8
      src/server/ua_server_internal.h
  27. 2 0
      src/server/ua_server_worker.c
  28. 3 3
      src/server/ua_services.h
  29. 107 87
      src/server/ua_services_attribute.c
  30. 93 103
      src/server/ua_services_call.c
  31. 4 5
      src/server/ua_services_discovery.c
  32. 197 198
      src/server/ua_services_nodemanagement.c
  33. 77 62
      src/server/ua_services_session.c
  34. 33 31
      src/server/ua_services_subscription.c
  35. 62 119
      src/server/ua_services_view.c
  36. 43 96
      src/server/ua_subscription.c
  37. 5 9
      src/server/ua_subscription.h
  38. 66 58
      src/ua_connection.c
  39. 1 0
      src/ua_securechannel.c
  40. 1 1
      src/ua_securechannel.h
  41. 8 8
      src/ua_session.c
  42. 338 587
      src/ua_types.c
  43. 716 831
      src/ua_types_encoding_binary.c
  44. 3 75
      src/ua_types_encoding_binary.h
  45. 18 1
      src/ua_util.h
  46. 148 464
      tests/check_builtin.c
  47. 13 11
      tests/check_memory.c
  48. 6 16
      tests/check_nodestore.c
  49. 69 72
      tests/check_services_attributes.c
  50. 55 85
      tools/generate_datatypes.py

+ 3 - 0
CMakeLists.txt

@@ -426,6 +426,9 @@ if(BUILD_EXAMPLES)
 	add_executable(server_datasource ${PROJECT_SOURCE_DIR}/examples/server_datasource.c $<TARGET_OBJECTS:open62541-object>)
 	add_executable(server_datasource ${PROJECT_SOURCE_DIR}/examples/server_datasource.c $<TARGET_OBJECTS:open62541-object>)
 	target_link_libraries(server_datasource ${LIBS})
 	target_link_libraries(server_datasource ${LIBS})
 
 
+	# add_executable(server_readspeed ${PROJECT_SOURCE_DIR}/examples/server_readspeed.c $<TARGET_OBJECTS:open62541-object>)
+	# target_link_libraries(server_readspeed ${LIBS})
+
 	add_executable(server_firstSteps ${PROJECT_SOURCE_DIR}/examples/server_firstSteps.c $<TARGET_OBJECTS:open62541-object>)
 	add_executable(server_firstSteps ${PROJECT_SOURCE_DIR}/examples/server_firstSteps.c $<TARGET_OBJECTS:open62541-object>)
 	target_link_libraries(server_firstSteps ${LIBS})
 	target_link_libraries(server_firstSteps ${LIBS})
 
 

+ 21 - 10
README.md

@@ -56,16 +56,24 @@ int main(int argc, char** argv)
         ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
         ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, PORT));
 
 
     /* add a variable node */
     /* add a variable node */
-    UA_Variant *myIntegerVariant = UA_Variant_new();
+    /* 1) set the variable attributes */
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
-    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
+    UA_Variant_setScalarCopy(&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");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName, myIntegerBrowseName,
-                              0, 0, parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
+    UA_NodeId variableType = UA_NODEID_NULL; /* no variable type defined */
+    UA_QualifiedName browseName = UA_QUALIFIEDNAME(1, "the answer");
+
+    /* 3) add the variable */
+    UA_Server_addVariableNode(server, newNodeId, parentNodeId,
+                              parentReferenceNodeId, browseName,
+                              variableType, attr, NULL);
 
 
     /* run the server loop */
     /* run the server loop */
     UA_StatusCode retval = UA_Server_run(server, WORKER_THREADS, &running);
     UA_StatusCode retval = UA_Server_run(server, WORKER_THREADS, &running);
@@ -81,6 +89,7 @@ int main(int argc, char** argv)
 
 
 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_Client *client = UA_Client_new(UA_ClientConfig_standard, Logger_Stdout_new());
     UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
     UA_StatusCode retval = UA_Client_connect(client, ClientNetworkLayerTCP_connect,
                                              "opc.tcp://localhost:16664");
                                              "opc.tcp://localhost:16664");
@@ -89,16 +98,18 @@ int main(int argc, char *argv[])
     	return retval;
     	return retval;
     }
     }
 
 
-    /* Read a node's value-attribute */
+    /* create a readrequest with one entry */
     UA_ReadRequest req;
     UA_ReadRequest req;
     UA_ReadRequest_init(&req);
     UA_ReadRequest_init(&req);
     req.nodesToRead = UA_ReadValueId_new();
     req.nodesToRead = UA_ReadValueId_new();
     req.nodesToReadSize = 1;
     req.nodesToReadSize = 1;
-    /* copy the nodeid-string to the heap (deleted with the req) */
+    
+    /* define the node and attribute to be read */
     req.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     req.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     req.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     req.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
 
 
-    UA_ReadResponse resp = UA_Client_read(client, &req);
+    /* call the service and print the result */
+    UA_ReadResponse resp = UA_Client_Service_read(client, req);
     if(resp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
     if(resp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
        resp.resultsSize > 0 && resp.results[0].hasValue &&
        resp.resultsSize > 0 && resp.results[0].hasValue &&
        UA_Variant_isScalar(&resp.results[0].value) &&
        UA_Variant_isScalar(&resp.results[0].value) &&

+ 40 - 3
doc/datatypes.rst

@@ -1,8 +1,45 @@
-Data Types
-==========
+Data Types Introduction
+=======================
+In open62541, all data types share the same basic API for creation, copying and deletion. Assume that *T* is the data type in question.
+
+void T_init(T *ptr)
+  Initialize the data type. This is synonymous with zeroing out the memory, i.e. *memset(dataptr, 0, sizeof(T))*.
+T* T_new()
+  Allocate and return the memory for the data type. The memory is already initialized.
+UA_StatusCode T_copy(const T *src, T *dst)
+  Copy the content of the data type. Returns *UA_STATUSCODE_GOOD* if it succeeded.
+void T_deleteMembers(T *ptr)
+  Delete the dynamically allocated content of the data type, but not the data type itself.
+void T_delete(T *ptr)
+  Delete the content of the data type and the memory for the data type itself.
+
+Here's a small example for the UA_String data type. UA_String will be introduced in more detail later on, but you should be able to follow the example already.
+
+.. code-block:: c
+
+  /* The definition of UA_String copied from ua_types.h */ 
+  typedef struct {
+      size_t length; ///< The length of the string
+      UA_Byte *data; ///< The string's content (not null-terminated)
+  } UA_String;
+
+  UA_String s1 = UA_STRING("test1");       /* s1 points to the statically allocated string buffer */
+  UA_String_init(&s1);                     /* Reset s1 (no memleak due to the statically allocated buffer) */
+  
+  UA_String s2 = UA_STRING_ALLOC("test2"); /* s2 points to a new copy of the string buffer (with malloc) */
+  UA_String_deleteMembers(&s2);            /* Free the content of s2, but not s2 itself */
+  
+  UA_String *s3 = UA_String_new();         /* The string s3 is malloced and initialized */
+  *s3 = UA_STRING_ALLOC("test3");          /* s3 points to a new copy of the string buffer */
+  
+  UA_String s4;
+  UA_copy(s3, &s4);                        /* Copy the content of s3 to s4 */
+  
+  UA_String_delete(s3);                    /* Free the string buffer and the string itself */
+  UA_String_deleteMembers(&s4);            /* Again, delete only the string buffer */
 
 
 Generic Data Type Handling
 Generic Data Type Handling
---------------------------
+==========================
 
 
 All data types are combinations of the 25 builtin data types show below. Types
 All data types are combinations of the 25 builtin data types show below. Types
 are described in the UA_DataType structure.
 are described in the UA_DataType structure.

+ 2 - 2
examples/CMakeLists.txt

@@ -14,8 +14,8 @@ if(ENABLE_MULTITHREADING)
     list(APPEND LIBS urcu-cds urcu urcu-common)
     list(APPEND LIBS urcu-cds urcu urcu-common)
 endif(ENABLE_MULTITHREADING)
 endif(ENABLE_MULTITHREADING)
 
 
-add_executable(server_readspeed server_readspeed.c)
-target_link_libraries(server_readspeed ${LIBS})
+# add_executable(server_readspeed server_readspeed.c)
+# target_link_libraries(server_readspeed ${LIBS})
 
 
 add_executable(server_variable server_variable.c)
 add_executable(server_variable server_variable.c)
 target_link_libraries(server_variable ${LIBS})
 target_link_libraries(server_variable ${LIBS})

+ 10 - 10
examples/client.c

@@ -14,8 +14,7 @@
 
 
 #include <stdio.h>
 #include <stdio.h>
 
 
-void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value);
-void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value) {
+static void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value) {
     printf("The Answer has changed!\n");
     printf("The Answer has changed!\n");
     return;
     return;
 }
 }
@@ -42,18 +41,19 @@ int main(int argc, char *argv[]) {
 
 
     UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
     UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
     printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
     printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
-    for (int i = 0; i < bResp.resultsSize; ++i) {
-        for (int j = 0; j < bResp.results[i].referencesSize; ++j) {
+    for (size_t i = 0; i < bResp.resultsSize; ++i) {
+        for (size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
             UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
             UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
             if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) {
             if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) {
                 printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
                 printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
-                       ref->nodeId.nodeId.identifier.numeric, ref->browseName.name.length,
-                       ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data);
+                       ref->nodeId.nodeId.identifier.numeric, (int)ref->browseName.name.length,
+                       ref->browseName.name.data, (int)ref->displayName.text.length,
+                       ref->displayName.text.data);
             } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) {
             } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) {
                 printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
                 printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
-                       ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data,
-                       ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length,
-                       ref->displayName.text.data);
+                       (int)ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data,
+                       (int)ref->browseName.name.length, ref->browseName.name.data,
+                       (int)ref->displayName.text.length, ref->displayName.text.data);
             }
             }
             //TODO: distinguish further types
             //TODO: distinguish further types
         }
         }
@@ -149,7 +149,7 @@ int main(int argc, char *argv[]) {
                             UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
                             UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
     if(retval == UA_STATUSCODE_GOOD) {
     if(retval == UA_STATUSCODE_GOOD) {
         printf("Method call was successfull, and %i returned values available.\n", outputSize);
         printf("Method call was successfull, and %i returned values available.\n", outputSize);
-        UA_Array_delete(output, &UA_TYPES[UA_TYPES_VARIANT], outputSize);
+        UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
     } else {
     } else {
         printf("Method call was unsuccessfull, and %x returned values available.\n", retval);
         printf("Method call was unsuccessfull, and %x returned values available.\n", retval);
     }
     }

+ 5 - 5
examples/client_firstSteps.c

@@ -22,11 +22,11 @@ int main(void) {
 
 
     //variables to store data
     //variables to store data
     UA_DateTime raw_date = 0;
     UA_DateTime raw_date = 0;
-    UA_String* string_date = UA_String_new();
+    UA_String string_date;
 
 
     UA_ReadRequest rReq;
     UA_ReadRequest rReq;
     UA_ReadRequest_init(&rReq);
     UA_ReadRequest_init(&rReq);
-    rReq.nodesToRead = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], 1);
+    rReq.nodesToRead = UA_Array_new(1, &UA_TYPES[UA_TYPES_READVALUEID]);
     rReq.nodesToReadSize = 1;
     rReq.nodesToReadSize = 1;
     rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
     rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
@@ -38,13 +38,13 @@ int main(void) {
             rResp.results[0].value.type == &UA_TYPES[UA_TYPES_DATETIME]) {
             rResp.results[0].value.type == &UA_TYPES[UA_TYPES_DATETIME]) {
         raw_date = *(UA_DateTime*)rResp.results[0].value.data;
         raw_date = *(UA_DateTime*)rResp.results[0].value.data;
         printf("raw date is: %" PRId64 "\n", raw_date);
         printf("raw date is: %" PRId64 "\n", raw_date);
-        UA_DateTime_toString(raw_date, string_date);
-        printf("string date is: %.*s\n", string_date->length, string_date->data);
+        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_ReadRequest_deleteMembers(&rReq);
     UA_ReadResponse_deleteMembers(&rResp);
     UA_ReadResponse_deleteMembers(&rResp);
-    UA_String_delete(string_date);
+    UA_String_deleteMembers(&string_date);
 
 
     UA_Client_disconnect(client);
     UA_Client_disconnect(client);
     UA_Client_delete(client);
     UA_Client_delete(client);

+ 2 - 2
examples/logger_stdout.c

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

+ 32 - 16
examples/networklayer_tcp.c

@@ -86,14 +86,21 @@ static UA_StatusCode
 socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
 socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeout) {
     response->data = malloc(connection->localConf.recvBufferSize);
     response->data = malloc(connection->localConf.recvBufferSize);
     if(!response->data) {
     if(!response->data) {
-        response->length = -1;
+        response->length = 0;
         return UA_STATUSCODE_BADOUTOFMEMORY; /* not enough memory retry */
         return UA_STATUSCODE_BADOUTOFMEMORY; /* not enough memory retry */
     }
     }
 
 
     if(timeout > 0) {
     if(timeout > 0) {
         /* currently, only the client uses timeouts */
         /* currently, only the client uses timeouts */
-        struct timeval tmptv = {0, timeout * 1000};
-        if(0 != setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tmptv, sizeof(struct timeval))) {
+#ifndef _WIN32
+        int timeout_usec = timeout * 1000;
+        struct timeval tmptv = {timeout_usec / 1000000, timeout_usec % 1000000};
+        int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tmptv, sizeof(struct timeval));
+#else
+        DWORD timeout_dw = timeout;
+        int ret = setsockopt(connection->sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout_dw, sizeof(DWORD));
+#endif
+        if(0 != ret) {
             UA_ByteString_deleteMembers(response);
             UA_ByteString_deleteMembers(response);
             socket_close(connection);
             socket_close(connection);
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
@@ -114,7 +121,7 @@ socket_recv(UA_Connection *connection, UA_ByteString *response, UA_UInt32 timeou
 #else
 #else
 		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
 		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
 #endif
 #endif
-            return UA_STATUSCODE_BADINTERNALERROR; /* retry */
+            return UA_STATUSCODE_GOOD; /* retry */
         else {
         else {
             socket_close(connection);
             socket_close(connection);
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
             return UA_STATUSCODE_BADCONNECTIONCLOSED;
@@ -200,7 +207,7 @@ static UA_StatusCode
 ServerNetworkLayerGetSendBuffer(UA_Connection *connection, size_t length, UA_ByteString *buf) {
 ServerNetworkLayerGetSendBuffer(UA_Connection *connection, size_t length, UA_ByteString *buf) {
     if(length > connection->remoteConf.recvBufferSize)
     if(length > connection->remoteConf.recvBufferSize)
         return UA_STATUSCODE_BADCOMMUNICATIONERROR;
         return UA_STATUSCODE_BADCOMMUNICATIONERROR;
-    return UA_ByteString_newMembers(buf, length);
+    return UA_ByteString_allocBuffer(buf, length);
 }
 }
 
 
 static void
 static void
@@ -296,8 +303,7 @@ static UA_StatusCode ServerNetworkLayerTCP_start(ServerNetworkLayerTCP *layer, U
          .sin_port = htons(layer->port), .sin_zero = {0}};
          .sin_port = htons(layer->port), .sin_zero = {0}};
     int optval = 1;
     int optval = 1;
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
     if(setsockopt(layer->serversockfd, SOL_SOCKET,
-                  SO_REUSEADDR, (const char *)&optval,
-                  sizeof(optval)) == -1) {
+                  SO_REUSEADDR, (const char *)&optval, sizeof(optval)) == -1) {
         UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
         UA_LOG_WARNING(layer->layer.logger, UA_LOGCATEGORY_NETWORK,
                        "Error during setting of socket options");
                        "Error during setting of socket options");
         CLOSESOCKET(layer->serversockfd);
         CLOSESOCKET(layer->serversockfd);
@@ -356,7 +362,16 @@ ServerNetworkLayerTCP_getJobs(ServerNetworkLayerTCP *layer, UA_Job **jobs, UA_UI
             continue;
             continue;
         UA_StatusCode retval = socket_recv(layer->mappings[i].connection, &buf, 0);
         UA_StatusCode retval = socket_recv(layer->mappings[i].connection, &buf, 0);
         if(retval == UA_STATUSCODE_GOOD) {
         if(retval == UA_STATUSCODE_GOOD) {
-            js[j] = UA_Connection_completeMessages(layer->mappings[i].connection, buf);
+            UA_Boolean realloced = UA_FALSE;
+            retval = UA_Connection_completeMessages(layer->mappings[i].connection, &buf, &realloced);
+            if(retval != UA_STATUSCODE_GOOD || buf.length == 0)
+                continue;
+            js[j].job.binaryMessage.connection = layer->mappings[i].connection;
+            js[j].job.binaryMessage.message = buf;
+            if(!realloced)
+                js[j].type = UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER;
+            else
+                js[j].type = UA_JOBTYPE_BINARYMESSAGE_ALLOCATED;
             j++;
             j++;
         } else if (retval == UA_STATUSCODE_BADCONNECTIONCLOSED) {
         } else if (retval == UA_STATUSCODE_BADCONNECTIONCLOSED) {
             UA_Connection *c = layer->mappings[i].connection;
             UA_Connection *c = layer->mappings[i].connection;
@@ -456,7 +471,7 @@ ClientNetworkLayerGetBuffer(UA_Connection *connection, size_t length, UA_ByteStr
         return UA_STATUSCODE_BADCOMMUNICATIONERROR;
         return UA_STATUSCODE_BADCOMMUNICATIONERROR;
     if(connection->state == UA_CONNECTION_CLOSED)
     if(connection->state == UA_CONNECTION_CLOSED)
         return UA_STATUSCODE_BADCONNECTIONCLOSED;
         return UA_STATUSCODE_BADCONNECTIONCLOSED;
-    return UA_ByteString_newMembers(buf, connection->remoteConf.recvBufferSize);
+    return UA_ByteString_allocBuffer(buf, connection->remoteConf.recvBufferSize);
 }
 }
 
 
 static void
 static void
@@ -484,6 +499,14 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpoin
     UA_Connection_init(&connection);
     UA_Connection_init(&connection);
     connection.localConf = localConf;
     connection.localConf = localConf;
 
 
+    //socket_set_nonblocking(connection.sockfd);
+    connection.send = socket_write;
+    connection.recv = socket_recv;
+    connection.close = ClientNetworkLayerClose;
+    connection.getSendBuffer = ClientNetworkLayerGetBuffer;
+    connection.releaseSendBuffer = ClientNetworkLayerReleaseBuffer;
+    connection.releaseRecvBuffer = ClientNetworkLayerReleaseBuffer;
+
     size_t urlLength = strlen(endpointUrl);
     size_t urlLength = strlen(endpointUrl);
     if(urlLength < 11 || urlLength >= 512) {
     if(urlLength < 11 || urlLength >= 512) {
         UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Server url size invalid");
         UA_LOG_WARNING((*logger), UA_LOGCATEGORY_NETWORK, "Server url size invalid");
@@ -555,12 +578,5 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, const char *endpoin
     }
     }
 #endif
 #endif
 
 
-    //socket_set_nonblocking(connection.sockfd);
-    connection.send = socket_write;
-    connection.recv = socket_recv;
-    connection.close = ClientNetworkLayerClose;
-    connection.getSendBuffer = ClientNetworkLayerGetBuffer;
-    connection.releaseSendBuffer = ClientNetworkLayerReleaseBuffer;
-    connection.releaseRecvBuffer = ClientNetworkLayerReleaseBuffer;
     return connection;
     return connection;
 }
 }

+ 16 - 28
examples/server.c

@@ -54,17 +54,12 @@ readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
     }
     }
-	UA_DateTime *currentTime = UA_DateTime_new();
-	if(!currentTime)
-		return UA_STATUSCODE_BADOUTOFMEMORY;
-	*currentTime = UA_DateTime_now();
-	value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
-	value->value.arrayLength = -1;
-	value->value.data = currentTime;
+	UA_DateTime currentTime = UA_DateTime_now();
+    UA_Variant_setScalarCopy(&value->value, &currentTime, &UA_TYPES[UA_TYPES_DATETIME]);
 	value->hasValue = UA_TRUE;
 	value->hasValue = UA_TRUE;
 	if(sourceTimeStamp) {
 	if(sourceTimeStamp) {
 		value->hasSourceTimestamp = UA_TRUE;
 		value->hasSourceTimestamp = UA_TRUE;
-		value->sourceTimestamp = *currentTime;
+		value->sourceTimestamp = currentTime;
 	}
 	}
 	return UA_STATUSCODE_GOOD;
 	return UA_STATUSCODE_GOOD;
 }
 }
@@ -83,28 +78,20 @@ readTemperature(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
     }
     }
 
 
-	UA_Double* currentTemperature = UA_Double_new();
-
-	if(!currentTemperature)
-		return UA_STATUSCODE_BADOUTOFMEMORY;
-
 	rewind(temperatureFile);
 	rewind(temperatureFile);
 	fflush(temperatureFile);
 	fflush(temperatureFile);
 
 
-	if(fscanf(temperatureFile, "%lf", currentTemperature) != 1){
+	UA_Double currentTemperature;
+	if(fscanf(temperatureFile, "%lf", &currentTemperature) != 1){
 		UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "Can not parse temperature");
 		UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "Can not parse temperature");
 		exit(1);
 		exit(1);
 	}
 	}
 
 
-	*currentTemperature /= 1000.0;
+	currentTemperature /= 1000.0;
 
 
 	value->sourceTimestamp = UA_DateTime_now();
 	value->sourceTimestamp = UA_DateTime_now();
 	value->hasSourceTimestamp = UA_TRUE;
 	value->hasSourceTimestamp = UA_TRUE;
-	value->value.type = &UA_TYPES[UA_TYPES_DOUBLE];
-	value->value.arrayLength = -1;
-	value->value.data = currentTemperature;
-	value->value.arrayDimensionsSize = -1;
-	value->value.arrayDimensions = NULL;
+    UA_Variant_setScalarCopy(&value->value, &currentTemperature, &UA_TYPES[UA_TYPES_DOUBLE]);
 	value->hasValue = UA_TRUE;
 	value->hasValue = UA_TRUE;
 	return UA_STATUSCODE_GOOD;
 	return UA_STATUSCODE_GOOD;
 }
 }
@@ -169,8 +156,9 @@ writeLedStatus(void *handle, const UA_NodeId nodeid,
 
 
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
 static UA_StatusCode
 static UA_StatusCode
-getMonitoredItems(const UA_NodeId objectId, const UA_Variant *input,
-                  UA_Variant *output, void *handle) {
+getMonitoredItems(void *methodHandle, const UA_NodeId objectId,
+                  size_t inputSize, const UA_Variant *input,
+                  size_t outputSize, UA_Variant *output) {
     UA_String tmp = UA_STRING("Hello World");
     UA_String tmp = UA_STRING("Hello World");
     UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]);
     UA_Variant_setScalarCopy(output, &tmp, &UA_TYPES[UA_TYPES_STRING]);
     printf("getMonitoredItems was called\n");
     printf("getMonitoredItems was called\n");
@@ -341,7 +329,7 @@ int main(int argc, char** argv) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), object_attr, NULL);
 
 
     UA_UInt32 id = 51000; // running id in namespace 0
     UA_UInt32 id = 51000; // running id in namespace 0
-    for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
+    for(UA_UInt32 type = 0; type < UA_TYPES_DIAGNOSTICINFO; type++) {
         if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
         if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
             continue;
             continue;
 
 
@@ -362,7 +350,7 @@ int main(int argc, char** argv) {
         UA_Variant_deleteMembers(&attr.value);
         UA_Variant_deleteMembers(&attr.value);
 
 
         /* add an array node for every built-in type */
         /* add an array node for every built-in type */
-        UA_Variant_setArray(&attr.value, UA_Array_new(&UA_TYPES[type], 10),
+        UA_Variant_setArray(&attr.value, UA_Array_new(10, &UA_TYPES[type]),
                             10, &UA_TYPES[type]);
                             10, &UA_TYPES[type]);
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
         UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id),
                                   UA_NODEID_NUMERIC(1, ARRAYID),
                                   UA_NODEID_NUMERIC(1, ARRAYID),
@@ -371,8 +359,8 @@ int main(int argc, char** argv) {
         UA_Variant_deleteMembers(&attr.value);
         UA_Variant_deleteMembers(&attr.value);
 
 
         /* add an matrix node for every built-in type */
         /* add an matrix node for every built-in type */
-        void* myMultiArray = UA_Array_new(&UA_TYPES[type],9);
-        attr.value.arrayDimensions = UA_Array_new(&UA_TYPES[UA_TYPES_INT32],2);
+        void* myMultiArray = UA_Array_new(9, &UA_TYPES[type]);
+        attr.value.arrayDimensions = UA_Array_new(2, &UA_TYPES[UA_TYPES_INT32]);
         attr.value.arrayDimensions[0] = 3;
         attr.value.arrayDimensions[0] = 3;
         attr.value.arrayDimensions[1] = 3;
         attr.value.arrayDimensions[1] = 3;
         attr.value.arrayDimensionsSize = 2;
         attr.value.arrayDimensionsSize = 2;
@@ -389,7 +377,7 @@ int main(int argc, char** argv) {
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
     UA_Argument inputArguments;
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
     UA_Argument_init(&inputArguments);
-    inputArguments.arrayDimensionsSize = -1;
+    inputArguments.arrayDimensionsSize = 0;
     inputArguments.arrayDimensions = NULL;
     inputArguments.arrayDimensions = NULL;
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
     inputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
@@ -398,7 +386,7 @@ int main(int argc, char** argv) {
 
 
     UA_Argument outputArguments;
     UA_Argument outputArguments;
     UA_Argument_init(&outputArguments);
     UA_Argument_init(&outputArguments);
-    outputArguments.arrayDimensionsSize = -1;
+    outputArguments.arrayDimensionsSize = 0;
     outputArguments.arrayDimensions = NULL;
     outputArguments.arrayDimensions = NULL;
     outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
     outputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");

+ 3 - 3
examples/server_method.c

@@ -38,7 +38,7 @@ static UA_StatusCode
 IncInt32ArrayValuesMethod(const UA_NodeId objectId, const UA_Variant *input,
 IncInt32ArrayValuesMethod(const UA_NodeId objectId, const UA_Variant *input,
                           UA_Variant *output, void *handle) {
                           UA_Variant *output, void *handle) {
 	UA_Variant_setArrayCopy(output, input->data, 5, &UA_TYPES[UA_TYPES_INT32]);
 	UA_Variant_setArrayCopy(output, input->data, 5, &UA_TYPES[UA_TYPES_INT32]);
-	for(int i = 0; i< input->arrayLength; i++)
+	for(size_t i = 0; i< input->arrayLength; i++)
 		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;
 		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;
 	return UA_STATUSCODE_GOOD;
 	return UA_STATUSCODE_GOOD;
 }
 }
@@ -60,7 +60,7 @@ int main(int argc, char** argv) {
     /* add the method node with the callback */
     /* add the method node with the callback */
     UA_Argument inputArguments;
     UA_Argument inputArguments;
     UA_Argument_init(&inputArguments);
     UA_Argument_init(&inputArguments);
-    inputArguments.arrayDimensionsSize = -1;
+    inputArguments.arrayDimensionsSize = 0;
     inputArguments.arrayDimensions = NULL;
     inputArguments.arrayDimensions = NULL;
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     inputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
     inputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
@@ -69,7 +69,7 @@ int main(int argc, char** argv) {
 
 
     UA_Argument outputArguments;
     UA_Argument outputArguments;
     UA_Argument_init(&outputArguments);
     UA_Argument_init(&outputArguments);
-    outputArguments.arrayDimensionsSize = -1;
+    outputArguments.arrayDimensionsSize = 0;
     outputArguments.arrayDimensions = NULL;
     outputArguments.arrayDimensions = NULL;
     outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArguments.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     outputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");
     outputArguments.description = UA_LOCALIZEDTEXT("en_US", "A String");

+ 21 - 20
examples/server_readspeed.c

@@ -7,6 +7,7 @@
 
 
 #ifdef UA_NO_AMALGAMATION
 #ifdef UA_NO_AMALGAMATION
 # include "ua_types.h"
 # include "ua_types.h"
+# include "ua_types_generated.h"
 # include "ua_server.h"
 # include "ua_server.h"
 # include "logger_stdout.h"
 # include "logger_stdout.h"
 # include "networklayer_tcp.h"
 # include "networklayer_tcp.h"
@@ -15,7 +16,7 @@
 #endif
 #endif
 
 
 #include <time.h>
 #include <time.h>
-#include "ua_types_generated.h"
+#include <stdio.h>
 #include "server/ua_services.h"
 #include "server/ua_services.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
 
 
@@ -32,21 +33,21 @@ int main(int argc, char** argv) {
 
 
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server_setLogger(server, logger);
     UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 
 
     /* add a variable node to the address space */
     /* add a variable node to the address space */
-    UA_Variant *myIntegerVariant = UA_Variant_new();
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
     UA_Int32 myInteger = 42;
     UA_Int32 myInteger = 42;
-    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
-    //NOTE: the link between myInteger and the value of the node is lost here, you can safely reuse myInteger
+    UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
+    attr.displayName = UA_LOCALIZEDTEXT("en_US","the answer");
+    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer"); /* UA_NODEID_NULL would assign a random free nodeid */
-    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-
-    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName, myIntegerBrowseName, 0, 0,
-                              parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NULL, attr, NULL);
 
 
     UA_ReadRequest request;
     UA_ReadRequest request;
     UA_ReadRequest_init(&request);
     UA_ReadRequest_init(&request);
@@ -59,12 +60,13 @@ int main(int argc, char** argv) {
     request.nodesToReadSize = 1;
     request.nodesToReadSize = 1;
     request.nodesToRead = &rvi;
     request.nodesToRead = &rvi;
 
 
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_ByteString request_msg;
     UA_ByteString request_msg;
+    retval |= UA_ByteString_allocBuffer(&request_msg, 1000);
     UA_ByteString response_msg;
     UA_ByteString response_msg;
-    UA_ByteString_newMembers(&request_msg, 1000);
-    UA_ByteString_newMembers(&response_msg, 1000);
+    retval |= UA_ByteString_allocBuffer(&response_msg, 1000);
     size_t offset = 0;
     size_t offset = 0;
-    UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_READREQUEST], &request_msg, &offset);
+    retval |= UA_encodeBinary(&request, &UA_TYPES[UA_TYPES_READREQUEST], &request_msg, &offset);
     
     
     clock_t begin, end;
     clock_t begin, end;
     begin = clock();
     begin = clock();
@@ -72,17 +74,15 @@ int main(int argc, char** argv) {
     UA_ReadRequest rq;
     UA_ReadRequest rq;
     UA_ReadResponse rr;
     UA_ReadResponse rr;
 
 
-    for(int i = 0; i < 600000; i++) {
-        UA_ReadRequest_init(&rq);
-        UA_ReadResponse_init(&rr);
-
+    for(int i = 0; i < 900000; i++) {
         offset = 0;
         offset = 0;
-        UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST]);
+        retval |= UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST]);
 
 
+        UA_ReadResponse_init(&rr);
         Service_Read(server, &adminSession, &rq, &rr);
         Service_Read(server, &adminSession, &rq, &rr);
 
 
         offset = 0;
         offset = 0;
-        UA_encodeBinary(&rr, &UA_TYPES[UA_TYPES_READRESPONSE], &response_msg, &offset);
+        retval |= UA_encodeBinary(&rr, &UA_TYPES[UA_TYPES_READRESPONSE], &response_msg, &offset);
 
 
         UA_ReadRequest_deleteMembers(&rq);
         UA_ReadRequest_deleteMembers(&rq);
         UA_ReadResponse_deleteMembers(&rr);
         UA_ReadResponse_deleteMembers(&rr);
@@ -91,11 +91,12 @@ int main(int argc, char** argv) {
     end = clock();
     end = clock();
     double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
     double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
     printf("duration was %f s\n", time_spent);
     printf("duration was %f s\n", time_spent);
+    printf("retval is %i\n", retval);
 
 
     UA_ByteString_deleteMembers(&request_msg);
     UA_ByteString_deleteMembers(&request_msg);
     UA_ByteString_deleteMembers(&response_msg);
     UA_ByteString_deleteMembers(&response_msg);
 
 
-    UA_StatusCode retval = UA_Server_run(server, 1, &running);
+    retval |= UA_Server_run(server, 1, &running);
     UA_Server_delete(server);
     UA_Server_delete(server);
 
 
     return retval;
     return retval;

+ 21 - 5
include/ua_connection.h

@@ -97,11 +97,27 @@ void UA_EXPORT UA_Connection_deleteMembers(UA_Connection *connection);
 void UA_EXPORT UA_Connection_detachSecureChannel(UA_Connection *connection);
 void UA_EXPORT UA_Connection_detachSecureChannel(UA_Connection *connection);
 void UA_EXPORT UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
 void UA_EXPORT UA_Connection_attachSecureChannel(UA_Connection *connection, UA_SecureChannel *channel);
 
 
-/** Returns a job that contains either a message-bytestring managed by the network layer or a
-    message-bytestring that was newly allocated (or a nothing-job). Half-received messages are
-    attached to the connection. The next completion tries to create a complete message with the next
-    buffer the connection receives. */
-UA_Job UA_EXPORT UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received);
+/**
+ * The network layer may receive chopped up messages since TCP is a streaming
+ * protocol. Furthermore, the networklayer may operate on ringbuffers or
+ * statically assigned memory.
+ *
+ * If an entire message is received, it is forwarded directly. But the memory
+ * needs to be freed with the networklayer-specific mechanism. If a half message
+ * is received, we copy it into a local buffer. Then, the stack-specific free
+ * needs to be used.
+ *
+ * @param connection The connection
+ * @param message The received message. The content may be overwritten when a
+ *        previsouly received buffer is completed.
+ * @param realloced The Boolean value is set to true if the outgoing message has
+ *        been reallocated from the network layer.
+ * @return Returns UA_STATUSCODE_GOOD or an error code. When an error occurs, the ingoing message
+ *         and the current buffer in the connection are freed.
+ */
+UA_StatusCode UA_EXPORT
+UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
+                               UA_Boolean * UA_RESTRICT realloced);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"

+ 3 - 6
include/ua_server.h

@@ -331,8 +331,9 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
                                     UA_NodeId *outNewNodeId);
                                     UA_NodeId *outNewNodeId);
 
 
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
-typedef UA_StatusCode (*UA_MethodCallback)(const UA_NodeId objectId, const UA_Variant *input,
-                                           UA_Variant *output, void *handle);
+typedef UA_StatusCode (*UA_MethodCallback)(void *methodHandle, const UA_NodeId objectId,
+                                           size_t inputSize, const UA_Variant *input,
+                                           size_t outputSize, UA_Variant *output);
 
 
 UA_StatusCode UA_EXPORT
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
@@ -404,10 +405,6 @@ static UA_INLINE UA_StatusCode
 UA_Server_writeValueAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Variant value) {
 UA_Server_writeValueAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_Variant value) {
     return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); }
     return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value); }
 
 
-/* The value content is moved into the node (not copied). The input variant is _inited internally. */
-UA_StatusCode UA_EXPORT
-UA_Server_writeValueAttribute_move(UA_Server *server, const UA_NodeId nodeId, UA_Variant *value);
-
 static UA_INLINE UA_StatusCode
 static UA_INLINE UA_StatusCode
 UA_Server_writeAccessLevelAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 accessLevel) {
 UA_Server_writeAccessLevelAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_UInt32 accessLevel) {
     return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }
     return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }

File diff suppressed because it is too large
+ 315 - 490
include/ua_types.h


+ 65 - 33
src/client/ua_client.c

@@ -1,5 +1,6 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_client.h"
 #include "ua_client.h"
+#include "ua_client_highlevel.h"
 #include "ua_client_internal.h"
 #include "ua_client_internal.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_nodeids.h"
 #include "ua_nodeids.h"
@@ -9,7 +10,7 @@
 #include "ua_transport_generated_encoding_binary.h"
 #include "ua_transport_generated_encoding_binary.h"
 
 
 const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
 const UA_EXPORT UA_ClientConfig UA_ClientConfig_standard =
-    { .timeout = 500 /* ms receive timout */, .secureChannelLifeTime = 30000,
+    { .timeout = 5000 /* ms receive timout */, .secureChannelLifeTime = 30000,
       .timeToRenewSecureChannel = 2000,
       .timeToRenewSecureChannel = 2000,
       {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
       {.protocolVersion = 0, .sendBufferSize = 65536, .recvBufferSize  = 65536,
        .maxMessageSize = 65536, .maxChunkCount = 1}};
        .maxMessageSize = 65536, .maxChunkCount = 1}};
@@ -50,13 +51,30 @@ UA_Client * UA_Client_new(UA_ClientConfig config, UA_Logger logger) {
     return client;
     return client;
 }
 }
 
 
-static void UA_Client_deleteMembers(UA_Client* client){
+static void UA_Client_deleteMembers(UA_Client* client) {
     UA_Client_disconnect(client);
     UA_Client_disconnect(client);
     UA_Connection_deleteMembers(&client->connection);
     UA_Connection_deleteMembers(&client->connection);
     UA_SecureChannel_deleteMembersCleanup(&client->channel);
     UA_SecureChannel_deleteMembersCleanup(&client->channel);
     if(client->endpointUrl.data)
     if(client->endpointUrl.data)
         UA_String_deleteMembers(&client->endpointUrl);
         UA_String_deleteMembers(&client->endpointUrl);
     UA_UserTokenPolicy_deleteMembers(&client->token);
     UA_UserTokenPolicy_deleteMembers(&client->token);
+#ifdef ENABLE_SUBSCRIPTIONS
+    UA_Client_NotificationsAckNumber *n, *tmp;
+    LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) {
+        LIST_REMOVE(n, listEntry);
+        free(n);
+    }
+    UA_Client_Subscription *sub, *tmps;
+    LIST_FOREACH_SAFE(sub, &client->subscriptions, listEntry, tmps) {
+        LIST_REMOVE(sub, listEntry);
+        UA_Client_MonitoredItem *mon, *tmpmon;
+        LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, tmpmon) {
+            UA_Client_Subscriptions_removeMonitoredItem(client, sub->SubscriptionID,
+                                                        mon->MonitoredItemId);
+        }
+        free(sub);
+    }
+#endif
 }
 }
 
 
 void UA_Client_reset(UA_Client* client){
 void UA_Client_reset(UA_Client* client){
@@ -108,32 +126,38 @@ static UA_StatusCode HelAckHandshake(UA_Client *c) {
     message.length = messageHeader.messageSize;
     message.length = messageHeader.messageSize;
     retval = c->connection.send(&c->connection, &message);
     retval = c->connection.send(&c->connection, &message);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Sending HEL failed");
+        UA_LOG_INFO(c->logger, UA_LOGCATEGORY_NETWORK, "Sending HEL failed");
         return retval;
         return retval;
     }
     }
     UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Sent HEL message");
     UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Sent HEL message");
 
 
     UA_ByteString reply;
     UA_ByteString reply;
     UA_ByteString_init(&reply);
     UA_ByteString_init(&reply);
+    UA_Boolean realloced = UA_FALSE;
     do {
     do {
         retval = c->connection.recv(&c->connection, &reply, c->config.timeout);
         retval = c->connection.recv(&c->connection, &reply, c->config.timeout);
+        retval |= UA_Connection_completeMessages(&c->connection, &reply, &realloced);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
-            UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Receiving ACK message failed");
+            UA_LOG_INFO(c->logger, UA_LOGCATEGORY_NETWORK, "Receiving ACK message failed");
             return retval;
             return retval;
         }
         }
-    } while(!reply.data);
+    } while(reply.length == 0);
 
 
     offset = 0;
     offset = 0;
     UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
     UA_TcpMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
     UA_TcpAcknowledgeMessage ackMessage;
     UA_TcpAcknowledgeMessage ackMessage;
     retval = UA_TcpAcknowledgeMessage_decodeBinary(&reply, &offset, &ackMessage);
     retval = UA_TcpAcknowledgeMessage_decodeBinary(&reply, &offset, &ackMessage);
-    UA_ByteString_deleteMembers(&reply);
+    if(!realloced)
+        c->connection.releaseRecvBuffer(&c->connection, &reply);
+    else
+        UA_ByteString_deleteMembers(&reply);
+
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Decoding ACK message failed");
+        UA_LOG_INFO(c->logger, UA_LOGCATEGORY_NETWORK, "Decoding ACK message failed");
         return retval;
         return retval;
     }
     }
-
     UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Received ACK message");
     UA_LOG_DEBUG(c->logger, UA_LOGCATEGORY_NETWORK, "Received ACK message");
+
     conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
     conn->remoteConf.maxChunkCount = ackMessage.maxChunkCount;
     conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
     conn->remoteConf.maxMessageSize = ackMessage.maxMessageSize;
     conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
     conn->remoteConf.protocolVersion = ackMessage.protocolVersion;
@@ -148,6 +172,10 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     if(renew && client->scExpiresAt - UA_DateTime_now() > client->config.timeToRenewSecureChannel * 10000)
     if(renew && client->scExpiresAt - UA_DateTime_now() > client->config.timeToRenewSecureChannel * 10000)
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
 
 
+    UA_Connection *c = &client->connection;
+    if(c->state != UA_CONNECTION_ESTABLISHED)
+        return UA_STATUSCODE_BADSERVERNOTCONNECTED;
+
     UA_SecureConversationMessageHeader messageHeader;
     UA_SecureConversationMessageHeader messageHeader;
     messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
     messageHeader.messageHeader.messageTypeAndFinal = UA_MESSAGETYPEANDFINAL_OPNF;
     messageHeader.secureChannelId = 0;
     messageHeader.secureChannelId = 0;
@@ -180,7 +208,6 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     }
     }
 
 
     UA_ByteString message;
     UA_ByteString message;
-    UA_Connection *c = &client->connection;
     UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
     UA_StatusCode retval = c->getSendBuffer(c, c->remoteConf.recvBufferSize, &message);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
@@ -211,14 +238,16 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
 
 
     UA_ByteString reply;
     UA_ByteString reply;
     UA_ByteString_init(&reply);
     UA_ByteString_init(&reply);
+    UA_Boolean realloced = UA_FALSE;
     do {
     do {
-        retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
+        retval = c->recv(c, &reply, client->config.timeout);
+        retval |= UA_Connection_completeMessages(c, &reply, &realloced);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
             UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
             UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
                          "Receiving OpenSecureChannelResponse failed");
                          "Receiving OpenSecureChannelResponse failed");
             return retval;
             return retval;
         }
         }
-    } while(!reply.data);
+    } while(reply.length == 0);
 
 
     offset = 0;
     offset = 0;
     UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
     UA_SecureConversationMessageHeader_decodeBinary(&reply, &offset, &messageHeader);
@@ -239,17 +268,21 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     UA_OpenSecureChannelResponse response;
     UA_OpenSecureChannelResponse response;
     UA_OpenSecureChannelResponse_init(&response);
     UA_OpenSecureChannelResponse_init(&response);
     retval = UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
     retval = UA_OpenSecureChannelResponse_decodeBinary(&reply, &offset, &response);
+    if(!realloced)
+        c->releaseRecvBuffer(c, &reply);
+    else
+        UA_ByteString_deleteMembers(&reply);
+        
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
         UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_SECURECHANNEL,
                      "Decoding OpenSecureChannelResponse failed");
                      "Decoding OpenSecureChannelResponse failed");
-        UA_ByteString_deleteMembers(&reply);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
         UA_OpenSecureChannelResponse_init(&response);
         UA_OpenSecureChannelResponse_init(&response);
         response.responseHeader.serviceResult = retval;
         response.responseHeader.serviceResult = retval;
         return retval;
         return retval;
     }
     }
+
     client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000;
     client->scExpiresAt = UA_DateTime_now() + response.securityToken.revisedLifetime * 10000;
-    UA_ByteString_deleteMembers(&reply);
     retval = response.responseHeader.serviceResult;
     retval = response.responseHeader.serviceResult;
 
 
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)
@@ -283,19 +316,9 @@ static UA_StatusCode ActivateSession(UA_Client *client) {
     UA_String_copy(&client->token.policyId, &identityToken.policyId);
     UA_String_copy(&client->token.policyId, &identityToken.policyId);
 
 
     //manual ExtensionObject encoding of the identityToken
     //manual ExtensionObject encoding of the identityToken
-    request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-    request.userIdentityToken.typeId = UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN].typeId;
-    request.userIdentityToken.typeId.identifier.numeric+=UA_ENCODINGOFFSET_BINARY;
-    
-    if (identityToken.policyId.length >= 0)
-        UA_ByteString_newMembers(&request.userIdentityToken.body, identityToken.policyId.length+4);
-    else {
-        identityToken.policyId.length = -1;
-        UA_ByteString_newMembers(&request.userIdentityToken.body, 4);
-    }
-    
-    size_t offset = 0;
-    UA_ByteString_encodeBinary(&identityToken.policyId,&request.userIdentityToken.body,&offset);
+    request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
+    request.userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN];
+    request.userIdentityToken.content.decoded.data = &identityToken;
 
 
     UA_ActivateSessionResponse response;
     UA_ActivateSessionResponse response;
     __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
     __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
@@ -323,10 +346,15 @@ static UA_StatusCode EndpointsHandshake(UA_Client *client) {
     __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
     __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
                         &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
                         &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);
 
 
+    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
+        UA_LOG_ERROR(client->logger, UA_LOGCATEGORY_CLIENT, "GetEndpointRequest failed");
+        return response.responseHeader.serviceResult;
+    }
+
     UA_Boolean endpointFound = UA_FALSE;
     UA_Boolean endpointFound = UA_FALSE;
     UA_Boolean tokenFound = UA_FALSE;
     UA_Boolean tokenFound = UA_FALSE;
     UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
     UA_String securityNone = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
-    for(UA_Int32 i = 0; i < response.endpointsSize; i++) {
+    for(size_t i = 0; i < response.endpointsSize; i++) {
         UA_EndpointDescription* endpoint = &response.endpoints[i];
         UA_EndpointDescription* endpoint = &response.endpoints[i];
         /* look out for an endpoint without security */
         /* look out for an endpoint without security */
         if(!UA_String_equal(&endpoint->securityPolicyUri, &securityNone))
         if(!UA_String_equal(&endpoint->securityPolicyUri, &securityNone))
@@ -334,7 +362,7 @@ static UA_StatusCode EndpointsHandshake(UA_Client *client) {
         endpointFound = UA_TRUE;
         endpointFound = UA_TRUE;
         /* endpoint with no security found */
         /* endpoint with no security found */
         /* look for a user token policy with an anonymous token */
         /* look for a user token policy with an anonymous token */
-        for(UA_Int32 j=0; j<endpoint->userIdentityTokensSize; ++j) {
+        for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) {
             UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
             UA_UserTokenPolicy* userToken = &endpoint->userIdentityTokens[j];
             if(userToken->tokenType != UA_USERTOKENTYPE_ANONYMOUS)
             if(userToken->tokenType != UA_USERTOKENTYPE_ANONYMOUS)
                 continue;
                 continue;
@@ -461,7 +489,7 @@ UA_StatusCode UA_Client_connect(UA_Client *client, UA_ConnectClientConnection co
     }
     }
 
 
     client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
     client->endpointUrl = UA_STRING_ALLOC(endpointUrl);
-    if(client->endpointUrl.length < 0) {
+    if(client->endpointUrl.data == NULL) {
         retval = UA_STATUSCODE_BADOUTOFMEMORY;
         retval = UA_STATUSCODE_BADOUTOFMEMORY;
         goto cleanup;
         goto cleanup;
     }
     }
@@ -534,7 +562,7 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
     UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT,
     UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT,
                  "Sending a request of type %i", requestType->typeId.identifier.numeric);
                  "Sending a request of type %i", requestType->typeId.identifier.numeric);
     retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId, request, requestType);
     retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId, request, requestType);
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
         if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
             respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE;
             respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE;
         else
         else
@@ -547,8 +575,10 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
     // Todo: push this into the generic securechannel implementation for client and server
     // Todo: push this into the generic securechannel implementation for client and server
     UA_ByteString reply;
     UA_ByteString reply;
     UA_ByteString_init(&reply);
     UA_ByteString_init(&reply);
+    UA_Boolean realloced = UA_FALSE;
     do {
     do {
         retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
         retval = client->connection.recv(&client->connection, &reply, client->config.timeout);
+        retval |= UA_Connection_completeMessages(&client->connection, &reply, &realloced);
         if(retval != UA_STATUSCODE_GOOD) {
         if(retval != UA_STATUSCODE_GOOD) {
             respHeader->serviceResult = retval;
             respHeader->serviceResult = retval;
             client->state = UA_CLIENTSTATE_ERRORED;
             client->state = UA_CLIENTSTATE_ERRORED;
@@ -568,9 +598,8 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
     UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
     UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
                                                  UA_ENCODINGOFFSET_BINARY);
                                                  UA_ENCODINGOFFSET_BINARY);
 
 
-    if(retval != UA_STATUSCODE_GOOD) {
+    if(retval != UA_STATUSCODE_GOOD)
         goto finish;
         goto finish;
-    }
 
 
     /* Todo: we need to demux responses since a publish responses may come at any time */
     /* Todo: we need to demux responses since a publish responses may come at any time */
     if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) {
     if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) {
@@ -591,7 +620,10 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
 
 
  finish:
  finish:
     UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
     UA_SymmetricAlgorithmSecurityHeader_deleteMembers(&symHeader);
-    UA_ByteString_deleteMembers(&reply);
+    if(!realloced)
+        client->connection.releaseRecvBuffer(&client->connection, &reply);
+    else
+        UA_ByteString_deleteMembers(&reply);
     if(retval != UA_STATUSCODE_GOOD){
     if(retval != UA_STATUSCODE_GOOD){
         UA_LOG_INFO(client->logger, UA_LOGCATEGORY_CLIENT, "Error receiving the response");
         UA_LOG_INFO(client->logger, UA_LOGCATEGORY_CLIENT, "Error receiving the response");
         client->state = UA_CLIENTSTATE_ERRORED;
         client->state = UA_CLIENTSTATE_ERRORED;

+ 43 - 55
src/client/ua_client_highlevel.c

@@ -2,52 +2,47 @@
 #include "ua_nodeids.h"
 #include "ua_nodeids.h"
 #include "ua_client_highlevel.h"
 #include "ua_client_highlevel.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
+#include "ua_util.h"
 
 
-UA_StatusCode UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt16 *namespaceIndex){
-	UA_ReadRequest ReadRequest;
-	UA_ReadResponse ReadResponse;
-	UA_StatusCode retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
-
-	UA_ReadRequest_init(&ReadRequest);
+UA_StatusCode
+UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt16 *namespaceIndex) {
+	UA_ReadRequest request;
+	UA_ReadRequest_init(&request);
     UA_ReadValueId id;
     UA_ReadValueId id;
 	id.attributeId = UA_ATTRIBUTEID_VALUE;
 	id.attributeId = UA_ATTRIBUTEID_VALUE;
 	id.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY);
 	id.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY);
-	ReadRequest.nodesToRead = &id;
-	ReadRequest.nodesToReadSize = 1;
+	request.nodesToRead = &id;
+	request.nodesToReadSize = 1;
 
 
-	ReadResponse = UA_Client_Service_read(client, ReadRequest);
-
-    if(ReadResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD){
-        retval = ReadResponse.responseHeader.serviceResult;
-        goto cleanup;
-    }
+	UA_ReadResponse response = UA_Client_Service_read(client, request);
 
 
-    if(ReadResponse.resultsSize != 1 || !ReadResponse.results[0].hasValue){
+	UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
+        retval = response.responseHeader.serviceResult;
+    else if(response.resultsSize != 1 || !response.results[0].hasValue)
         retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
         retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
-        goto cleanup;
-    }
-
-    if(ReadResponse.results[0].value.type != &UA_TYPES[UA_TYPES_STRING]){
+    else if(response.results[0].value.type != &UA_TYPES[UA_TYPES_STRING])
         retval = UA_STATUSCODE_BADTYPEMISMATCH;
         retval = UA_STATUSCODE_BADTYPEMISMATCH;
-        goto cleanup;
+
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ReadResponse_deleteMembers(&response);
+        return retval;
     }
     }
 
 
     retval = UA_STATUSCODE_BADNOTFOUND;
     retval = UA_STATUSCODE_BADNOTFOUND;
-    for(UA_UInt16 iterator = 0; iterator < ReadResponse.results[0].value.arrayLength; iterator++){
-        if(UA_String_equal(namespaceUri, &((UA_String*)ReadResponse.results[0].value.data)[iterator] )){
-            *namespaceIndex = iterator;
+    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;
             retval = UA_STATUSCODE_GOOD;
             retval = UA_STATUSCODE_GOOD;
             break;
             break;
         }
         }
     }
     }
 
 
-cleanup:
-    UA_ReadResponse_deleteMembers(&ReadResponse);
-
+    UA_ReadResponse_deleteMembers(&response);
 	return retval;
 	return retval;
 }
 }
 
 
-
 /*******************/
 /*******************/
 /* Node Management */
 /* Node Management */
 /*******************/
 /*******************/
@@ -113,8 +108,8 @@ UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId, const
     return retval;
     return retval;
 }
 }
 
 
-UA_StatusCode UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
-                                   UA_Boolean deleteTargetReferences) {
+UA_StatusCode
+UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId, UA_Boolean deleteTargetReferences) {
     UA_DeleteNodesItem item;
     UA_DeleteNodesItem item;
     UA_DeleteNodesItem_init(&item);
     UA_DeleteNodesItem_init(&item);
     item.nodeId = nodeId;
     item.nodeId = nodeId;
@@ -138,11 +133,11 @@ UA_StatusCode UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
     return retval;
     return retval;
 }
 }
 
 
-UA_StatusCode __UA_Client_addNode(UA_Client *client, 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) {
+UA_StatusCode
+__UA_Client_addNode(UA_Client *client, 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) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_AddNodesRequest request;
     UA_AddNodesRequest request;
     UA_AddNodesRequest_init(&request);
     UA_AddNodesRequest_init(&request);
@@ -154,22 +149,12 @@ UA_StatusCode __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClas
     item.browseName = browseName;
     item.browseName = browseName;
     item.nodeClass = nodeClass;
     item.nodeClass = nodeClass;
     item.typeDefinition.nodeId = typeDefinition;
     item.typeDefinition.nodeId = typeDefinition;
-    size_t attributes_length = UA_calcSizeBinary(attr, attributeType);
-    item.nodeAttributes.typeId = attributeType->typeId;
-    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-    retval = UA_ByteString_newMembers(&item.nodeAttributes.body, attributes_length);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    size_t offset = 0;
-    retval = UA_encodeBinary(attr, attributeType, &item.nodeAttributes.body, &offset);
-    if(retval != UA_STATUSCODE_GOOD) {
-        UA_ByteString_deleteMembers(&item.nodeAttributes.body);
-        return retval;
-    }
+    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
+    item.nodeAttributes.content.decoded.type = attributeType;
+    item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr; // hack. is not written into.
     request.nodesToAdd = &item;
     request.nodesToAdd = &item;
     request.nodesToAddSize = 1;
     request.nodesToAddSize = 1;
     UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);
     UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);
-    UA_ByteString_deleteMembers(&item.nodeAttributes.body);
     if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
     if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
         retval = response.responseHeader.serviceResult;
         retval = response.responseHeader.serviceResult;
         UA_AddNodesResponse_deleteMembers(&response);
         UA_AddNodesResponse_deleteMembers(&response);
@@ -179,11 +164,13 @@ UA_StatusCode __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClas
         UA_AddNodesResponse_deleteMembers(&response);
         UA_AddNodesResponse_deleteMembers(&response);
         return UA_STATUSCODE_BADUNEXPECTEDERROR;
         return UA_STATUSCODE_BADUNEXPECTEDERROR;
     }
     }
-    if(outNewNodeId && response.results[0].statusCode) {
+    if(outNewNodeId && response.results[0].statusCode == UA_STATUSCODE_GOOD) {
         *outNewNodeId = response.results[0].addedNodeId;
         *outNewNodeId = response.results[0].addedNodeId;
         UA_NodeId_init(&response.results[0].addedNodeId);
         UA_NodeId_init(&response.results[0].addedNodeId);
     }
     }
-    return response.results[0].statusCode;
+    retval = response.results[0].statusCode;
+    UA_AddNodesResponse_deleteMembers(&response);
+    return retval;
 }
 }
 
 
 /********/
 /********/
@@ -191,9 +178,8 @@ UA_StatusCode __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClas
 /********/
 /********/
 
 
 UA_StatusCode
 UA_StatusCode
-UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId,
-               UA_Int32 inputSize, const UA_Variant *input, UA_Int32 *outputSize,
-               UA_Variant **output) {
+UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId, UA_Int32 inputSize,
+               const UA_Variant *input, UA_Int32 *outputSize, UA_Variant **output) {
     UA_CallRequest request;
     UA_CallRequest request;
     UA_CallRequest_init(&request);
     UA_CallRequest_init(&request);
     UA_CallMethodRequest item;
     UA_CallMethodRequest item;
@@ -219,7 +205,7 @@ UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId meth
         *output = response.results[0].outputArguments;
         *output = response.results[0].outputArguments;
         *outputSize = response.results[0].outputArgumentsSize;
         *outputSize = response.results[0].outputArgumentsSize;
         response.results[0].outputArguments = NULL;
         response.results[0].outputArguments = NULL;
-        response.results[0].outputArgumentsSize = -1;
+        response.results[0].outputArgumentsSize = 0;
     }
     }
     UA_CallResponse_deleteMembers(&response);
     UA_CallResponse_deleteMembers(&response);
     return retval;
     return retval;
@@ -248,6 +234,7 @@ __UA_Client_readAttribute(UA_Client *client, UA_NodeId nodeId, UA_AttributeId at
         UA_ReadResponse_deleteMembers(&response);
         UA_ReadResponse_deleteMembers(&response);
         return retval;
         return retval;
     }
     }
+
     UA_DataValue *res = response.results;
     UA_DataValue *res = response.results;
     if(res->hasStatus != UA_STATUSCODE_GOOD)
     if(res->hasStatus != UA_STATUSCODE_GOOD)
         retval = res->hasStatus;
         retval = res->hasStatus;
@@ -257,17 +244,18 @@ __UA_Client_readAttribute(UA_Client *client, UA_NodeId nodeId, UA_AttributeId at
         UA_ReadResponse_deleteMembers(&response);
         UA_ReadResponse_deleteMembers(&response);
         return retval;
         return retval;
     }
     }
+
     if(attributeId == UA_ATTRIBUTEID_VALUE) {
     if(attributeId == UA_ATTRIBUTEID_VALUE) {
         memcpy(out, &res->value, sizeof(UA_Variant));
         memcpy(out, &res->value, sizeof(UA_Variant));
         UA_Variant_init(&res->value);
         UA_Variant_init(&res->value);
-    }
-    else if(res->value.type != outDataType) {
+    } else if(res->value.type != outDataType) {
         retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
         retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
     } else {
     } else {
         memcpy(out, res->value.data, res->value.type->memSize);
         memcpy(out, res->value.data, res->value.type->memSize);
         UA_free(res->value.data);
         UA_free(res->value.data);
         res->value.data = NULL;
         res->value.data = NULL;
     }
     }
+
     UA_ReadResponse_deleteMembers(&response);
     UA_ReadResponse_deleteMembers(&response);
     return retval;
     return retval;
 }
 }

+ 41 - 44
src/client/ua_client_highlevel_subscriptions.c

@@ -57,7 +57,7 @@ UA_StatusCode UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscr
     if(!sub)
     if(!sub)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
     
     
-    UA_DeleteSubscriptionsRequest  request;
+    UA_DeleteSubscriptionsRequest request;
     UA_DeleteSubscriptionsRequest_init(&request);
     UA_DeleteSubscriptionsRequest_init(&request);
     request.subscriptionIdsSize = 1;
     request.subscriptionIdsSize = 1;
     request.subscriptionIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
     request.subscriptionIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
@@ -68,7 +68,7 @@ UA_StatusCode UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscr
         retval |= UA_Client_Subscriptions_removeMonitoredItem(client, sub->SubscriptionID,
         retval |= UA_Client_Subscriptions_removeMonitoredItem(client, sub->SubscriptionID,
                                                               mon->MonitoredItemId);
                                                               mon->MonitoredItemId);
     }
     }
-    if(retval != UA_STATUSCODE_GOOD){
+    if(retval != UA_STATUSCODE_GOOD) {
 	    UA_DeleteSubscriptionsRequest_deleteMembers(&request);
 	    UA_DeleteSubscriptionsRequest_deleteMembers(&request);
         return retval;
         return retval;
     }
     }
@@ -197,16 +197,15 @@ UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
     // Check if the server has acknowledged any of our ACKS
     // Check if the server has acknowledged any of our ACKS
     // Note that a list of serverside status codes may be send without valid publish data, i.e. 
     // Note that a list of serverside status codes may be send without valid publish data, i.e. 
     // during keepalives or no data availability
     // during keepalives or no data availability
-    UA_Client_NotificationsAckNumber *tmpAck = client->pendingNotificationsAcks.lh_first;
-    UA_Client_NotificationsAckNumber *nxtAck = tmpAck;
-    for(int i=0; i<response.resultsSize && nxtAck != NULL; i++) {
-        tmpAck = nxtAck;
-        nxtAck = tmpAck->listEntry.le_next;
+    UA_Client_NotificationsAckNumber *ack, *tmpAck;
+    size_t i = 0;
+    LIST_FOREACH_SAFE(ack, &client->pendingNotificationsAcks, listEntry, tmpAck) {
         if(response.results[i] == UA_STATUSCODE_GOOD ||
         if(response.results[i] == UA_STATUSCODE_GOOD ||
-            response.results[i] == UA_STATUSCODE_BADSEQUENCENUMBERINVALID) {
-            LIST_REMOVE(tmpAck, listEntry);
-            UA_free(tmpAck);
+           response.results[i] == UA_STATUSCODE_BADSEQUENCENUMBERINVALID) {
+            LIST_REMOVE(ack, listEntry);
+            UA_free(ack);
         }
         }
+        i++;
     }
     }
     
     
     if(response.subscriptionId == 0)
     if(response.subscriptionId == 0)
@@ -221,44 +220,38 @@ UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
         return UA_FALSE;
         return UA_FALSE;
     
     
     UA_NotificationMessage msg = response.notificationMessage;
     UA_NotificationMessage msg = response.notificationMessage;
-    UA_DataChangeNotification dataChangeNotification;
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Client_MonitoredItem *mon;
     UA_Client_MonitoredItem *mon;
-    size_t decodingOffset = 0;
-    for(int k = 0; k < msg.notificationDataSize; k++) {
-        if(msg.notificationData[k].encoding == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
-            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
-                msg.notificationData[k].typeId.identifier.numeric == 811 ) {
-                // This is a dataChangeNotification
-                retval |= UA_DataChangeNotification_decodeBinary(&msg.notificationData[k].body,
-                                                                 &decodingOffset, &dataChangeNotification);
-                UA_MonitoredItemNotification *mitemNot;
-                for(int i = 0; i < dataChangeNotification.monitoredItemsSize; i++) {
-                    mitemNot = &dataChangeNotification.monitoredItems[i];
-                    // find this client handle
-                    LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
-                        if(mon->ClientHandle == mitemNot->clientHandle) {
-                            mon->handler(mitemNot->clientHandle, &mitemNot->value);
-                            break;
-                        }
+    for(size_t k = 0; k < msg.notificationDataSize; k++) {
+        if(msg.notificationData[k].encoding != UA_EXTENSIONOBJECT_DECODED)
+            continue;
+        
+        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];
+                // find this client handle
+                LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
+                    if(mon->ClientHandle == mitemNot->clientHandle) {
+                        mon->handler(mitemNot->clientHandle, &mitemNot->value);
+                        break;
                     }
                     }
                 }
                 }
-                UA_DataChangeNotification_deleteMembers(&dataChangeNotification);
-                continue;
             }
             }
+            continue;
+        }
 
 
-            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
-               msg.notificationData[k].typeId.identifier.numeric == 820 ) {
-                //FIXME: This is a statusChangeNotification (not supported yet)
-                continue;
-            }
+        /* if(msg.notificationData[k].typeId.namespaceIndex == 0 && */
+        /*    msg.notificationData[k].typeId.identifier.numeric == 820 ) { */
+        /*     //FIXME: This is a statusChangeNotification (not supported yet) */
+        /*     continue; */
+        /* } */
 
 
-            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
-               msg.notificationData[k].typeId.identifier.numeric == 916 ) {
-                //FIXME: This is an EventNotification
-                continue;
-            }
-        }
+        /* if(msg.notificationData[k].typeId.namespaceIndex == 0 && */
+        /*    msg.notificationData[k].typeId.identifier.numeric == 916 ) { */
+        /*     //FIXME: This is an EventNotification */
+        /*     continue; */
+        /* } */
     }
     }
     
     
     /* We processed this message, add it to the list of pending acks (but make
     /* We processed this message, add it to the list of pending acks (but make
@@ -289,8 +282,12 @@ void UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
         UA_Client_NotificationsAckNumber *ack;
         UA_Client_NotificationsAckNumber *ack;
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
             request.subscriptionAcknowledgementsSize++;
             request.subscriptionAcknowledgementsSize++;
-        request.subscriptionAcknowledgements = UA_malloc(sizeof(UA_SubscriptionAcknowledgement) *
-                                                         request.subscriptionAcknowledgementsSize);
+        if(request.subscriptionAcknowledgementsSize > 0) {
+            request.subscriptionAcknowledgements = UA_malloc(sizeof(UA_SubscriptionAcknowledgement) *
+                                                             request.subscriptionAcknowledgementsSize);
+            if(!request.subscriptionAcknowledgements)
+                return;
+        }
         
         
         int index = 0 ;
         int index = 0 ;
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry) {
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry) {

+ 36 - 68
src/server/ua_nodes.c

@@ -2,29 +2,16 @@
 #include "ua_util.h"
 #include "ua_util.h"
 
 
 /* UA_Node */
 /* UA_Node */
-static void UA_Node_init(UA_Node *p) {
-	UA_NodeId_init(&p->nodeId);
-	UA_NodeClass_init(&p->nodeClass);
-	UA_QualifiedName_init(&p->browseName);
-	UA_LocalizedText_init(&p->displayName);
-	UA_LocalizedText_init(&p->description);
-	p->writeMask = 0;
-	p->userWriteMask = 0;
-	p->referencesSize = -1;
-	p->references = NULL;
-}
-
 static void UA_Node_deleteMembers(UA_Node *p) {
 static void UA_Node_deleteMembers(UA_Node *p) {
 	UA_NodeId_deleteMembers(&p->nodeId);
 	UA_NodeId_deleteMembers(&p->nodeId);
 	UA_QualifiedName_deleteMembers(&p->browseName);
 	UA_QualifiedName_deleteMembers(&p->browseName);
 	UA_LocalizedText_deleteMembers(&p->displayName);
 	UA_LocalizedText_deleteMembers(&p->displayName);
 	UA_LocalizedText_deleteMembers(&p->description);
 	UA_LocalizedText_deleteMembers(&p->description);
-	UA_Array_delete(p->references, &UA_TYPES[UA_TYPES_REFERENCENODE], p->referencesSize);
+	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) {
 static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 	UA_StatusCode retval = UA_STATUSCODE_GOOD;
 	UA_StatusCode retval = UA_STATUSCODE_GOOD;
-	UA_Node_init(dst);
 	retval |= UA_NodeId_copy(&src->nodeId, &dst->nodeId);
 	retval |= UA_NodeId_copy(&src->nodeId, &dst->nodeId);
 	dst->nodeClass = src->nodeClass;
 	dst->nodeClass = src->nodeClass;
 	retval |= UA_QualifiedName_copy(&src->browseName, &dst->browseName);
 	retval |= UA_QualifiedName_copy(&src->browseName, &dst->browseName);
@@ -32,45 +19,54 @@ static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 	retval |= UA_LocalizedText_copy(&src->description, &dst->description);
 	retval |= UA_LocalizedText_copy(&src->description, &dst->description);
 	dst->writeMask = src->writeMask;
 	dst->writeMask = src->writeMask;
 	dst->userWriteMask = src->userWriteMask;
 	dst->userWriteMask = src->userWriteMask;
-	dst->referencesSize = src->referencesSize;
-	retval |= UA_Array_copy(src->references, (void**)&dst->references, &UA_TYPES[UA_TYPES_REFERENCENODE],
-                            src->referencesSize);
-	if(retval)
+	if(retval != UA_STATUSCODE_GOOD) {
     	UA_Node_deleteMembers(dst);
     	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;
 	return retval;
 }
 }
 
 
-void UA_Node_deleteAnyNodeClass(UA_Node *node) {
+
+void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
     switch(node->nodeClass) {
     switch(node->nodeClass) {
     case UA_NODECLASS_OBJECT:
     case UA_NODECLASS_OBJECT:
-        UA_ObjectNode_delete((UA_ObjectNode*)node);
+        UA_ObjectNode_deleteMembers((UA_ObjectNode*)node);
         break;
         break;
     case UA_NODECLASS_VARIABLE:
     case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_delete((UA_VariableNode*)node);
+        UA_VariableNode_deleteMembers((UA_VariableNode*)node);
         break;
         break;
     case UA_NODECLASS_METHOD:
     case UA_NODECLASS_METHOD:
-        UA_MethodNode_delete((UA_MethodNode*)node);
+        UA_MethodNode_deleteMembers((UA_MethodNode*)node);
         break;
         break;
     case UA_NODECLASS_OBJECTTYPE:
     case UA_NODECLASS_OBJECTTYPE:
-        UA_ObjectTypeNode_delete((UA_ObjectTypeNode*)node);
+        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode*)node);
         break;
         break;
     case UA_NODECLASS_VARIABLETYPE:
     case UA_NODECLASS_VARIABLETYPE:
-        UA_VariableTypeNode_delete((UA_VariableTypeNode*)node);
+        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode*)node);
         break;
         break;
     case UA_NODECLASS_REFERENCETYPE:
     case UA_NODECLASS_REFERENCETYPE:
-        UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode*)node);
+        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode*)node);
         break;
         break;
     case UA_NODECLASS_DATATYPE:
     case UA_NODECLASS_DATATYPE:
-        UA_DataTypeNode_delete((UA_DataTypeNode*)node);
+        UA_DataTypeNode_deleteMembers((UA_DataTypeNode*)node);
         break;
         break;
     case UA_NODECLASS_VIEW:
     case UA_NODECLASS_VIEW:
-        UA_ViewNode_delete((UA_ViewNode*)node);
+        UA_ViewNode_deleteMembers((UA_ViewNode*)node);
         break;
         break;
     default:
     default:
         break;
         break;
     }
     }
 }
 }
 
 
+void UA_Node_deleteAnyNodeClass(UA_Node *node) {
+    UA_Node_deleteMembersAnyNodeClass(node);
+    UA_free(node);
+}
+
 typedef UA_Node *(*UA_NewNodeFunction)(void);
 typedef UA_Node *(*UA_NewNodeFunction)(void);
 typedef UA_StatusCode (*UA_CopyNodeFunction)(const UA_Node *src, UA_Node *dst);
 typedef UA_StatusCode (*UA_CopyNodeFunction)(const UA_Node *src, UA_Node *dst);
 typedef void (*UA_DeleteNodeFunction)(UA_Node *p);
 typedef void (*UA_DeleteNodeFunction)(UA_Node *p);
@@ -138,10 +134,8 @@ UA_Node * UA_Node_copyAnyNodeClass(const UA_Node *node) {
 
 
 /* UA_ObjectNode */
 /* UA_ObjectNode */
 void UA_ObjectNode_init(UA_ObjectNode *p) {
 void UA_ObjectNode_init(UA_ObjectNode *p) {
-	UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_ObjectNode));
     p->nodeClass = UA_NODECLASS_OBJECT;
     p->nodeClass = UA_NODECLASS_OBJECT;
-    p->eventNotifier = 0;
-    p->instanceHandle = NULL;
 }
 }
 
 
 UA_ObjectNode * UA_ObjectNode_new(void) {
 UA_ObjectNode * UA_ObjectNode_new(void) {
@@ -168,11 +162,8 @@ UA_StatusCode UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
 
 
 /* UA_ObjectTypeNode */
 /* UA_ObjectTypeNode */
 void UA_ObjectTypeNode_init(UA_ObjectTypeNode *p) {
 void UA_ObjectTypeNode_init(UA_ObjectTypeNode *p) {
-	UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_ObjectTypeNode));
     p->nodeClass = UA_NODECLASS_OBJECTTYPE;
     p->nodeClass = UA_NODECLASS_OBJECTTYPE;
-    p->isAbstract = UA_FALSE;
-    p->lifecycleManagement = (UA_ObjectLifecycleManagement)
-        {.constructor = NULL, .destructor = NULL};
 }
 }
 
 
 UA_ObjectTypeNode * UA_ObjectTypeNode_new(void) {
 UA_ObjectTypeNode * UA_ObjectTypeNode_new(void) {
@@ -199,16 +190,11 @@ UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectType
 
 
 /* UA_VariableNode */
 /* UA_VariableNode */
 void UA_VariableNode_init(UA_VariableNode *p) {
 void UA_VariableNode_init(UA_VariableNode *p) {
-	UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_VariableNode));
     p->nodeClass = UA_NODECLASS_VARIABLE;
     p->nodeClass = UA_NODECLASS_VARIABLE;
-    p->valueSource = UA_VALUESOURCE_VARIANT;
-    UA_Variant_init(&p->value.variant.value);
-    p->value.variant.callback = (UA_ValueCallback){NULL,NULL,NULL};
     p->valueRank = -2; // scalar or array of any dimension
     p->valueRank = -2; // scalar or array of any dimension
     p->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     p->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     p->userAccessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     p->userAccessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
-    p->minimumSamplingInterval = 0.0;
-    p->historizing = UA_FALSE;
 }
 }
 
 
 UA_VariableNode * UA_VariableNode_new(void) {
 UA_VariableNode * UA_VariableNode_new(void) {
@@ -230,7 +216,6 @@ void UA_VariableNode_delete(UA_VariableNode *p) {
 }
 }
 
 
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
 UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
-    UA_VariableNode_init(dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
     dst->valueRank = src->valueRank;
     dst->valueRank = src->valueRank;
     dst->valueSource = src->valueSource;
     dst->valueSource = src->valueSource;
@@ -239,7 +224,7 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
         dst->value.variant.callback = src->value.variant.callback;
         dst->value.variant.callback = src->value.variant.callback;
     } else
     } else
         dst->value.dataSource = src->value.dataSource;
         dst->value.dataSource = src->value.dataSource;
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_VariableNode_deleteMembers(dst);
         UA_VariableNode_deleteMembers(dst);
         return retval;
         return retval;
     }
     }
@@ -252,13 +237,9 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
 
 
 /* UA_VariableTypeNode */
 /* UA_VariableTypeNode */
 void UA_VariableTypeNode_init(UA_VariableTypeNode *p) {
 void UA_VariableTypeNode_init(UA_VariableTypeNode *p) {
-	UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_VariableTypeNode));
     p->nodeClass = UA_NODECLASS_VARIABLETYPE;
     p->nodeClass = UA_NODECLASS_VARIABLETYPE;
-    p->valueSource = UA_VALUESOURCE_VARIANT;
-    UA_Variant_init(&p->value.variant.value);
-    p->value.variant.callback = (UA_ValueCallback){NULL, NULL, NULL};
     p->valueRank = -2; // scalar or array of any dimension
     p->valueRank = -2; // scalar or array of any dimension
-    p->isAbstract = UA_FALSE;
 }
 }
 
 
 UA_VariableTypeNode * UA_VariableTypeNode_new(void) {
 UA_VariableTypeNode * UA_VariableTypeNode_new(void) {
@@ -280,16 +261,15 @@ void UA_VariableTypeNode_delete(UA_VariableTypeNode *p) {
 }
 }
 
 
 UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) {
 UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_VariableTypeNode *dst) {
-    UA_VariableTypeNode_init(dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 	UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
     dst->valueRank = src->valueRank;
     dst->valueRank = src->valueRank;
     dst->valueSource = src->valueSource;
     dst->valueSource = src->valueSource;
     if(src->valueSource == UA_VALUESOURCE_VARIANT){
     if(src->valueSource == UA_VALUESOURCE_VARIANT){
         UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
         UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
         dst->value.variant.callback = src->value.variant.callback;
         dst->value.variant.callback = src->value.variant.callback;
-    }else
+    } else
         dst->value.dataSource = src->value.dataSource;
         dst->value.dataSource = src->value.dataSource;
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_VariableTypeNode_deleteMembers(dst);
         UA_VariableTypeNode_deleteMembers(dst);
         return retval;
         return retval;
     }
     }
@@ -299,11 +279,8 @@ UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_Variab
 
 
 /* UA_ReferenceTypeNode */
 /* UA_ReferenceTypeNode */
 void UA_ReferenceTypeNode_init(UA_ReferenceTypeNode *p) {
 void UA_ReferenceTypeNode_init(UA_ReferenceTypeNode *p) {
-	UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_ReferenceTypeNode));
     p->nodeClass = UA_NODECLASS_REFERENCETYPE;
     p->nodeClass = UA_NODECLASS_REFERENCETYPE;
-    p->isAbstract = UA_FALSE;
-    p->symmetric = UA_FALSE;
-    UA_LocalizedText_init(&p->inverseName);
 }
 }
 
 
 UA_ReferenceTypeNode * UA_ReferenceTypeNode_new(void) {
 UA_ReferenceTypeNode * UA_ReferenceTypeNode_new(void) {
@@ -325,10 +302,10 @@ void UA_ReferenceTypeNode_delete(UA_ReferenceTypeNode *p) {
 
 
 UA_StatusCode UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src, UA_ReferenceTypeNode *dst) {
 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);
     UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
     retval = UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
     retval = UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_ReferenceTypeNode_deleteMembers(dst);
         UA_ReferenceTypeNode_deleteMembers(dst);
         return retval;
         return retval;
     }
     }
@@ -339,14 +316,8 @@ UA_StatusCode UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src, UA_Refe
 
 
 /* UA_MethodNode */
 /* UA_MethodNode */
 void UA_MethodNode_init(UA_MethodNode *p) {
 void UA_MethodNode_init(UA_MethodNode *p) {
-    UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_MethodNode));
     p->nodeClass = UA_NODECLASS_METHOD;
     p->nodeClass = UA_NODECLASS_METHOD;
-    p->executable = UA_FALSE;
-    p->userExecutable = UA_FALSE;
-#ifdef ENABLE_METHODCALLS
-    p->methodHandle        = NULL;
-    p->attachedMethod      = NULL;
-#endif
 }
 }
 
 
 UA_MethodNode * UA_MethodNode_new(void) {
 UA_MethodNode * UA_MethodNode_new(void) {
@@ -387,10 +358,8 @@ UA_StatusCode UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
 
 
 /* UA_ViewNode */
 /* UA_ViewNode */
 void UA_ViewNode_init(UA_ViewNode *p) {
 void UA_ViewNode_init(UA_ViewNode *p) {
-    UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_ViewNode));
     p->nodeClass = UA_NODECLASS_VIEW;
     p->nodeClass = UA_NODECLASS_VIEW;
-    p->containsNoLoops = UA_FALSE;
-    p->eventNotifier = 0;
 }
 }
 
 
 UA_ViewNode * UA_ViewNode_new(void) {
 UA_ViewNode * UA_ViewNode_new(void) {
@@ -417,9 +386,8 @@ UA_StatusCode UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
 
 
 /* UA_DataTypeNode */
 /* UA_DataTypeNode */
 void UA_DataTypeNode_init(UA_DataTypeNode *p) {
 void UA_DataTypeNode_init(UA_DataTypeNode *p) {
-	UA_Node_init((UA_Node*)p);
+    memset(p, 0, sizeof(UA_DataTypeNode));
     p->nodeClass = UA_NODECLASS_DATATYPE;
     p->nodeClass = UA_NODECLASS_DATATYPE;
-    p->isAbstract = UA_FALSE;
 }
 }
 
 
 UA_DataTypeNode * UA_DataTypeNode_new(void) {
 UA_DataTypeNode * UA_DataTypeNode_new(void) {

+ 5 - 4
src/server/ua_nodes.h

@@ -20,7 +20,7 @@
     UA_LocalizedText description;               \
     UA_LocalizedText description;               \
     UA_UInt32 writeMask;                        \
     UA_UInt32 writeMask;                        \
     UA_UInt32 userWriteMask;                    \
     UA_UInt32 userWriteMask;                    \
-    UA_Int32 referencesSize;                    \
+    size_t referencesSize;                      \
     UA_ReferenceNode *references;
     UA_ReferenceNode *references;
 
 
 typedef struct {
 typedef struct {
@@ -28,6 +28,7 @@ typedef struct {
 } UA_Node;
 } UA_Node;
 
 
 void UA_Node_deleteAnyNodeClass(UA_Node *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_Node * UA_Node_copyAnyNodeClass(const UA_Node *node);
 
 
 /**************/
 /**************/
@@ -118,9 +119,9 @@ typedef struct {
 } UA_ReferenceTypeNode;
 } UA_ReferenceTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_ReferenceTypeNode)
 UA_TYPE_HANDLING_FUNCTIONS(UA_ReferenceTypeNode)
 
 
-/***********************/
-/* ReferenceMethodNode */
-/***********************/
+/**************/
+/* MethodNode */
+/**************/
 
 
 typedef struct {
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_STANDARD_NODEMEMBERS

+ 79 - 164
src/server/ua_nodestore.c

@@ -2,25 +2,28 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
 
 
-/* It could happen that we want to delete a node even though a function higher
-   in the call-chain still has a reference. So we count references and delete
-   once the count falls to zero. That means we copy every node to a new place
-   where it is right behind the refcount integer.
-
-   Since we copy nodes on the heap, we make the alloc for the nodeEntry bigger
-   to accommodate for the different nodeclasses (the nodeEntry may have an
-   overlength "tail"). */
-#define ALIVE_BIT (1 << 15) /* Alive bit in the refcount */
-struct nodeEntry {
-    UA_UInt16 refcount;
-    UA_Node node; // could be const, but then we cannot free it without compilers warnings
-};
+#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;
+} UA_NodeStoreEntry;
 
 
 struct UA_NodeStore {
 struct UA_NodeStore {
-    struct nodeEntry **entries;
-    UA_UInt32          size;
-    UA_UInt32          count;
-    UA_UInt32          sizePrimeIndex;
+    UA_NodeStoreEntry *entries;
+    UA_UInt32 size;
+    UA_UInt32 count;
+    UA_UInt32 sizePrimeIndex;
 };
 };
 
 
 #include "ua_nodestore_hash.inc"
 #include "ua_nodestore_hash.inc"
@@ -50,18 +53,19 @@ static UA_Int16 higher_prime_index(hash_t n) {
 
 
 /* Returns UA_TRUE if an entry was found under the nodeid. Otherwise, returns
 /* Returns UA_TRUE if an entry was found under the nodeid. Otherwise, returns
    false and sets slot to a pointer to the next free slot. */
    false and sets slot to a pointer to the next free slot. */
-static UA_Boolean containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, struct nodeEntry ***entry) {
+static UA_Boolean
+containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, UA_NodeStoreEntry **entry) {
     hash_t         h     = hash(nodeid);
     hash_t         h     = hash(nodeid);
     UA_UInt32      size  = ns->size;
     UA_UInt32      size  = ns->size;
     hash_t         index = mod(h, size);
     hash_t         index = mod(h, size);
-    struct nodeEntry **e = &ns->entries[index];
+    UA_NodeStoreEntry *e = &ns->entries[index];
 
 
-    if(*e == NULL) {
+    if(!e->taken) {
         *entry = e;
         *entry = e;
         return UA_FALSE;
         return UA_FALSE;
     }
     }
 
 
-    if(UA_NodeId_equal(&(*e)->node.nodeId, nodeid)) {
+    if(UA_NodeId_equal(&e->node.node.nodeId, nodeid)) {
         *entry = e;
         *entry = e;
         return UA_TRUE;
         return UA_TRUE;
     }
     }
@@ -71,15 +75,12 @@ static UA_Boolean containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid
         index += hash2;
         index += hash2;
         if(index >= size)
         if(index >= size)
             index -= size;
             index -= size;
-
         e = &ns->entries[index];
         e = &ns->entries[index];
-
-        if(*e == NULL) {
+        if(!e->taken) {
             *entry = e;
             *entry = e;
             return UA_FALSE;
             return UA_FALSE;
         }
         }
-
-        if(UA_NodeId_equal(&(*e)->node.nodeId, nodeid)) {
+        if(UA_NodeId_equal(&e->node.node.nodeId, nodeid)) {
             *entry = e;
             *entry = e;
             return UA_TRUE;
             return UA_TRUE;
         }
         }
@@ -93,31 +94,29 @@ static UA_Boolean containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid
    repeatedly inserts the table elements. The occupancy of the table after the
    repeatedly inserts the table elements. The occupancy of the table after the
    call will be about 50%. */
    call will be about 50%. */
 static UA_StatusCode expand(UA_NodeStore *ns) {
 static UA_StatusCode expand(UA_NodeStore *ns) {
-    UA_Int32 osize = ns->size;
-    UA_Int32 count = ns->count;
+    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 <= 32))
+    if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODESTORE_MINSIZE))
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
 
 
-
     UA_UInt32 nindex = higher_prime_index(count * 2);
     UA_UInt32 nindex = higher_prime_index(count * 2);
     UA_Int32 nsize = primes[nindex];
     UA_Int32 nsize = primes[nindex];
-    struct nodeEntry **nentries;
-    if(!(nentries = UA_malloc(sizeof(struct nodeEntry *) * nsize)))
+    UA_NodeStoreEntry *nentries;
+    if(!(nentries = UA_calloc(nsize, sizeof(UA_NodeStoreEntry))))
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
-    memset(nentries, 0, nsize * sizeof(struct nodeEntry *));
-    struct nodeEntry **oentries = ns->entries;
+    UA_NodeStoreEntry *oentries = ns->entries;
     ns->entries = nentries;
     ns->entries = nentries;
     ns->size    = nsize;
     ns->size    = nsize;
     ns->sizePrimeIndex = nindex;
     ns->sizePrimeIndex = nindex;
 
 
     // recompute the position of every entry and insert the pointer
     // recompute the position of every entry and insert the pointer
-    for(UA_Int32 i=0, j=0;i<osize && j<count;i++) {
-        if(!oentries[i])
+    for(size_t i = 0, j = 0; i < osize && j < count; i++) {
+        if(!oentries[i].taken)
             continue;
             continue;
-        struct nodeEntry **e;
-        containsNodeId(ns, &(*oentries[i]).node.nodeId, &e);  /* We know this returns an empty entry here */
+        UA_NodeStoreEntry *e;
+        containsNodeId(ns, &oentries[i].node.node.nodeId, &e);  /* We know this returns an empty entry here */
         *e = oentries[i];
         *e = oentries[i];
         j++;
         j++;
     }
     }
@@ -127,43 +126,14 @@ static UA_StatusCode expand(UA_NodeStore *ns) {
 }
 }
 
 
 /* Marks the entry dead and deletes if necessary. */
 /* Marks the entry dead and deletes if necessary. */
-static void deleteEntry(struct nodeEntry *entry) {
-    if(entry->refcount > 0)
-        return;
-    switch(entry->node.nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        UA_ObjectNode_deleteMembers((UA_ObjectNode*)&entry->node);
-        break;
-    case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_deleteMembers((UA_VariableNode*)&entry->node);
-        break;
-    case UA_NODECLASS_METHOD:
-        UA_MethodNode_deleteMembers((UA_MethodNode *)&entry->node);
-        break;
-    case UA_NODECLASS_OBJECTTYPE:
-        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode*)&entry->node);
-        break;
-    case UA_NODECLASS_VARIABLETYPE:
-        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode*)&entry->node);
-        break;
-    case UA_NODECLASS_REFERENCETYPE:
-        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode*)&entry->node);
-        break;
-    case UA_NODECLASS_DATATYPE:
-        UA_DataTypeNode_deleteMembers((UA_DataTypeNode*)&entry->node);
-        break;
-    case UA_NODECLASS_VIEW:
-        UA_ViewNode_deleteMembers((UA_ViewNode*)&entry->node);
-        break;
-    default:
-        UA_assert(UA_FALSE);
-        break;
-    }
-    UA_free(entry);
+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). */
 /** Copies the node into the entry. Then free the original node (but not its content). */
-static struct nodeEntry * nodeEntryFromNode(UA_Node *node) {
+static void fillEntry(UA_NodeStoreEntry *entry, UA_Node *node) {
     size_t nodesize = 0;
     size_t nodesize = 0;
     switch(node->nodeClass) {
     switch(node->nodeClass) {
     case UA_NODECLASS_OBJECT:
     case UA_NODECLASS_OBJECT:
@@ -193,14 +163,9 @@ static struct nodeEntry * nodeEntryFromNode(UA_Node *node) {
     default:
     default:
         UA_assert(UA_FALSE);
         UA_assert(UA_FALSE);
     }
     }
-
-    struct nodeEntry *newEntry;
-    if(!(newEntry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
-        return NULL;
-
-    memcpy(&newEntry->node, node, nodesize);
+    memcpy(&entry->node, node, nodesize);
     UA_free(node);
     UA_free(node);
-    return newEntry;
+    entry->taken = UA_TRUE;
 }
 }
 
 
 /**********************/
 /**********************/
@@ -211,152 +176,102 @@ UA_NodeStore * UA_NodeStore_new(void) {
     UA_NodeStore *ns;
     UA_NodeStore *ns;
     if(!(ns = UA_malloc(sizeof(UA_NodeStore))))
     if(!(ns = UA_malloc(sizeof(UA_NodeStore))))
         return NULL;
         return NULL;
-
-    ns->sizePrimeIndex = higher_prime_index(32);
+    ns->sizePrimeIndex = higher_prime_index(UA_NODESTORE_MINSIZE);
     ns->size = primes[ns->sizePrimeIndex];
     ns->size = primes[ns->sizePrimeIndex];
     ns->count = 0;
     ns->count = 0;
-    if(!(ns->entries = UA_malloc(sizeof(struct nodeEntry *) * ns->size))) {
+    if(!(ns->entries = UA_calloc(ns->size, sizeof(UA_NodeStoreEntry)))) {
         UA_free(ns);
         UA_free(ns);
         return NULL;
         return NULL;
     }
     }
-    memset(ns->entries, 0, ns->size * sizeof(struct nodeEntry *));
     return ns;
     return ns;
 }
 }
 
 
 void UA_NodeStore_delete(UA_NodeStore *ns) {
 void UA_NodeStore_delete(UA_NodeStore *ns) {
     UA_UInt32 size = ns->size;
     UA_UInt32 size = ns->size;
-    struct nodeEntry **entries = ns->entries;
+    UA_NodeStoreEntry *entries = ns->entries;
     for(UA_UInt32 i = 0;i < size;i++) {
     for(UA_UInt32 i = 0;i < size;i++) {
-        if(entries[i] != NULL) {
-            entries[i]->refcount &= ~ALIVE_BIT; // mark dead
-            deleteEntry(entries[i]);
-            entries[i] = NULL;
-            ns->count--;
-        }
+        if(entries[i].taken)
+            deleteEntry(&entries[i]);
     }
     }
-
     UA_free(ns->entries);
     UA_free(ns->entries);
     UA_free(ns);
     UA_free(ns);
 }
 }
 
 
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node **inserted) {
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, UA_Node **inserted) {
     if(ns->size * 3 <= ns->count * 4) {
     if(ns->size * 3 <= ns->count * 4) {
         if(expand(ns) != UA_STATUSCODE_GOOD)
         if(expand(ns) != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADINTERNALERROR;
             return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
-    // get a free slot
-    struct nodeEntry **slot;
-    //FIXME: a bit dirty workaround of preserving namespace
-    //namespace index is assumed to be valid
+
+    UA_NodeStoreEntry *entry;
     UA_NodeId tempNodeid;
     UA_NodeId tempNodeid;
-    UA_NodeId_copy(&node->nodeId, &tempNodeid);
+    tempNodeid = node->nodeId;
     tempNodeid.namespaceIndex = 0;
     tempNodeid.namespaceIndex = 0;
     if(UA_NodeId_isNull(&tempNodeid)) {
     if(UA_NodeId_isNull(&tempNodeid)) {
-        // find a unique nodeid that is not taken
-        node->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-
-        if(node->nodeId.namespaceIndex==0) //original request for ns=0 should yield ns=1
-            node->nodeId.namespaceIndex=1;
-
+        /* find a free nodeid */
+        if(node->nodeId.namespaceIndex == 0) //original request for ns=0 should yield ns=1
+            node->nodeId.namespaceIndex = 1;
         UA_Int32 identifier = ns->count+1; // start value
         UA_Int32 identifier = ns->count+1; // start value
         UA_Int32 size = ns->size;
         UA_Int32 size = ns->size;
         hash_t increase = mod2(identifier, size);
         hash_t increase = mod2(identifier, size);
         while(UA_TRUE) {
         while(UA_TRUE) {
             node->nodeId.identifier.numeric = identifier;
             node->nodeId.identifier.numeric = identifier;
-            if(!containsNodeId(ns, &node->nodeId, &slot))
+            if(!containsNodeId(ns, &node->nodeId, &entry))
                 break;
                 break;
             identifier += increase;
             identifier += increase;
             if(identifier >= size)
             if(identifier >= size)
                 identifier -= size;
                 identifier -= size;
         }
         }
     } else {
     } else {
-        UA_NodeId_deleteMembers(&tempNodeid);
-        if(containsNodeId(ns, &node->nodeId, &slot))
+        if(containsNodeId(ns, &node->nodeId, &entry))
             return UA_STATUSCODE_BADNODEIDEXISTS;
             return UA_STATUSCODE_BADNODEIDEXISTS;
     }
     }
 
 
-    struct nodeEntry *entry = nodeEntryFromNode(node);
-    if(!entry)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-
-    *slot = entry;
+    fillEntry(entry, node);
     ns->count++;
     ns->count++;
-
-    if(inserted) {
-        entry->refcount = ALIVE_BIT + 1;
-        *inserted = &entry->node;
-    } else {
-        entry->refcount = ALIVE_BIT;
-    }
-
+    if(inserted)
+        *inserted = &entry->node.node;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_Node *node,
-                                   const UA_Node **inserted) {
-    struct nodeEntry **slot;
-    const UA_NodeId *nodeId = &node->nodeId;
-    if(!containsNodeId(ns, nodeId, &slot))
+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))
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
-
-    // you try to replace an obsolete node (without threading this can't happen
-    // if the user doesn't do it deliberately in his code)
-    if(&(*slot)->node != oldNode)
+    /* that is not the node you are looking for */
+    if(&slot->node.node != oldNode)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
-
-    struct nodeEntry *entry = nodeEntryFromNode(node);
-    if(!entry)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-
-    (*slot)->refcount &= ~ALIVE_BIT; // mark dead
-    *slot = entry;
-
-    if(inserted) {
-        entry->refcount = ALIVE_BIT + 1;
-        *inserted = &entry->node;
-    } else {
-        entry->refcount = ALIVE_BIT;
-    }
+    deleteEntry(slot);
+    fillEntry(slot, node);
+    if(inserted)
+        *inserted = &slot->node.node;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-const UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
-    struct nodeEntry **slot;
+UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
+    UA_NodeStoreEntry *slot;
     if(!containsNodeId(ns, nodeid, &slot))
     if(!containsNodeId(ns, nodeid, &slot))
         return NULL;
         return NULL;
-    (*slot)->refcount++;
-    return &(*slot)->node;
+    return &slot->node.node;
 }
 }
 
 
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
-    struct nodeEntry **slot;
+    UA_NodeStoreEntry *slot;
     if(!containsNodeId(ns, nodeid, &slot))
     if(!containsNodeId(ns, nodeid, &slot))
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
-
-    // Check before if deleting the node makes the UA_NodeStore inconsistent.
-    (*slot)->refcount &= ~ALIVE_BIT; // mark dead
-    deleteEntry(*slot);
-    *slot = NULL;
+    deleteEntry(slot);
     ns->count--;
     ns->count--;
-
     /* Downsize the hashmap if it is very empty */
     /* Downsize the hashmap if it is very empty */
     if(ns->count * 8 < ns->size && ns->size > 32)
     if(ns->count * 8 < ns->size && ns->size > 32)
         expand(ns); // this can fail. we just continue with the bigger hashmap.
         expand(ns); // this can fail. we just continue with the bigger hashmap.
-
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
 void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
     for(UA_UInt32 i = 0;i < ns->size;i++) {
     for(UA_UInt32 i = 0;i < ns->size;i++) {
-        if(ns->entries[i] != NULL)
-            visitor(&ns->entries[i]->node);
+        if(ns->entries[i].taken)
+            visitor(&ns->entries[i].node.node);
     }
     }
 }
 }
-
-void UA_NodeStore_release(const UA_Node *managed) {
-    /* We know what we are doing here and remove a compiler warning. Nobody has
-       a reference to the const pointer, so we can free it. */
-    struct nodeEntry *entry = (struct nodeEntry *) ((uintptr_t)managed - offsetof(struct nodeEntry, node));
-    entry->refcount--;
-    deleteEntry(entry);
-}

+ 16 - 12
src/server/ua_nodestore.h

@@ -25,13 +25,21 @@
  * @{
  * @{
  */
  */
 
 
+/* For multithreading, nodes in the nodestore are immutable */
+#ifdef UA_MULTITHREADING
+# define UA_MT_CONST const
+#else
+# define UA_MT_CONST
+#endif
+
 struct UA_NodeStore;
 struct UA_NodeStore;
 typedef struct UA_NodeStore UA_NodeStore;
 typedef struct UA_NodeStore UA_NodeStore;
 
 
 /** Create a new nodestore */
 /** Create a new nodestore */
 UA_NodeStore * UA_NodeStore_new(void);
 UA_NodeStore * UA_NodeStore_new(void);
 
 
-/** Delete the nodestore and all nodes in it */
+/** Delete the nodestore and all nodes in it. Do not call from a read-side
+    critical section (multithreading). */
 void UA_NodeStore_delete(UA_NodeStore *ns);
 void UA_NodeStore_delete(UA_NodeStore *ns);
 
 
 /**
 /**
@@ -41,14 +49,16 @@ void UA_NodeStore_delete(UA_NodeStore *ns);
  * is not NULL, then a pointer to the managed node is returned (and must be
  * is not NULL, then a pointer to the managed node is returned (and must be
  * released).
  * released).
  */
  */
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node **inserted);
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, UA_MT_CONST UA_Node **inserted);
 
 
 /**
 /**
  * Replace an existing node in the nodestore. If the node was already replaced,
  * Replace an existing node in the nodestore. If the node was already replaced,
- * UA_STATUSCODE_BADINTERNALERROR is returned. If inserted is not NULL, a
- * pointer to the managed (immutable) node is returned.
+ * 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.
  */
  */
-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_MT_CONST UA_Node *oldNode,
+                                   UA_Node *node, UA_MT_CONST UA_Node **inserted);
 
 
 /**
 /**
  * Remove a node from the nodestore. Always succeeds, even if the node was not
  * Remove a node from the nodestore. Always succeeds, even if the node was not
@@ -62,13 +72,7 @@ UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid);
  * entirely. After the node is no longer used, it needs to be released to decrease
  * entirely. After the node is no longer used, it needs to be released to decrease
  * the reference count.
  * the reference count.
  */
  */
-const UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid);
-
-/**
- * Release a managed node. Do never call this with a node that isn't managed by a
- * nodestore.
- */
-void UA_NodeStore_release(const UA_Node *managed);
+UA_MT_CONST UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid);
 
 
 /**
 /**
  * A function that can be evaluated on all entries in a nodestore via
  * A function that can be evaluated on all entries in a nodestore via

+ 65 - 138
src/server/ua_nodestore_concurrent.c

@@ -1,83 +1,60 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 
 
-#define ALIVE_BIT (1 << 15) /* Alive bit in the refcount */
-
 struct nodeEntry {
 struct nodeEntry {
-    struct cds_lfht_node htn;      /* contains next-ptr for urcu-hashmap */
-    struct rcu_head      rcu_head; /* For call-rcu */
-    UA_UInt16 refcount;            /* Counts the amount of readers on it [alive-bit, 15 counter-bits] */
-    UA_Node node;                  /* Might be cast from any _bigger_ UA_Node* type. Allocate enough memory! */
+    struct cds_lfht_node htn; ///< Contains the next-ptr for urcu-hashmap
+    struct rcu_head rcu_head; ///< For call-rcu
+    UA_Node node; ///< Might be cast from any _bigger_ UA_Node* type. Allocate enough memory!
 };
 };
 
 
 struct UA_NodeStore {
 struct UA_NodeStore {
-    struct cds_lfht *ht; /* Hash table */
+    struct cds_lfht *ht;
 };
 };
 
 
 #include "ua_nodestore_hash.inc"
 #include "ua_nodestore_hash.inc"
 
 
-static void node_deleteMembers(UA_Node *node) {
-    switch(node->nodeClass) {
+static void deleteEntry(struct rcu_head *head) {
+    struct nodeEntry *entry = caa_container_of(head, struct nodeEntry, rcu_head);
+    switch(entry->node.nodeClass) {
     case UA_NODECLASS_OBJECT:
     case UA_NODECLASS_OBJECT:
-        UA_ObjectNode_deleteMembers((UA_ObjectNode *)node);
+        UA_ObjectNode_deleteMembers((UA_ObjectNode*)&entry->node);
         break;
         break;
     case UA_NODECLASS_VARIABLE:
     case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_deleteMembers((UA_VariableNode *)node);
+        UA_VariableNode_deleteMembers((UA_VariableNode*)&entry->node);
         break;
         break;
     case UA_NODECLASS_METHOD:
     case UA_NODECLASS_METHOD:
-        UA_MethodNode_deleteMembers((UA_MethodNode *)node);
+        UA_MethodNode_deleteMembers((UA_MethodNode*)&entry->node);
         break;
         break;
     case UA_NODECLASS_OBJECTTYPE:
     case UA_NODECLASS_OBJECTTYPE:
-        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode *)node);
+        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode*)&entry->node);
         break;
         break;
     case UA_NODECLASS_VARIABLETYPE:
     case UA_NODECLASS_VARIABLETYPE:
-        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode *)node);
+        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode*)&entry->node);
         break;
         break;
     case UA_NODECLASS_REFERENCETYPE:
     case UA_NODECLASS_REFERENCETYPE:
-        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode *)node);
+        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode*)&entry->node);
         break;
         break;
     case UA_NODECLASS_DATATYPE:
     case UA_NODECLASS_DATATYPE:
-        UA_DataTypeNode_deleteMembers((UA_DataTypeNode *)node);
+        UA_DataTypeNode_deleteMembers((UA_DataTypeNode*)&entry->node);
         break;
         break;
     case UA_NODECLASS_VIEW:
     case UA_NODECLASS_VIEW:
-        UA_ViewNode_deleteMembers((UA_ViewNode *)node);
+        UA_ViewNode_deleteMembers((UA_ViewNode*)&entry->node);
         break;
         break;
     default:
     default:
         UA_assert(UA_FALSE);
         UA_assert(UA_FALSE);
         break;
         break;
     }
     }
+    free(entry);
 }
 }
 
 
 /* We are in a rcu_read lock. So the node will not be freed under our feet. */
 /* We are in a rcu_read lock. So the node will not be freed under our feet. */
 static int compare(struct cds_lfht_node *htn, const void *orig) {
 static int compare(struct cds_lfht_node *htn, const void *orig) {
     const UA_NodeId *origid = (const UA_NodeId *)orig;
     const UA_NodeId *origid = (const UA_NodeId *)orig;
-    const UA_NodeId *newid  = &((struct nodeEntry *)htn)->node.nodeId;   /* The htn is first in the entry structure. */
+    /* The htn is first in the entry structure. */
+    const UA_NodeId *newid  = &((struct nodeEntry *)htn)->node.nodeId;
     return UA_NodeId_equal(newid, origid);
     return UA_NodeId_equal(newid, origid);
 }
 }
 
 
-/* The entry was removed from the hashtable. No more readers can get it. Since
-   all readers using the node for a longer time (outside the rcu critical
-   section) increased the refcount, we only need to wait for the refcount
-   to reach zero. */
-static void markDead(struct rcu_head *head) {
-    struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)head - offsetof(struct nodeEntry, rcu_head)); 
-    uatomic_and(&entry->refcount, ~ALIVE_BIT); // set the alive bit to zero
-    if(uatomic_read(&entry->refcount) > 0)
-        return;
-
-    node_deleteMembers(&entry->node);
-    UA_free(entry);
-}
-
-/* Free the entry if it is dead and nobody uses it anymore */
-void UA_NodeStore_release(const UA_Node *managed) {
-    struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)managed - offsetof(struct nodeEntry, node)); 
-    if(uatomic_add_return(&entry->refcount, -1) == 0) {
-        node_deleteMembers(&entry->node);
-        UA_free(entry);
-    }
-}
-
 UA_NodeStore * UA_NodeStore_new() {
 UA_NodeStore * UA_NodeStore_new() {
     UA_NodeStore *ns;
     UA_NodeStore *ns;
     if(!(ns = UA_malloc(sizeof(UA_NodeStore))))
     if(!(ns = UA_malloc(sizeof(UA_NodeStore))))
@@ -87,27 +64,27 @@ UA_NodeStore * UA_NodeStore_new() {
     ns->ht = cds_lfht_new(32, 32, 0, CDS_LFHT_AUTO_RESIZE, NULL);
     ns->ht = cds_lfht_new(32, 32, 0, CDS_LFHT_AUTO_RESIZE, NULL);
     if(!ns->ht) {
     if(!ns->ht) {
         UA_free(ns);
         UA_free(ns);
-        return NULL;
+        ns = NULL;
     }
     }
     return ns;
     return ns;
 }
 }
 
 
+/* do not call with read-side critical section held!! */
 void UA_NodeStore_delete(UA_NodeStore *ns) {
 void UA_NodeStore_delete(UA_NodeStore *ns) {
-    struct cds_lfht      *ht = ns->ht;
+    struct cds_lfht *ht = ns->ht;
     struct cds_lfht_iter  iter;
     struct cds_lfht_iter  iter;
-
-    rcu_read_lock();
     cds_lfht_first(ht, &iter);
     cds_lfht_first(ht, &iter);
+    rcu_read_lock();
     while(iter.node) {
     while(iter.node) {
         if(!cds_lfht_del(ht, iter.node)) {
         if(!cds_lfht_del(ht, iter.node)) {
-            struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)iter.node - offsetof(struct nodeEntry, htn)); 
-            call_rcu(&entry->rcu_head, markDead);
+            /* points to the htn entry, which is first */
+            struct nodeEntry *entry = (struct nodeEntry*) iter.node;
+            call_rcu(&entry->rcu_head, deleteEntry);
         }
         }
         cds_lfht_next(ht, &iter);
         cds_lfht_next(ht, &iter);
     }
     }
     rcu_read_unlock();
     rcu_read_unlock();
     cds_lfht_destroy(ht, NULL);
     cds_lfht_destroy(ht, NULL);
-
     UA_free(ns);
     UA_free(ns);
 }
 }
 
 
@@ -146,25 +123,18 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
     struct nodeEntry *entry;
     struct nodeEntry *entry;
     if(!(entry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
     if(!(entry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
-    memcpy((void*)&entry->node, node, nodesize);
+    UA_Node *newNode = &entry->node;
+    memcpy(newNode, node, nodesize);
 
 
     cds_lfht_node_init(&entry->htn);
     cds_lfht_node_init(&entry->htn);
-    entry->refcount = ALIVE_BIT;
-    if(inserted) // increase the counter before adding the node
-        entry->refcount++;
-
     struct cds_lfht_node *result;
     struct cds_lfht_node *result;
-    //FIXME: a bit dirty workaround of preserving namespace
     //namespace index is assumed to be valid
     //namespace index is assumed to be valid
     UA_NodeId tempNodeid;
     UA_NodeId tempNodeid;
-    UA_NodeId_copy(&node->nodeId, &tempNodeid);
+    tempNodeid = node->nodeId;
     tempNodeid.namespaceIndex = 0;
     tempNodeid.namespaceIndex = 0;
     if(!UA_NodeId_isNull(&tempNodeid)) {
     if(!UA_NodeId_isNull(&tempNodeid)) {
         hash_t h = hash(&node->nodeId);
         hash_t h = hash(&node->nodeId);
-        rcu_read_lock();
-        result = cds_lfht_add_unique(ns->ht, h, compare, &entry->node.nodeId, &entry->htn);
-        rcu_read_unlock();
-
+        result = cds_lfht_add_unique(ns->ht, h, compare, &newNode->nodeId, &entry->htn);
         /* If the nodeid exists already */
         /* If the nodeid exists already */
         if(result != &entry->htn) {
         if(result != &entry->htn) {
             UA_free(entry);
             UA_free(entry);
@@ -172,31 +142,28 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
         }
         }
     } else {
     } else {
         /* create a unique nodeid */
         /* create a unique nodeid */
-        ((UA_Node *)&entry->node)->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-        if(((UA_Node *)&entry->node)->nodeId.namespaceIndex == 0) //original request for ns=0 should yield ns=1
-            ((UA_Node *)&entry->node)->nodeId.namespaceIndex = 1;
-        if(((UA_Node *)&entry->node)->nodeClass==UA_NODECLASS_VARIABLE){ //set namespaceIndex in browseName in case id is generated
-        	((UA_VariableNode*)&entry->node)->browseName.namespaceIndex=((UA_Node *)&entry->node)->nodeId.namespaceIndex;
-        }
+        newNode->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
+        if(newNode->nodeId.namespaceIndex == 0) // original request for ns=0 should yield ns=1
+            newNode->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;
 
 
         unsigned long identifier;
         unsigned long identifier;
         long before, after;
         long before, after;
-        rcu_read_lock();
         cds_lfht_count_nodes(ns->ht, &before, &identifier, &after); // current amount of nodes stored
         cds_lfht_count_nodes(ns->ht, &before, &identifier, &after); // current amount of nodes stored
         identifier++;
         identifier++;
 
 
-        ((UA_Node *)&entry->node)->nodeId.identifier.numeric = identifier;
+        newNode->nodeId.identifier.numeric = identifier;
         while(UA_TRUE) {
         while(UA_TRUE) {
-            hash_t nhash = hash(&entry->node.nodeId);
-            result = cds_lfht_add_unique(ns->ht, nhash, compare, &entry->node.nodeId, &entry->htn);
+            hash_t h = hash(&newNode->nodeId);
+            result = cds_lfht_add_unique(ns->ht, h, compare, &newNode->nodeId, &entry->htn);
             if(result == &entry->htn)
             if(result == &entry->htn)
                 break;
                 break;
-
-            ((UA_Node *)&entry->node)->nodeId.identifier.numeric += (identifier * 2654435761);
+            newNode->nodeId.identifier.numeric += (identifier * 2654435761);
         }
         }
-        rcu_read_unlock();
     }
     }
-    UA_NodeId_deleteMembers(&tempNodeid);
+
     UA_free(node);
     UA_free(node);
     if(inserted)
     if(inserted)
         *inserted = &entry->node;
         *inserted = &entry->node;
@@ -205,6 +172,18 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
 
 
 UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_Node *node,
 UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_Node *node,
                                    const UA_Node **inserted) {
                                    const UA_Node **inserted) {
+    /* 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);
+    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)
+        return UA_STATUSCODE_BADINTERNALERROR;
+    
     size_t nodesize;
     size_t nodesize;
     /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
     /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
     switch(node->nodeClass) {
     switch(node->nodeClass) {
@@ -240,43 +219,16 @@ UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_
     if(!(newEntry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
     if(!(newEntry = UA_malloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
     memcpy((void*)&newEntry->node, node, nodesize);
     memcpy((void*)&newEntry->node, node, nodesize);
-
     cds_lfht_node_init(&newEntry->htn);
     cds_lfht_node_init(&newEntry->htn);
-    newEntry->refcount = ALIVE_BIT;
-    if(inserted) // increase the counter before adding the node
-        newEntry->refcount++;
-
-    hash_t h = hash(&node->nodeId);
-    struct cds_lfht_iter iter;
-    rcu_read_lock();
-    cds_lfht_lookup(ns->ht, h, compare, &node->nodeId, &iter);
-
-    /* No node found that can be replaced */
-    if(!iter.node) {
-        rcu_read_unlock();
-        UA_free(newEntry);
-        return UA_STATUSCODE_BADNODEIDUNKNOWN;
-    }
 
 
-    struct nodeEntry *oldEntry = (struct nodeEntry*) ((uintptr_t)iter.node - offsetof(struct nodeEntry, htn)); 
-    /* The node we found is obsolete*/
-    if(&oldEntry->node != oldNode) {
-        rcu_read_unlock();
-        UA_free(newEntry);
-        return UA_STATUSCODE_BADINTERNALERROR;
-    }
-
-    /* The old node is replaced by a managed node. */
     if(cds_lfht_replace(ns->ht, &iter, h, compare, &node->nodeId, &newEntry->htn) != 0) {
     if(cds_lfht_replace(ns->ht, &iter, h, compare, &node->nodeId, &newEntry->htn) != 0) {
         /* Replacing failed. Maybe the node got replaced just before this thread tried to.*/
         /* Replacing failed. Maybe the node got replaced just before this thread tried to.*/
-        rcu_read_unlock();
         UA_free(newEntry);
         UA_free(newEntry);
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
         
         
     /* If an entry got replaced, mark it as dead. */
     /* If an entry got replaced, mark it as dead. */
-    call_rcu(&oldEntry->rcu_head, markDead);
-    rcu_read_unlock();
+    call_rcu(&oldEntry->rcu_head, deleteEntry);
     UA_free(node);
     UA_free(node);
 
 
     if(inserted)
     if(inserted)
@@ -285,58 +237,33 @@ UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node *oldNode, UA_
 }
 }
 
 
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
 UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid) {
-    hash_t nhash = hash(nodeid);
+    hash_t h = hash(nodeid);
     struct cds_lfht_iter iter;
     struct cds_lfht_iter iter;
-
-    rcu_read_lock();
-    /* If this fails, then the node has already been removed. */
-    cds_lfht_lookup(ns->ht, nhash, compare, &nodeid, &iter);
-    if(!iter.node || cds_lfht_del(ns->ht, iter.node) != 0) {
-        rcu_read_unlock();
+    cds_lfht_lookup(ns->ht, h, compare, &nodeid, &iter);
+    if(!iter.node || cds_lfht_del(ns->ht, iter.node) != 0)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
-    }
-
-    struct nodeEntry *entry = (struct nodeEntry*) ((uintptr_t)iter.node - offsetof(struct nodeEntry, htn)); 
-    call_rcu(&entry->rcu_head, markDead);
-    rcu_read_unlock();
-
+    struct nodeEntry *entry = (struct nodeEntry*)iter.node;
+    call_rcu(&entry->rcu_head, deleteEntry);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 const UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
 const UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid) {
-    hash_t nhash = hash(nodeid);
+    hash_t h = hash(nodeid);
     struct cds_lfht_iter iter;
     struct cds_lfht_iter iter;
-
-    rcu_read_lock();
-    cds_lfht_lookup(ns->ht, nhash, compare, nodeid, &iter);
-    struct nodeEntry *found_entry = (struct nodeEntry *)cds_lfht_iter_get_node(&iter);
-
-    if(!found_entry) {
-        rcu_read_unlock();
+    cds_lfht_lookup(ns->ht, h, compare, nodeid, &iter);
+    struct nodeEntry *found_entry = (struct nodeEntry*)iter.node;
+    if(!found_entry)
         return NULL;
         return NULL;
-    }
-
-    /* This is done within a read-lock. The node will not be marked dead within a read-lock. */
-    uatomic_inc(&found_entry->refcount);
-    rcu_read_unlock();
     return &found_entry->node;
     return &found_entry->node;
 }
 }
 
 
 void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
 void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visitor) {
-    struct cds_lfht     *ht = ns->ht;
+    struct cds_lfht *ht = ns->ht;
     struct cds_lfht_iter iter;
     struct cds_lfht_iter iter;
-
-    rcu_read_lock();
     cds_lfht_first(ht, &iter);
     cds_lfht_first(ht, &iter);
     while(iter.node != NULL) {
     while(iter.node != NULL) {
-        struct nodeEntry *found_entry = (struct nodeEntry *)cds_lfht_iter_get_node(&iter);
-        uatomic_inc(&found_entry->refcount);
-        const UA_Node      *node = &found_entry->node;
-        rcu_read_unlock();
-        visitor(node);
-        UA_NodeStore_release((const UA_Node *)node);
-        rcu_read_lock();
+        struct nodeEntry *found_entry = (struct nodeEntry*)iter.node;
+        visitor(&found_entry->node);
         cds_lfht_next(ht, &iter);
         cds_lfht_next(ht, &iter);
     }
     }
-    rcu_read_unlock();
 }
 }

+ 36 - 49
src/server/ua_securechannel_manager.c

@@ -2,9 +2,9 @@
 #include "ua_session.h"
 #include "ua_session.h"
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
 
 
-UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm,
-        size_t maxChannelCount, UA_UInt32 tokenLifetime,
-        UA_UInt32 startChannelId, UA_UInt32 startTokenId) {
+UA_StatusCode
+UA_SecureChannelManager_init(UA_SecureChannelManager *cm, size_t maxChannelCount, UA_UInt32 tokenLifetime,
+                             UA_UInt32 startChannelId, UA_UInt32 startTokenId) {
     LIST_INIT(&cm->channels);
     LIST_INIT(&cm->channels);
     cm->lastChannelId = startChannelId;
     cm->lastChannelId = startChannelId;
     cm->lastTokenId = startTokenId;
     cm->lastTokenId = startTokenId;
@@ -16,8 +16,7 @@ UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm,
 
 
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
     channel_list_entry *entry, *temp;
     channel_list_entry *entry, *temp;
-    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp)
-    {
+    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp) {
         LIST_REMOVE(entry, pointers);
         LIST_REMOVE(entry, pointers);
         UA_SecureChannel_deleteMembersCleanup(&entry->channel);
         UA_SecureChannel_deleteMembersCleanup(&entry->channel);
         UA_free(entry);
         UA_free(entry);
@@ -25,15 +24,13 @@ void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
 }
 }
 
 
 /* remove channels that were not renewed or who have no connection attached */
 /* remove channels that were not renewed or who have no connection attached */
-void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm,
-        UA_DateTime now) {
+void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime now) {
     channel_list_entry *entry, *temp;
     channel_list_entry *entry, *temp;
-    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp)
-    {
-        UA_DateTime timeout = entry->channel.securityToken.createdAt
-                + ((UA_DateTime) entry->channel.securityToken.revisedLifetime
-                        * 10000);
-        if (timeout < now || !entry->channel.connection) {
+    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp) {
+        UA_DateTime timeout =
+            entry->channel.securityToken.createdAt +
+            ((UA_DateTime)entry->channel.securityToken.revisedLifetime * 10000);
+        if(timeout < now || !entry->channel.connection) {
             LIST_REMOVE(entry, pointers);
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
 #ifndef UA_MULTITHREADING
 #ifndef UA_MULTITHREADING
@@ -43,28 +40,23 @@ void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm,
                     &cm->currentChannelCount, -1);
                     &cm->currentChannelCount, -1);
 #endif
 #endif
             UA_free(entry);
             UA_free(entry);
-        } else if (entry->channel.nextSecurityToken.tokenId > 0) {
+        } else if(entry->channel.nextSecurityToken.tokenId > 0) {
             UA_SecureChannel_revolveTokens(&entry->channel);
             UA_SecureChannel_revolveTokens(&entry->channel);
         }
         }
     }
     }
 }
 }
 
 
-UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm,
-        UA_Connection *conn, const UA_OpenSecureChannelRequest *request,
-        UA_OpenSecureChannelResponse *response) {
-
-    if (request->securityMode != UA_MESSAGESECURITYMODE_NONE) {
+UA_StatusCode
+UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
+                             const UA_OpenSecureChannelRequest *request,
+                             UA_OpenSecureChannelResponse *response) {
+    if(request->securityMode != UA_MESSAGESECURITYMODE_NONE)
         return UA_STATUSCODE_BADSECURITYMODEREJECTED;
         return UA_STATUSCODE_BADSECURITYMODEREJECTED;
-
-    }
-
-    channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
-    if (!entry) {
+    if(cm->currentChannelCount >= cm->maxChannelCount)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
-    }
-    if (cm->currentChannelCount >= cm->maxChannelCount) {
+    channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
+    if(!entry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
-    }
 #ifndef UA_MULTITHREADING
 #ifndef UA_MULTITHREADING
     cm->currentChannelCount++;
     cm->currentChannelCount++;
 #else
 #else
@@ -83,7 +75,7 @@ UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm,
             (request->requestedLifetime > cm->maxChannelLifetime) ?
             (request->requestedLifetime > cm->maxChannelLifetime) ?
                     cm->maxChannelLifetime : request->requestedLifetime;
                     cm->maxChannelLifetime : request->requestedLifetime;
     /* pragmatic workaround to get clients requesting lifetime of 0 working */
     /* pragmatic workaround to get clients requesting lifetime of 0 working */
-    if (entry->channel.securityToken.revisedLifetime == 0)
+    if(entry->channel.securityToken.revisedLifetime == 0)
         entry->channel.securityToken.revisedLifetime = cm->maxChannelLifetime;
         entry->channel.securityToken.revisedLifetime = cm->maxChannelLifetime;
 
 
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
@@ -100,15 +92,16 @@ UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager *cm,
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_SecureChannelManager_renew(UA_SecureChannelManager *cm,
-        UA_Connection *conn, const UA_OpenSecureChannelRequest *request,
-        UA_OpenSecureChannelResponse *response) {
+UA_StatusCode
+UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_Connection *conn,
+                              const UA_OpenSecureChannelRequest *request,
+                              UA_OpenSecureChannelResponse *response) {
     UA_SecureChannel *channel = conn->channel;
     UA_SecureChannel *channel = conn->channel;
-    if (!channel)
+    if(!channel)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
 
 
     /* if no security token is already issued */
     /* if no security token is already issued */
-    if (channel->nextSecurityToken.tokenId == 0) {
+    if(channel->nextSecurityToken.tokenId == 0) {
         channel->nextSecurityToken.channelId = channel->securityToken.channelId;
         channel->nextSecurityToken.channelId = channel->securityToken.channelId;
         //FIXME: UaExpert seems not to use the new tokenid
         //FIXME: UaExpert seems not to use the new tokenid
         channel->nextSecurityToken.tokenId = cm->lastTokenId++;
         channel->nextSecurityToken.tokenId = cm->lastTokenId++;
@@ -119,45 +112,39 @@ UA_StatusCode UA_SecureChannelManager_renew(UA_SecureChannelManager *cm,
                         cm->maxChannelLifetime : request->requestedLifetime;
                         cm->maxChannelLifetime : request->requestedLifetime;
 
 
         /* pragmatic workaround to get clients requesting lifetime of 0 working */
         /* pragmatic workaround to get clients requesting lifetime of 0 working */
-        if (channel->nextSecurityToken.revisedLifetime == 0)
+        if(channel->nextSecurityToken.revisedLifetime == 0)
             channel->nextSecurityToken.revisedLifetime = cm->maxChannelLifetime;
             channel->nextSecurityToken.revisedLifetime = cm->maxChannelLifetime;
     }
     }
 
 
-    if (channel->clientNonce.data)
+    if(channel->clientNonce.data)
         UA_ByteString_deleteMembers(&channel->clientNonce);
         UA_ByteString_deleteMembers(&channel->clientNonce);
 
 
     UA_ByteString_copy(&request->clientNonce, &channel->clientNonce);
     UA_ByteString_copy(&request->clientNonce, &channel->clientNonce);
     UA_ByteString_copy(&channel->serverNonce, &response->serverNonce);
     UA_ByteString_copy(&channel->serverNonce, &response->serverNonce);
-    UA_ChannelSecurityToken_copy(&channel->nextSecurityToken,
-            &response->securityToken);
+    UA_ChannelSecurityToken_copy(&channel->nextSecurityToken, &response->securityToken);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_SecureChannel *
-UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
+UA_SecureChannel * UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
     channel_list_entry *entry;
     channel_list_entry *entry;
-    LIST_FOREACH(entry, &cm->channels, pointers)
-    {
-        if (entry->channel.securityToken.channelId == channelId)
+    LIST_FOREACH(entry, &cm->channels, pointers) {
+        if(entry->channel.securityToken.channelId == channelId)
             return &entry->channel;
             return &entry->channel;
     }
     }
     return NULL;
     return NULL;
 }
 }
 
 
-UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm,
-        UA_UInt32 channelId) {
+UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
     channel_list_entry *entry;
     channel_list_entry *entry;
-    LIST_FOREACH(entry, &cm->channels, pointers)
-    {
-        if (entry->channel.securityToken.channelId == channelId) {
+    LIST_FOREACH(entry, &cm->channels, pointers) {
+        if(entry->channel.securityToken.channelId == channelId) {
             LIST_REMOVE(entry, pointers);
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
             UA_free(entry);
             UA_free(entry);
 #ifndef UA_MULTITHREADING
 #ifndef UA_MULTITHREADING
             cm->currentChannelCount--;
             cm->currentChannelCount--;
 #else
 #else
-            cm->currentChannelCount = uatomic_add_return(
-                    &cm->currentChannelCount, -1);
+            cm->currentChannelCount = uatomic_add_return(&cm->currentChannelCount, -1);
 #endif
 #endif
             return UA_STATUSCODE_GOOD;
             return UA_STATUSCODE_GOOD;
         }
         }

+ 134 - 153
src/server/ua_server.c

@@ -19,6 +19,10 @@ const UA_EXPORT UA_ServerConfig UA_ServerConfig_standard = {
     .Application_applicationURI = "urn:unconfigured:open62541:open62541Server",
     .Application_applicationURI = "urn:unconfigured:open62541:open62541Server",
     .Application_applicationName = "open62541" };
     .Application_applicationName = "open62541" };
 
 
+#if defined(UA_MULTITHREADING) && !defined(NDEBUG)
+UA_THREAD_LOCAL bool rcu_locked = UA_FALSE;
+#endif
+
 static const UA_NodeId nodeIdHasSubType = {
 static const UA_NodeId nodeIdHasSubType = {
     .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
     .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
     .identifier.numeric = UA_NS0ID_HASSUBTYPE};
     .identifier.numeric = UA_NS0ID_HASSUBTYPE};
@@ -104,7 +108,10 @@ UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
 
 
 UA_StatusCode UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
 UA_StatusCode UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
                                    UA_Boolean deleteReferences) {
                                    UA_Boolean deleteReferences) {
-    return Service_DeleteNodes_single(server, &adminSession, &nodeId, deleteReferences);
+    UA_RCU_LOCK();
+    UA_StatusCode retval = Service_DeleteNodes_single(server, &adminSession, &nodeId, deleteReferences);
+    UA_RCU_UNLOCK();
+    return retval;
 }
 }
 
 
 UA_StatusCode
 UA_StatusCode
@@ -117,24 +124,28 @@ UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, const
     item.isForward = isForward;
     item.isForward = isForward;
     item.targetNodeId = targetNodeId;
     item.targetNodeId = targetNodeId;
     item.deleteBidirectional = deleteBidirectional;
     item.deleteBidirectional = deleteBidirectional;
-    return Service_DeleteReferences_single(server, &adminSession, &item);
+    UA_RCU_LOCK();
+    UA_StatusCode retval = Service_DeleteReferences_single(server, &adminSession, &item);
+    UA_RCU_UNLOCK();
+    return retval;
 }
 }
 
 
 UA_StatusCode
 UA_StatusCode
 UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
 UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
                                UA_NodeIteratorCallback callback, void *handle) {
                                UA_NodeIteratorCallback callback, void *handle) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_RCU_LOCK();
     const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
     const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
-    if(!parent)
+    if(!parent) {
+        UA_RCU_UNLOCK();
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
-    
-    for(int i=0; i<parent->referencesSize; i++) {
+    }
+    for(size_t i = 0; i < parent->referencesSize; i++) {
         UA_ReferenceNode *ref = &parent->references[i];
         UA_ReferenceNode *ref = &parent->references[i];
         retval |= callback(ref->targetId.nodeId, ref->isInverse,
         retval |= callback(ref->targetId.nodeId, ref->isInverse,
                            ref->referenceTypeId, handle);
                            ref->referenceTypeId, handle);
     }
     }
-    
-    UA_NodeStore_release(parent);
+    UA_RCU_UNLOCK();
     return retval;
     return retval;
 }
 }
 
 
@@ -148,6 +159,21 @@ UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
     item.referenceTypeId = refTypeId;
     item.referenceTypeId = refTypeId;
     item.isForward = isForward;
     item.isForward = isForward;
     item.targetNodeId = targetId;
     item.targetNodeId = targetId;
+    UA_RCU_LOCK();
+    UA_StatusCode retval = Service_AddReferences_single(server, &adminSession, &item);
+    UA_RCU_UNLOCK();
+    return retval;
+}
+
+static UA_StatusCode
+addReferenceInternal(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
+                     const UA_ExpandedNodeId targetId, UA_Boolean isForward) {
+    UA_AddReferencesItem item;
+    UA_AddReferencesItem_init(&item);
+    item.sourceNodeId = sourceId;
+    item.referenceTypeId = refTypeId;
+    item.isForward = isForward;
+    item.targetNodeId = targetId;
     return Service_AddReferences_single(server, &adminSession, &item);
     return Service_AddReferences_single(server, &adminSession, &item);
 }
 }
 
 
@@ -167,29 +193,26 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                     const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
                     const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
-    UA_AddNodesResult result;
-    UA_AddNodesResult_init(&result);
-
     UA_AddNodesItem item;
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
     UA_AddNodesItem_init(&item);
-    result.statusCode = UA_QualifiedName_copy(&browseName, &item.browseName);
+    item.parentNodeId.nodeId = parentNodeId;
+    item.referenceTypeId = referenceTypeId;
+    item.requestedNewNodeId.nodeId = requestedNewNodeId;
+    item.browseName = browseName;
     item.nodeClass = nodeClass;
     item.nodeClass = nodeClass;
-    result.statusCode |= UA_NodeId_copy(&parentNodeId, &item.parentNodeId.nodeId);
-    result.statusCode |= UA_NodeId_copy(&referenceTypeId, &item.referenceTypeId);
-    result.statusCode |= UA_NodeId_copy(&requestedNewNodeId,
-                                        &item.requestedNewNodeId.nodeId);
-    result.statusCode |= UA_NodeId_copy(&typeDefinition, &item.typeDefinition.nodeId);
-    UA_NodeAttributes *attrCopy = UA_alloca(attributeType->memSize);
-    result.statusCode |= UA_copy(attr, attrCopy, attributeType);
-    if(result.statusCode == UA_STATUSCODE_GOOD)
-        Service_AddNodes_single(server, &adminSession, &item, attrCopy, &result);
+    item.typeDefinition.nodeId = typeDefinition;
+    item.nodeAttributes = (UA_ExtensionObject){.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE,
+                                               .content.decoded = {attributeType, (void*)(uintptr_t)attr}};
+    UA_AddNodesResult result;
+    UA_AddNodesResult_init(&result);
+    UA_RCU_LOCK();
+    Service_AddNodes_single(server, &adminSession, &item, &result);
+    UA_RCU_UNLOCK();
 
 
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
     if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
         *outNewNodeId = result.addedNodeId;
         *outNewNodeId = result.addedNodeId;
     else
     else
         UA_AddNodesResult_deleteMembers(&result);
         UA_AddNodesResult_deleteMembers(&result);
-    UA_AddNodesItem_deleteMembers(&item);
-    UA_deleteMembers(attrCopy, attributeType);
     return result.statusCode;
     return result.statusCode;
 }
 }
 
 
@@ -208,11 +231,8 @@ void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *network
     server->networkLayers[server->networkLayersSize] = networkLayer;
     server->networkLayers[server->networkLayersSize] = networkLayer;
     server->networkLayersSize++;
     server->networkLayersSize++;
 
 
-    if(server->description.discoveryUrlsSize < 0)
-        server->description.discoveryUrlsSize = 0;
-    UA_String* newUrls;
-    newUrls = UA_realloc(server->description.discoveryUrls,
-                         sizeof(UA_String)*(server->description.discoveryUrlsSize+1));
+    UA_String* newUrls = UA_realloc(server->description.discoveryUrls,
+                                    sizeof(UA_String)*(server->description.discoveryUrlsSize+1));
     if(!newUrls) {
     if(!newUrls) {
         UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Adding discoveryUrl");
         UA_LOG_ERROR(server->logger, UA_LOGCATEGORY_SERVER, "Adding discoveryUrl");
         return;
         return;
@@ -221,7 +241,7 @@ void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *network
     UA_String_copy(&networkLayer->discoveryUrl,
     UA_String_copy(&networkLayer->discoveryUrl,
                    &server->description.discoveryUrls[server->description.discoveryUrlsSize]);
                    &server->description.discoveryUrls[server->description.discoveryUrlsSize]);
     server->description.discoveryUrlsSize++;
     server->description.discoveryUrlsSize++;
-    for(UA_Int32 i = 0; i < server->endpointDescriptionsSize; i++) {
+    for(size_t i = 0; i < server->endpointDescriptionsSize; i++) {
         if(!server->endpointDescriptions[i].endpointUrl.data)
         if(!server->endpointDescriptions[i].endpointUrl.data)
             UA_String_copy(&networkLayer->discoveryUrl,
             UA_String_copy(&networkLayer->discoveryUrl,
                            &server->endpointDescriptions[i].endpointUrl);
                            &server->endpointDescriptions[i].endpointUrl);
@@ -229,7 +249,7 @@ void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer *network
 }
 }
 
 
 void UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate) {
 void UA_Server_setServerCertificate(UA_Server *server, UA_ByteString certificate) {
-    for(UA_Int32 i = 0; i < server->endpointDescriptionsSize; i++)
+    for(size_t i = 0; i < server->endpointDescriptionsSize; i++)
         UA_ByteString_copy(&certificate,
         UA_ByteString_copy(&certificate,
                            &server->endpointDescriptions[i].serverCertificate);
                            &server->endpointDescriptions[i].serverCertificate);
 }
 }
@@ -245,6 +265,7 @@ void UA_Server_setLogger(UA_Server *server, UA_Logger logger) {
 /* The server needs to be stopped before it can be deleted */
 /* The server needs to be stopped before it can be deleted */
 void UA_Server_delete(UA_Server *server) {
 void UA_Server_delete(UA_Server *server) {
     // Delete the timed work
     // Delete the timed work
+    UA_RCU_LOCK();
     UA_Server_deleteAllRepeatedJobs(server);
     UA_Server_deleteAllRepeatedJobs(server);
 
 
     // Delete all internal data
     // Delete all internal data
@@ -256,11 +277,9 @@ void UA_Server_delete(UA_Server *server) {
     UA_Server_deleteExternalNamespaces(server);
     UA_Server_deleteExternalNamespaces(server);
 #endif
 #endif
     UA_ByteString_deleteMembers(&server->serverCertificate);
     UA_ByteString_deleteMembers(&server->serverCertificate);
-    UA_Array_delete(server->namespaces, &UA_TYPES[UA_TYPES_STRING],
-                    server->namespacesSize);
-    UA_Array_delete(server->endpointDescriptions,
-                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION],
-                    server->endpointDescriptionsSize);
+    UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
+    UA_Array_delete(server->endpointDescriptions, server->endpointDescriptionsSize,
+                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
 
 
     // Delete the network layers
     // Delete the network layers
     for(size_t i = 0; i < server->networkLayersSize; i++) {
     for(size_t i = 0; i < server->networkLayersSize; i++) {
@@ -270,6 +289,7 @@ void UA_Server_delete(UA_Server *server) {
     }
     }
     UA_free(server->networkLayers);
     UA_free(server->networkLayers);
 
 
+    UA_RCU_UNLOCK();
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     /* so the workers don't spin if the queue is empty */
     /* so the workers don't spin if the queue is empty */
     pthread_cond_destroy(&server->dispatchQueue_condition);
     pthread_cond_destroy(&server->dispatchQueue_condition);
@@ -320,9 +340,9 @@ readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
     status->secondsTillShutdown = 0;
     status->secondsTillShutdown = 0;
 
 
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
-    value->value.arrayLength = -1;
+    value->value.arrayLength = 0;
     value->value.data = status;
     value->value.data = status;
-    value->value.arrayDimensionsSize = -1;
+    value->value.arrayDimensionsSize = 0;
     value->value.arrayDimensions = NULL;
     value->value.arrayDimensions = NULL;
     value->hasValue = UA_TRUE;
     value->hasValue = UA_TRUE;
     if(sourceTimeStamp) {
     if(sourceTimeStamp) {
@@ -425,7 +445,7 @@ addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletyp
 }
 }
 
 
 UA_Server * UA_Server_new(UA_ServerConfig config) {
 UA_Server * UA_Server_new(UA_ServerConfig config) {
-    UA_Server *server = UA_malloc(sizeof(UA_Server));
+    UA_Server *server = UA_calloc(1, sizeof(UA_Server));
     if(!server)
     if(!server)
         return NULL;
         return NULL;
 
 
@@ -438,46 +458,27 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    	rcu_register_thread();
    	rcu_register_thread();
     cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
     cds_wfcq_init(&server->dispatchQueue_head, &server->dispatchQueue_tail);
     cds_lfs_init(&server->mainLoopJobs);
     cds_lfs_init(&server->mainLoopJobs);
-    server->delayedJobs = NULL;
+    UA_RCU_LOCK();
 #endif
 #endif
 
 
-    // logger
-    server->logger = NULL;
-
     // random seed
     // random seed
     server->random_seed = (UA_UInt32)UA_DateTime_now();
     server->random_seed = (UA_UInt32)UA_DateTime_now();
 
 
-    // networklayers
-    server->networkLayers = NULL;
-    server->networkLayersSize = 0;
-
-    UA_ByteString_init(&server->serverCertificate);
-
     // mockup application description
     // mockup application description
     UA_ApplicationDescription_init(&server->description);
     UA_ApplicationDescription_init(&server->description);
     server->description.productUri = UA_STRING_ALLOC(PRODUCT_URI);
     server->description.productUri = UA_STRING_ALLOC(PRODUCT_URI);
-    server->description.applicationUri =
-        UA_STRING_ALLOC(server->config.Application_applicationURI);
-    server->description.discoveryUrlsSize = 0;
+    server->description.applicationUri = UA_STRING_ALLOC(server->config.Application_applicationURI);
 
 
     server->description.applicationName =
     server->description.applicationName =
         UA_LOCALIZEDTEXT_ALLOC("en_US", server->config.Application_applicationName);
         UA_LOCALIZEDTEXT_ALLOC("en_US", server->config.Application_applicationName);
     server->description.applicationType = UA_APPLICATIONTYPE_SERVER;
     server->description.applicationType = UA_APPLICATIONTYPE_SERVER;
 
 
-#ifdef UA_EXTERNAL_NAMESPACES
-    server->externalNamespacesSize = 0;
-    server->externalNamespaces = NULL;
-#endif
-
     /* ns0 and ns1 */
     /* ns0 and ns1 */
-    server->namespaces = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 2);
+    server->namespaces = UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
     server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
     server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
     UA_String_copy(&server->description.applicationUri, &server->namespaces[1]);
     UA_String_copy(&server->description.applicationUri, &server->namespaces[1]);
     server->namespacesSize = 2;
     server->namespacesSize = 2;
 
 
-    server->endpointDescriptions = NULL;
-    server->endpointDescriptionsSize = 0;
-
     UA_EndpointDescription *endpoint = UA_EndpointDescription_new(); // todo: check return code
     UA_EndpointDescription *endpoint = UA_EndpointDescription_new(); // todo: check return code
     if(endpoint) {
     if(endpoint) {
         endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
         endpoint->securityMode = UA_MESSAGESECURITYMODE_NONE;
@@ -494,7 +495,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
             size++;
             size++;
         }
         }
         endpoint->userIdentityTokensSize = size;
         endpoint->userIdentityTokensSize = size;
-        endpoint->userIdentityTokens = UA_Array_new(&UA_TYPES[UA_TYPES_USERTOKENPOLICY], size);
+        endpoint->userIdentityTokens = UA_Array_new(size, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
 
 
         int currentIndex = 0;
         int currentIndex = 0;
         if(server->config.Login_enableAnonymous){
         if(server->config.Login_enableAnonymous){
@@ -697,8 +698,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType);
 
 
     // complete bootstrap of hassubtype
     // complete bootstrap of hassubtype
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_TRUE);
 
 
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasproperty, "HasProperty");
     copyNames((UA_Node*)hasproperty, "HasProperty");
@@ -818,8 +819,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     addNodeInternal(server, (UA_Node*)referencetypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
     addNodeInternal(server, (UA_Node*)referencetypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
                     nodeIdOrganizes);
                     nodeIdOrganizes);
 
 
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), nodeIdOrganizes,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), nodeIdOrganizes,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES), UA_TRUE);
 
 
     /**********************/
     /**********************/
     /* Basic Object Types */
     /* Basic Object Types */
@@ -834,18 +835,18 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     addObjectTypeNode(server, "BaseObjectType", UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER,
     addObjectTypeNode(server, "BaseObjectType", UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER,
                       UA_NS0ID_ORGANIZES);
                       UA_NS0ID_ORGANIZES);
     addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTTYPESFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTTYPESFOLDER), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
     addObjectTypeNode(server, "ServerType", UA_NS0ID_SERVERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerType", UA_NS0ID_SERVERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerDiagnosticsType", UA_NS0ID_SERVERDIAGNOSTICSTYPE,
     addObjectTypeNode(server, "ServerDiagnosticsType", UA_NS0ID_SERVERDIAGNOSTICSTYPE,
                       UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
                       UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
@@ -864,8 +865,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)datatypes, "DataTypes");
     copyNames((UA_Node*)datatypes, "DataTypes");
     datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
     datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
     addNodeInternal(server, (UA_Node*)datatypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), nodeIdOrganizes);
     addNodeInternal(server, (UA_Node*)datatypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), nodeIdOrganizes);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATATYPESFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATATYPESFOLDER), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
 
 
     addDataTypeNode(server, "BaseDataType", UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER);
     addDataTypeNode(server, "BaseDataType", UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER);
     addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, UA_NS0ID_BASEDATATYPE);
@@ -905,8 +906,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
     variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
     addNodeInternal(server, (UA_Node*)variabletypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
     addNodeInternal(server, (UA_Node*)variabletypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
                     nodeIdOrganizes);
                     nodeIdOrganizes);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
     addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE,
     addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE,
                                   UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
                                   UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
     addVariableTypeNode_subtype(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
     addVariableTypeNode_subtype(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
@@ -929,8 +930,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
     servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
     addNodeInternal(server, (UA_Node*)servernode, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
     addNodeInternal(server, (UA_Node*)servernode, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                     nodeIdOrganizes);
                     nodeIdOrganizes);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE), UA_TRUE);
 
 
     UA_VariableNode *namespaceArray = UA_VariableNode_new();
     UA_VariableNode *namespaceArray = UA_VariableNode_new();
     copyNames((UA_Node*)namespaceArray, "NamespaceArray");
     copyNames((UA_Node*)namespaceArray, "NamespaceArray");
@@ -941,14 +942,13 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     namespaceArray->valueRank = 1;
     namespaceArray->valueRank = 1;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->minimumSamplingInterval = 1.0;
     addNodeInternal(server, (UA_Node*)namespaceArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
     addNodeInternal(server, (UA_Node*)namespaceArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
-                           UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
 
 
     UA_VariableNode *serverArray = UA_VariableNode_new();
     UA_VariableNode *serverArray = UA_VariableNode_new();
     copyNames((UA_Node*)serverArray, "ServerArray");
     copyNames((UA_Node*)serverArray, "ServerArray");
     serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
     serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
-    serverArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+    serverArray->value.variant.value.data = UA_Array_new(1, &UA_TYPES[UA_TYPES_STRING]);
     serverArray->value.variant.value.arrayLength = 1;
     serverArray->value.variant.value.arrayLength = 1;
     serverArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     serverArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     *(UA_String *)serverArray->value.variant.value.data =
     *(UA_String *)serverArray->value.variant.value.data =
@@ -956,22 +956,21 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     serverArray->valueRank = 1;
     serverArray->valueRank = 1;
     serverArray->minimumSamplingInterval = 1.0;
     serverArray->minimumSamplingInterval = 1.0;
     addNodeInternal(server, (UA_Node*)serverArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
     addNodeInternal(server, (UA_Node*)serverArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
 
 
     UA_ObjectNode *servercapablities = UA_ObjectNode_new();
     UA_ObjectNode *servercapablities = UA_ObjectNode_new();
     copyNames((UA_Node*)servercapablities, "ServerCapabilities");
     copyNames((UA_Node*)servercapablities, "ServerCapabilities");
     servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
     servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
     addNodeInternal(server, (UA_Node*)servercapablities, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
     addNodeInternal(server, (UA_Node*)servercapablities, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                     nodeIdHasComponent);
                     nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
-                           nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE), UA_TRUE);
 
 
     UA_VariableNode *localeIdArray = UA_VariableNode_new();
     UA_VariableNode *localeIdArray = UA_VariableNode_new();
     copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
     copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
     localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
     localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
-    localeIdArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+    localeIdArray->value.variant.value.data = UA_Array_new(1, &UA_TYPES[UA_TYPES_STRING]);
     localeIdArray->value.variant.value.arrayLength = 1;
     localeIdArray->value.variant.value.arrayLength = 1;
     localeIdArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     localeIdArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     *(UA_String *)localeIdArray->value.variant.value.data = UA_STRING_ALLOC("en");
     *(UA_String *)localeIdArray->value.variant.value.data = UA_STRING_ALLOC("en");
@@ -979,8 +978,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     localeIdArray->minimumSamplingInterval = 1.0;
     localeIdArray->minimumSamplingInterval = 1.0;
     addNodeInternal(server, (UA_Node*)localeIdArray,
     addNodeInternal(server, (UA_Node*)localeIdArray,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
 
 
     UA_VariableNode *maxBrowseContinuationPoints = UA_VariableNode_new();
     UA_VariableNode *maxBrowseContinuationPoints = UA_VariableNode_new();
     copyNames((UA_Node*)maxBrowseContinuationPoints, "MaxBrowseContinuationPoints");
     copyNames((UA_Node*)maxBrowseContinuationPoints, "MaxBrowseContinuationPoints");
@@ -991,8 +990,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     maxBrowseContinuationPoints->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT16];
     maxBrowseContinuationPoints->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT16];
     addNodeInternal(server, (UA_Node*)maxBrowseContinuationPoints,
     addNodeInternal(server, (UA_Node*)maxBrowseContinuationPoints,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
 
 
     /** ServerProfileArray **/
     /** ServerProfileArray **/
 #define MAX_PROFILEARRAY 16 //a *magic* limit to the number of supported profiles
 #define MAX_PROFILEARRAY 16 //a *magic* limit to the number of supported profiles
@@ -1015,7 +1014,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)serverProfileArray, "ServerProfileArray");
     copyNames((UA_Node*)serverProfileArray, "ServerProfileArray");
     serverProfileArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY;
     serverProfileArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY;
     serverProfileArray->value.variant.value.arrayLength = profileArraySize;
     serverProfileArray->value.variant.value.arrayLength = profileArraySize;
-    serverProfileArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], profileArraySize);
+    serverProfileArray->value.variant.value.data = UA_Array_new(profileArraySize, &UA_TYPES[UA_TYPES_STRING]);
     serverProfileArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     serverProfileArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     for(UA_UInt16 i=0;i<profileArraySize;i++)
     for(UA_UInt16 i=0;i<profileArraySize;i++)
         ((UA_String *)serverProfileArray->value.variant.value.data)[i] = profileArray[i];
         ((UA_String *)serverProfileArray->value.variant.value.data)[i] = profileArray[i];
@@ -1023,16 +1022,16 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     serverProfileArray->minimumSamplingInterval = 1.0;
     serverProfileArray->minimumSamplingInterval = 1.0;
     addNodeInternal(server, (UA_Node*)serverProfileArray,
     addNodeInternal(server, (UA_Node*)serverProfileArray,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
 
 
     UA_ObjectNode *serverdiagnostics = UA_ObjectNode_new();
     UA_ObjectNode *serverdiagnostics = UA_ObjectNode_new();
     copyNames((UA_Node*)serverdiagnostics, "ServerDiagnostics");
     copyNames((UA_Node*)serverdiagnostics, "ServerDiagnostics");
     serverdiagnostics->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS;
     serverdiagnostics->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS;
     addNodeInternal(server, (UA_Node*)serverdiagnostics,
     addNodeInternal(server, (UA_Node*)serverdiagnostics,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE), UA_TRUE);
 
 
     UA_VariableNode *enabledFlag = UA_VariableNode_new();
     UA_VariableNode *enabledFlag = UA_VariableNode_new();
     copyNames((UA_Node*)enabledFlag, "EnabledFlag");
     copyNames((UA_Node*)enabledFlag, "EnabledFlag");
@@ -1043,9 +1042,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     enabledFlag->minimumSamplingInterval = 1.0;
     enabledFlag->minimumSamplingInterval = 1.0;
     addNodeInternal(server, (UA_Node*)enabledFlag,
     addNodeInternal(server, (UA_Node*)enabledFlag,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), nodeIdHasProperty);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), nodeIdHasProperty);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
-                           UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
 
 
     UA_VariableNode *serverstatus = UA_VariableNode_new();
     UA_VariableNode *serverstatus = UA_VariableNode_new();
     copyNames((UA_Node*)serverstatus, "ServerStatus");
     copyNames((UA_Node*)serverstatus, "ServerStatus");
@@ -1053,8 +1051,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
     serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
     serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus, .write = NULL};
     serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus, .write = NULL};
     addNodeInternal(server, (UA_Node*)serverstatus, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
     addNodeInternal(server, (UA_Node*)serverstatus, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE), UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasTypeDefinition,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE), UA_TRUE);
 
 
     UA_VariableNode *starttime = UA_VariableNode_new();
     UA_VariableNode *starttime = UA_VariableNode_new();
     copyNames((UA_Node*)starttime, "StartTime");
     copyNames((UA_Node*)starttime, "StartTime");
@@ -1064,8 +1062,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     starttime->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
     starttime->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
     addNodeInternal(server, (UA_Node*)starttime, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
     addNodeInternal(server, (UA_Node*)starttime, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
                     nodeIdHasComponent);
                     nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *currenttime = UA_VariableNode_new();
     UA_VariableNode *currenttime = UA_VariableNode_new();
     copyNames((UA_Node*)currenttime, "CurrentTime");
     copyNames((UA_Node*)currenttime, "CurrentTime");
@@ -1075,8 +1073,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
                                                      .write = NULL};
                                                      .write = NULL};
     addNodeInternal(server, (UA_Node*)currenttime,
     addNodeInternal(server, (UA_Node*)currenttime,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *state = UA_VariableNode_new();
     UA_VariableNode *state = UA_VariableNode_new();
     UA_ServerState *stateEnum = UA_ServerState_new();
     UA_ServerState *stateEnum = UA_ServerState_new();
@@ -1084,12 +1082,12 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)state, "State");
     copyNames((UA_Node*)state, "State");
     state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
     state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
     state->value.variant.value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
     state->value.variant.value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
-    state->value.variant.value.arrayLength = -1;
+    state->value.variant.value.arrayLength = 0;
     state->value.variant.value.data = stateEnum; // points into the other object.
     state->value.variant.value.data = stateEnum; // points into the other object.
     addNodeInternal(server, (UA_Node*)state, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
     addNodeInternal(server, (UA_Node*)state, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
                     nodeIdHasComponent);
                     nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *buildinfo = UA_VariableNode_new();
     UA_VariableNode *buildinfo = UA_VariableNode_new();
     copyNames((UA_Node*)buildinfo, "BuildInfo");
     copyNames((UA_Node*)buildinfo, "BuildInfo");
@@ -1099,9 +1097,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     getBuildInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
     getBuildInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
     addNodeInternal(server, (UA_Node*)buildinfo,
     addNodeInternal(server, (UA_Node*)buildinfo,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE),
-                           UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+                         nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE), UA_TRUE);
 
 
     UA_VariableNode *producturi = UA_VariableNode_new();
     UA_VariableNode *producturi = UA_VariableNode_new();
     copyNames((UA_Node*)producturi, "ProductUri");
     copyNames((UA_Node*)producturi, "ProductUri");
@@ -1111,8 +1108,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     producturi->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     producturi->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     addNodeInternal(server, (UA_Node*)producturi,
     addNodeInternal(server, (UA_Node*)producturi,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *manufacturername = UA_VariableNode_new();
     UA_VariableNode *manufacturername = UA_VariableNode_new();
     copyNames((UA_Node*)manufacturername, "ManufacturererName");
     copyNames((UA_Node*)manufacturername, "ManufacturererName");
@@ -1122,9 +1119,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     manufacturername->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     manufacturername->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     addNodeInternal(server, (UA_Node*)manufacturername,
     addNodeInternal(server, (UA_Node*)manufacturername,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-    UA_Server_addReference(server,
-                           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *productname = UA_VariableNode_new();
     UA_VariableNode *productname = UA_VariableNode_new();
     copyNames((UA_Node*)productname, "ProductName");
     copyNames((UA_Node*)productname, "ProductName");
@@ -1134,8 +1130,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     productname->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     productname->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     addNodeInternal(server, (UA_Node*)productname,
     addNodeInternal(server, (UA_Node*)productname,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *softwareversion = UA_VariableNode_new();
     UA_VariableNode *softwareversion = UA_VariableNode_new();
     copyNames((UA_Node*)softwareversion, "SoftwareVersion");
     copyNames((UA_Node*)softwareversion, "SoftwareVersion");
@@ -1145,8 +1141,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     softwareversion->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     softwareversion->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     addNodeInternal(server, (UA_Node*)softwareversion,
     addNodeInternal(server, (UA_Node*)softwareversion,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *buildnumber = UA_VariableNode_new();
     UA_VariableNode *buildnumber = UA_VariableNode_new();
     copyNames((UA_Node*)buildnumber, "BuildNumber");
     copyNames((UA_Node*)buildnumber, "BuildNumber");
@@ -1156,8 +1152,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     buildnumber->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     buildnumber->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
     addNodeInternal(server, (UA_Node*)buildnumber,
     addNodeInternal(server, (UA_Node*)buildnumber,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *builddate = UA_VariableNode_new();
     UA_VariableNode *builddate = UA_VariableNode_new();
     copyNames((UA_Node*)builddate, "BuildDate");
     copyNames((UA_Node*)builddate, "BuildDate");
@@ -1167,8 +1163,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     builddate->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
     builddate->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
     addNodeInternal(server, (UA_Node*)builddate,
     addNodeInternal(server, (UA_Node*)builddate,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *secondstillshutdown = UA_VariableNode_new();
     UA_VariableNode *secondstillshutdown = UA_VariableNode_new();
     copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
     copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
@@ -1177,8 +1173,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     secondstillshutdown->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT32];
     secondstillshutdown->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT32];
     addNodeInternal(server, (UA_Node*)secondstillshutdown,
     addNodeInternal(server, (UA_Node*)secondstillshutdown,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
 
 
     UA_VariableNode *shutdownreason = UA_VariableNode_new();
     UA_VariableNode *shutdownreason = UA_VariableNode_new();
     copyNames((UA_Node*)shutdownreason, "ShutdownReason");
     copyNames((UA_Node*)shutdownreason, "ShutdownReason");
@@ -1187,8 +1183,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     shutdownreason->value.variant.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
     shutdownreason->value.variant.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
     addNodeInternal(server, (UA_Node*)shutdownreason,
     addNodeInternal(server, (UA_Node*)shutdownreason,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),
-                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),
+                         nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    UA_RCU_UNLOCK();
     return server;
     return server;
 }
 }
 
 
@@ -1201,28 +1198,12 @@ __UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId,
     wvalue.nodeId = nodeId;
     wvalue.nodeId = nodeId;
     wvalue.attributeId = attributeId;
     wvalue.attributeId = attributeId;
     if(attributeId != UA_ATTRIBUTEID_VALUE)
     if(attributeId != UA_ATTRIBUTEID_VALUE)
-        UA_Variant_setScalarCopy(&wvalue.value.value, value, type);
+        /* hacked cast. the target WriteValue is used as const anyway */
+        UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value, type);
     else
     else
-        UA_Variant_copy(value, &wvalue.value.value);
-    wvalue.value.hasValue = UA_TRUE;
-    UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
-    UA_NodeId_init(&wvalue.nodeId);
-    UA_WriteValue_deleteMembers(&wvalue);
-    return retval;
-}
-
-UA_StatusCode
-UA_Server_writeValueAttribute_move(UA_Server *server, const UA_NodeId nodeId, UA_Variant *value) {
-    UA_WriteValue wvalue;
-    UA_WriteValue_init(&wvalue);
-    wvalue.nodeId = nodeId;
-    wvalue.attributeId = UA_ATTRIBUTEID_VALUE;
-    wvalue.value.value = *value;
-    UA_Variant_init(value);
+        wvalue.value.value = *(const UA_Variant*)value;
     wvalue.value.hasValue = UA_TRUE;
     wvalue.value.hasValue = UA_TRUE;
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
-    UA_NodeId_init(&wvalue.nodeId);
-    UA_WriteValue_deleteMembers(&wvalue);
     return retval;
     return retval;
 }
 }
 
 
@@ -1301,7 +1282,7 @@ __UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
     else {
     else {
         memcpy(v, dv.value.data, dv.value.type->memSize);
         memcpy(v, dv.value.data, dv.value.type->memSize);
         dv.value.data = NULL;
         dv.value.data = NULL;
-        dv.value.arrayLength = -1;
+        dv.value.arrayLength = 0;
         UA_Variant_deleteMembers(&dv.value);
         UA_Variant_deleteMembers(&dv.value);
     }
     }
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;

+ 13 - 9
src/server/ua_server_binary.c

@@ -223,7 +223,9 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
         *responseType = &UA_TYPES[UA_TYPES_PUBLISHRESPONSE];
         *responseType = &UA_TYPES[UA_TYPES_PUBLISHRESPONSE];
         break;
         break;
     case UA_NS0ID_REPUBLISHREQUEST:
     case UA_NS0ID_REPUBLISHREQUEST:
-        INVOKE_SERVICE(Republish, UA_TYPES_REPUBLISHRESPONSE);
+        *service = (UA_Service)Service_Republish;
+        *requestType = &UA_TYPES[UA_TYPES_REPUBLISHREQUEST];
+        *responseType = &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE];
         break;
         break;
     case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST:
     case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST:
         *service = (UA_Service)Service_ModifySubscription;
         *service = (UA_Service)Service_ModifySubscription;
@@ -232,18 +234,18 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
         break;
         break;
     case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST:
     case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST:
         *service = (UA_Service)Service_DeleteSubscriptions;
         *service = (UA_Service)Service_DeleteSubscriptions;
-        *requestType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONREQUEST];
-        *responseType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONRESPONSE];
+        *requestType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST];
+        *responseType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE];
         break;
         break;
     case UA_NS0ID_CREATEMONITOREDITEMSREQUEST:
     case UA_NS0ID_CREATEMONITOREDITEMSREQUEST:
         *service = (UA_Service)Service_CreateMonitoredItems;
         *service = (UA_Service)Service_CreateMonitoredItems;
-        *requestType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMREQUEST];
-        *responseType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMRESPONSE];
+        *requestType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST];
+        *responseType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE];
         break;
         break;
     case UA_NS0ID_DELETEMONITOREDITEMSREQUEST:
     case UA_NS0ID_DELETEMONITOREDITEMSREQUEST:
         *service = (UA_Service)Service_DeleteMonitoredItems;
         *service = (UA_Service)Service_DeleteMonitoredItems;
-        *requestType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMREQUEST];
-        *responseType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMRESPONSE];
+        *requestType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST];
+        *responseType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE];
         break;
         break;
 #endif
 #endif
 
 
@@ -393,12 +395,14 @@ processMSG(UA_Connection *connection, UA_Server *server, const UA_ByteString *ms
 
 
     /* Test if the session is valid */
     /* Test if the session is valid */
     if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) {
     if(!session->activated && requestType->typeIndex != UA_TYPES_ACTIVATESESSIONREQUEST) {
+        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service with a non-activated session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         return;
         return;
     }
     }
 #ifndef EXTENSION_STATELESS
 #ifndef EXTENSION_STATELESS
     if(session == &anonymousSession &&
     if(session == &anonymousSession &&
-       requestType->typeIndex > UA_TYPES_CREATESESSIONREQUEST) {
+       requestType->typeIndex > UA_TYPES_ACTIVATESESSIONREQUEST) {
+        UA_LOG_INFO(server->logger, UA_LOGCATEGORY_SERVER, "Client tries to call a service without a session");
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
         sendError(channel, msg, *pos, sequenceHeader.requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
         return;
         return;
     }
     }
@@ -484,5 +488,5 @@ void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection
                         connection->sockfd, pos, targetpos);
                         connection->sockfd, pos, targetpos);
             pos = targetpos;
             pos = targetpos;
         }
         }
-    } while(msg->length > (UA_Int32)pos);
+    } while(msg->length > pos);
 }
 }

+ 1 - 8
src/server/ua_server_internal.h

@@ -36,7 +36,7 @@ struct UA_Server {
     UA_DateTime startTime;
     UA_DateTime startTime;
     UA_DateTime buildDate;
     UA_DateTime buildDate;
     UA_ApplicationDescription description;
     UA_ApplicationDescription description;
-    UA_Int32 endpointDescriptionsSize;
+    size_t endpointDescriptionsSize;
     UA_EndpointDescription *endpointDescriptions;
     UA_EndpointDescription *endpointDescriptions;
 
 
     /* Communication */
     /* Communication */
@@ -98,11 +98,4 @@ UA_StatusCode UA_Server_addDelayedJob(UA_Server *server, UA_Job job);
 
 
 void UA_Server_deleteAllRepeatedJobs(UA_Server *server);
 void UA_Server_deleteAllRepeatedJobs(UA_Server *server);
 
 
-typedef void (*UA_SendResponseCallback)(UA_Server*, UA_Session*, const void*, const UA_DataType*);
-
-void UA_Server_processRequest(UA_Server *server, UA_Session *session,
-                              const void *request, const UA_DataType *requestType,
-                              void *response, const UA_DataType *responseType,
-                              UA_SendResponseCallback *send);
-
 #endif /* UA_SERVER_INTERNAL_H_ */
 #endif /* UA_SERVER_INTERNAL_H_ */

+ 2 - 0
src/server/ua_server_worker.c

@@ -148,9 +148,11 @@ static void * workerLoop(struct workerStartData *startInfo) {
         struct DispatchJobsList *wln = (struct DispatchJobsList*)
         struct DispatchJobsList *wln = (struct DispatchJobsList*)
             cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
             cds_wfcq_dequeue_blocking(&server->dispatchQueue_head, &server->dispatchQueue_tail);
         if(wln) {
         if(wln) {
+            UA_RCU_LOCK();
             processJobs(server, wln->jobs, wln->jobsSize);
             processJobs(server, wln->jobs, wln->jobsSize);
             UA_free(wln->jobs);
             UA_free(wln->jobs);
             UA_free(wln);
             UA_free(wln);
+            UA_RCU_UNLOCK();
         } else {
         } else {
             /* sleep until a work arrives (and wakes up all worker threads) */
             /* 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
             #if defined(__APPLE__) || defined(__MACH__) // OS X does not have clock_gettime, use clock_get_time

+ 3 - 3
src/server/ua_services.h

@@ -115,8 +115,8 @@ void Service_CloseSession(UA_Server *server, UA_Session *session,
 void Service_AddNodes(UA_Server *server, UA_Session *session,
 void Service_AddNodes(UA_Server *server, UA_Session *session,
                       const UA_AddNodesRequest *request,
                       const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response);
                       UA_AddNodesResponse *response);
-void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
-                             UA_NodeAttributes *attr, UA_AddNodesResult *result);
+void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
+                             UA_AddNodesResult *result);
 
 
 /** Used to add one or more References to one or more Nodes. */
 /** Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session,
 void Service_AddReferences(UA_Server *server, UA_Session *session,
@@ -249,7 +249,7 @@ Service_Write(UA_Server *server, UA_Session *session,
 
 
 /** Single attribute writes are exposed to the userspace. The wvalue may be destroyed (deleteMembers) */
 /** Single attribute writes are exposed to the userspace. The wvalue may be destroyed (deleteMembers) */
 UA_StatusCode
 UA_StatusCode
-Service_Write_single(UA_Server *server, UA_Session *session, UA_WriteValue *wvalue);
+Service_Write_single(UA_Server *server, UA_Session *session, const UA_WriteValue *wvalue);
 
 
 // Service_HistoryUpdate
 // Service_HistoryUpdate
 /** @} */
 /** @} */

+ 107 - 87
src/server/ua_services_attribute.c

@@ -47,11 +47,12 @@ UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
     size_t dimensionsMax = 0;
     size_t dimensionsMax = 0;
     struct UA_NumericRangeDimension *dimensions = NULL;
     struct UA_NumericRangeDimension *dimensions = NULL;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_Int32 pos = 0;
+    size_t pos = 0;
     do {
     do {
         /* alloc dimensions */
         /* alloc dimensions */
         if(index >= (UA_Int32)dimensionsMax) {
         if(index >= (UA_Int32)dimensionsMax) {
-            struct UA_NumericRangeDimension *newds = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2));
+            struct UA_NumericRangeDimension *newds;
+            newds = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2));
             if(!newds) {
             if(!newds) {
                 retval = UA_STATUSCODE_BADOUTOFMEMORY;
                 retval = UA_STATUSCODE_BADOUTOFMEMORY;
                 break;
                 break;
@@ -103,6 +104,14 @@ 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) {
+    UA_Variant_init(v);
+    v->type = type;
+    v->data = (void*)(uintptr_t)p;
+    v->storageType = UA_VARIANT_DATA_NODELETE;
+}
+
 static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_TimestampsToReturn timestamps,
 static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_TimestampsToReturn timestamps,
                                           const UA_ReadValueId *id, UA_DataValue *v) {
                                           const UA_ReadValueId *id, UA_DataValue *v) {
     UA_NumericRange range;
     UA_NumericRange range;
@@ -119,10 +128,11 @@ static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_Ti
         if(vn->value.variant.callback.onRead)
         if(vn->value.variant.callback.onRead)
             vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId,
             vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId,
                                               &v->value, rangeptr);
                                               &v->value, rangeptr);
-        if(rangeptr)
+        if(!rangeptr) {
+            v->value = vn->value.variant.value;
+            v->value.storageType = UA_VARIANT_DATA_NODELETE;
+        } else
             retval = UA_Variant_copyRange(&vn->value.variant.value, &v->value, range);
             retval = UA_Variant_copyRange(&vn->value.variant.value, &v->value, range);
-        else
-            retval = UA_Variant_copy(&vn->value.variant.value, &v->value);
         if(retval == UA_STATUSCODE_GOOD)
         if(retval == UA_STATUSCODE_GOOD)
             handleSourceTimestamps(timestamps, v);
             handleSourceTimestamps(timestamps, v);
     } else {
     } else {
@@ -140,8 +150,8 @@ static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_Ti
 static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataValue *v) {
 static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataValue *v) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-        retval = UA_Variant_setScalarCopy(&v->value, &vn->value.variant.value.type->typeId,
-                                          &UA_TYPES[UA_TYPES_NODEID]);
+        forceVariantSetScalar(&v->value, &vn->value.variant.value.type->typeId,
+                              &UA_TYPES[UA_TYPES_NODEID]);
     } else {
     } else {
         /* Read from the datasource to see the data type */
         /* Read from the datasource to see the data type */
         UA_DataValue val;
         UA_DataValue val;
@@ -158,8 +168,9 @@ static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataV
 static UA_StatusCode getVariableNodeArrayDimensions(const UA_VariableNode *vn, UA_DataValue *v) {
 static UA_StatusCode getVariableNodeArrayDimensions(const UA_VariableNode *vn, UA_DataValue *v) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-        retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.value.arrayDimensions,
-                                         vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+        UA_Variant_setArray(&v->value, vn->value.variant.value.arrayDimensions,
+                            vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+        v->value.storageType = UA_VARIANT_DATA_NODELETE;
     } else {
     } else {
         /* Read the datasource to see the array dimensions */
         /* Read the datasource to see the array dimensions */
         UA_DataValue val;
         UA_DataValue val;
@@ -181,14 +192,14 @@ static const UA_String binEncoding = {sizeof("DefaultBinary")-1, (UA_Byte*)"Defa
 /** Reads a single attribute from a node in the nodestore. */
 /** Reads a single attribute from a node in the nodestore. */
 void Service_Read_single(UA_Server *server, UA_Session *session, const UA_TimestampsToReturn timestamps,
 void Service_Read_single(UA_Server *server, UA_Session *session, const UA_TimestampsToReturn timestamps,
                          const UA_ReadValueId *id, UA_DataValue *v) {
                          const UA_ReadValueId *id, UA_DataValue *v) {
-	if(id->dataEncoding.name.length >= 0 && !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
+	if(id->dataEncoding.name.length > 0 && !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
            v->hasStatus = UA_TRUE;
            v->hasStatus = UA_TRUE;
            v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
            v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
            return;
            return;
 	}
 	}
 
 
 	//index range for a non-value
 	//index range for a non-value
-	if(id->indexRange.length >= 0 && id->attributeId != UA_ATTRIBUTEID_VALUE){
+	if(id->indexRange.length > 0 && id->attributeId != UA_ATTRIBUTEID_VALUE){
 		v->hasStatus = UA_TRUE;
 		v->hasStatus = UA_TRUE;
 		v->status = UA_STATUSCODE_BADINDEXRANGENODATA;
 		v->status = UA_STATUSCODE_BADINDEXRANGENODATA;
 		return;
 		return;
@@ -204,54 +215,53 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
     /* When setting the value fails in the switch, we get an error code and set hasValue to false */
     /* When setting the value fails in the switch, we get an error code and set hasValue to false */
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     v->hasValue = UA_TRUE;
     v->hasValue = UA_TRUE;
-
     switch(id->attributeId) {
     switch(id->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODEID:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
+        forceVariantSetScalar(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
         break;
         break;
     case UA_ATTRIBUTEID_NODECLASS:
     case UA_ATTRIBUTEID_NODECLASS:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
+        forceVariantSetScalar(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
         break;
         break;
     case UA_ATTRIBUTEID_BROWSENAME:
     case UA_ATTRIBUTEID_BROWSENAME:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+        forceVariantSetScalar(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
         break;
         break;
     case UA_ATTRIBUTEID_DISPLAYNAME:
     case UA_ATTRIBUTEID_DISPLAYNAME:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        forceVariantSetScalar(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
         break;
     case UA_ATTRIBUTEID_DESCRIPTION:
     case UA_ATTRIBUTEID_DESCRIPTION:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        forceVariantSetScalar(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
         break;
     case UA_ATTRIBUTEID_WRITEMASK:
     case UA_ATTRIBUTEID_WRITEMASK:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
+        forceVariantSetScalar(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
         break;
     case UA_ATTRIBUTEID_USERWRITEMASK:
     case UA_ATTRIBUTEID_USERWRITEMASK:
-        retval = UA_Variant_setScalarCopy(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
+        forceVariantSetScalar(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
         break;
         break;
     case UA_ATTRIBUTEID_ISABSTRACT:
     case UA_ATTRIBUTEID_ISABSTRACT:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE |
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE |
                         UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
                         UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->isAbstract,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->isAbstract,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_SYMMETRIC:
     case UA_ATTRIBUTEID_SYMMETRIC:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_INVERSENAME:
     case UA_ATTRIBUTEID_INVERSENAME:
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
         CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName,
-                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName,
+                              &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
         break;
         break;
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
     case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
         CHECK_NODECLASS(UA_NODECLASS_VIEW);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->containsNoLoops,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_ViewNode*)node)->containsNoLoops,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
     case UA_ATTRIBUTEID_EVENTNOTIFIER:
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
         CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_ViewNode*)node)->eventNotifier,
-                                          &UA_TYPES[UA_TYPES_BYTE]);
+        forceVariantSetScalar(&v->value, &((const UA_ViewNode*)node)->eventNotifier,
+                              &UA_TYPES[UA_TYPES_BYTE]);
         break;
         break;
     case UA_ATTRIBUTEID_VALUE:
     case UA_ATTRIBUTEID_VALUE:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
@@ -263,8 +273,8 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
         break;
         break;
     case UA_ATTRIBUTEID_VALUERANK:
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableTypeNode*)node)->valueRank,
-                                           &UA_TYPES[UA_TYPES_INT32]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableTypeNode*)node)->valueRank,
+                              &UA_TYPES[UA_TYPES_INT32]);
         break;
         break;
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
@@ -272,41 +282,39 @@ void Service_Read_single(UA_Server *server, UA_Session *session, const UA_Timest
         break;
         break;
     case UA_ATTRIBUTEID_ACCESSLEVEL:
     case UA_ATTRIBUTEID_ACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->accessLevel,
-                                          &UA_TYPES[UA_TYPES_BYTE]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->accessLevel,
+                              &UA_TYPES[UA_TYPES_BYTE]);
         break;
         break;
     case UA_ATTRIBUTEID_USERACCESSLEVEL:
     case UA_ATTRIBUTEID_USERACCESSLEVEL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->userAccessLevel,
-                                          &UA_TYPES[UA_TYPES_BYTE]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->userAccessLevel,
+                              &UA_TYPES[UA_TYPES_BYTE]);
         break;
         break;
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
     case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval,
-                                          &UA_TYPES[UA_TYPES_DOUBLE]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval,
+                              &UA_TYPES[UA_TYPES_DOUBLE]);
         break;
         break;
     case UA_ATTRIBUTEID_HISTORIZING:
     case UA_ATTRIBUTEID_HISTORIZING:
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
         CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_VariableNode*)node)->historizing,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->historizing,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_EXECUTABLE:
     case UA_ATTRIBUTEID_EXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->executable,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_MethodNode*)node)->executable,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     case UA_ATTRIBUTEID_USEREXECUTABLE:
     case UA_ATTRIBUTEID_USEREXECUTABLE:
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
         CHECK_NODECLASS(UA_NODECLASS_METHOD);
-        retval = UA_Variant_setScalarCopy(&v->value, &((const UA_MethodNode*)node)->userExecutable,
-                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
+        forceVariantSetScalar(&v->value, &((const UA_MethodNode*)node)->userExecutable,
+                              &UA_TYPES[UA_TYPES_BOOLEAN]);
         break;
         break;
     default:
     default:
         retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
         retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
         break;
         break;
     }
     }
 
 
-    UA_NodeStore_release(node);
-
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         v->hasValue = UA_FALSE;
         v->hasValue = UA_FALSE;
         v->hasStatus = UA_TRUE;
         v->hasStatus = UA_TRUE;
@@ -333,7 +341,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
     }
 
 
     size_t size = request->nodesToReadSize;
     size_t size = request->nodesToReadSize;
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_DATAVALUE], size);
+    response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_DATAVALUE]);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
@@ -375,8 +383,8 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
     }
 
 
 #ifdef EXTENSION_STATELESS
 #ifdef EXTENSION_STATELESS
+    /* Add an expiry header for caching */
     if(session==&anonymousSession){
     if(session==&anonymousSession){
-		/* expiry header */
 		UA_ExtensionObject additionalHeader;
 		UA_ExtensionObject additionalHeader;
 		UA_ExtensionObject_init(&additionalHeader);
 		UA_ExtensionObject_init(&additionalHeader);
 		additionalHeader.typeId = UA_TYPES[UA_TYPES_VARIANT].typeId;
 		additionalHeader.typeId = UA_TYPES[UA_TYPES_VARIANT].typeId;
@@ -417,16 +425,14 @@ UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const U
                                  UA_EditNodeCallback callback, const void *data) {
                                  UA_EditNodeCallback callback, const void *data) {
     UA_StatusCode retval;
     UA_StatusCode retval;
     do {
     do {
-        const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
+        UA_MT_CONST UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
         if(!node)
         if(!node)
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
 #ifndef UA_MULTITHREADING
 #ifndef UA_MULTITHREADING
-        retval = callback(server, session, (UA_Node*)(uintptr_t)node, data);
-        UA_NodeStore_release(node);
+        retval = callback(server, session, node, data);
         return retval;
         return retval;
 #else
 #else
         UA_Node *copy = UA_Node_copyAnyNodeClass(node);
         UA_Node *copy = UA_Node_copyAnyNodeClass(node);
-        UA_NodeStore_release(node);
         if(!copy)
         if(!copy)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
         retval = callback(server, session, copy, data);
         retval = callback(server, session, copy, data);
@@ -458,7 +464,7 @@ UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session, const U
 
 
 static UA_StatusCode
 static UA_StatusCode
 Service_Write_single_ValueDataSource(UA_Server *server, UA_Session *session, const UA_VariableNode *node,
 Service_Write_single_ValueDataSource(UA_Server *server, UA_Session *session, const UA_VariableNode *node,
-                                     UA_WriteValue *wvalue) {
+                                     const UA_WriteValue *wvalue) {
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
     UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
     UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
     UA_assert(node->valueSource == UA_VALUESOURCE_DATASOURCE);
     UA_assert(node->valueSource == UA_VALUESOURCE_DATASOURCE);
@@ -479,9 +485,25 @@ Service_Write_single_ValueDataSource(UA_Server *server, UA_Session *session, con
     return retval;
     return retval;
 }
 }
 
 
+enum type_equivalence {
+    TYPE_EQUIVALENCE_NONE,
+    TYPE_EQUIVALENCE_ENUM,
+    TYPE_EQUIVALENCE_OPAQUE
+};
+
+static enum type_equivalence typeEquivalence(const UA_DataType *type) {
+    if(type->membersSize != 1 || !type->members[0].namespaceZero)
+        return TYPE_EQUIVALENCE_NONE;
+    if(type->members[0].memberTypeIndex == UA_TYPES_INT32)
+        return TYPE_EQUIVALENCE_ENUM;
+    if(type->members[0].memberTypeIndex == UA_TYPES_BYTE && type->members[0].isArray)
+        return TYPE_EQUIVALENCE_OPAQUE;
+    return TYPE_EQUIVALENCE_NONE;
+}
+
 /* In the multithreaded case, node is a copy */
 /* In the multithreaded case, node is a copy */
 static UA_StatusCode
 static UA_StatusCode
-MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node, UA_WriteValue *wvalue) {
+CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
     UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
     UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
     UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE || node->nodeClass == UA_NODECLASS_VARIABLETYPE);
     UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT);
     UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT);
@@ -499,24 +521,25 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
 
 
     /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings.
     /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings.
        nodeV contains the correct type definition. */
        nodeV contains the correct type definition. */
-    UA_Variant *newV = &wvalue->value.value;
+    const UA_Variant *newV = &wvalue->value.value;
     UA_Variant *oldV = &node->value.variant.value;
     UA_Variant *oldV = &node->value.variant.value;
     UA_Variant cast_v;
     UA_Variant cast_v;
     if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
     if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
         cast_v = wvalue->value.value;
         cast_v = wvalue->value.value;
         newV = &cast_v;
         newV = &cast_v;
-        if(oldV->type->namespaceZero && newV->type->namespaceZero &&
-           oldV->type->typeIndex == newV->type->typeIndex) {
+        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
             /* An enum was sent as an int32, or an opaque type as a bytestring. This is
                detected with the typeIndex indicated the "true" datatype. */
                detected with the typeIndex indicated the "true" datatype. */
-            newV->type = oldV->type;
+            cast_v.type = oldV->type;
         } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
         } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
                   newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) {
                   newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) {
             /* a string is written to a byte array */
             /* a string is written to a byte array */
             UA_ByteString *str = (UA_ByteString*) newV->data;
             UA_ByteString *str = (UA_ByteString*) newV->data;
-            newV->arrayLength = str->length;
-            newV->data = str->data;
-            newV->type = &UA_TYPES[UA_TYPES_BYTE];
+            cast_v.arrayLength = str->length;
+            cast_v.data = str->data;
+            cast_v.type = &UA_TYPES[UA_TYPES_BYTE];
         } else {
         } else {
             if(rangeptr)
             if(rangeptr)
                 UA_free(range.dimensions);
                 UA_free(range.dimensions);
@@ -525,13 +548,10 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
     }
     }
     
     
     if(!rangeptr) {
     if(!rangeptr) {
-        // TODO: Avoid copying the whole node and then delete the old value for multithreading
         UA_Variant_deleteMembers(&node->value.variant.value);
         UA_Variant_deleteMembers(&node->value.variant.value);
-        node->value.variant.value = *newV;
-        UA_Variant_init(&wvalue->value.value);
-    } else {
+        UA_Variant_copy(newV, &node->value.variant.value);
+    } else
         retval = UA_Variant_setRangeCopy(&node->value.variant.value, newV->data, newV->arrayLength, range);
         retval = UA_Variant_setRangeCopy(&node->value.variant.value, newV->data, newV->arrayLength, range);
-    }
     if(node->value.variant.callback.onWrite)
     if(node->value.variant.callback.onWrite)
         node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,
         node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,
                                              &node->value.variant.value, rangeptr);
                                              &node->value.variant.value, rangeptr);
@@ -541,9 +561,11 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
-MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_WriteValue *wvalue) {
+CopyAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, const UA_WriteValue *wvalue) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     void *value = wvalue->value.value.data;
     void *value = wvalue->value.value.data;
+    void *target = NULL;
+    const UA_DataType *type = NULL;
 	switch(wvalue->attributeId) {
 	switch(wvalue->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODECLASS:
     case UA_ATTRIBUTEID_NODECLASS:
@@ -552,21 +574,18 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 		break;
 		break;
 	case UA_ATTRIBUTEID_BROWSENAME:
 	case UA_ATTRIBUTEID_BROWSENAME:
 		CHECK_DATATYPE(QUALIFIEDNAME);
 		CHECK_DATATYPE(QUALIFIEDNAME);
-		UA_QualifiedName_deleteMembers(&node->browseName);
-        node->browseName = *(UA_QualifiedName*)value;
-        UA_QualifiedName_init((UA_QualifiedName*)value);
+        target = &node->browseName;
+        type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
 		break;
 		break;
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 	case UA_ATTRIBUTEID_DISPLAYNAME:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-		UA_LocalizedText_deleteMembers(&node->displayName);
-        node->displayName = *(UA_LocalizedText*)value;
-		UA_LocalizedText_init((UA_LocalizedText*)value);
+        target = &node->displayName;
+        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 		break;
 	case UA_ATTRIBUTEID_DESCRIPTION:
 	case UA_ATTRIBUTEID_DESCRIPTION:
 		CHECK_DATATYPE(LOCALIZEDTEXT);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-		UA_LocalizedText_deleteMembers(&node->description);
-        node->description = *(UA_LocalizedText*)value;
-		UA_LocalizedText_init((UA_LocalizedText*)value);
+        target = &node->description;
+        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 		break;
 	case UA_ATTRIBUTEID_WRITEMASK:
 	case UA_ATTRIBUTEID_WRITEMASK:
 		CHECK_DATATYPE(UINT32);
 		CHECK_DATATYPE(UINT32);
@@ -590,10 +609,8 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 	case UA_ATTRIBUTEID_INVERSENAME:
 	case UA_ATTRIBUTEID_INVERSENAME:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
 		CHECK_DATATYPE(LOCALIZEDTEXT);
-        UA_ReferenceTypeNode *n = (UA_ReferenceTypeNode*)node;
-		UA_LocalizedText_deleteMembers(&n->inverseName);
-        n->inverseName = *(UA_LocalizedText*)value;
-		UA_LocalizedText_init((UA_LocalizedText*)value);
+        target = &((UA_ReferenceTypeNode*)node)->inverseName;
+        type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
 		break;
 		break;
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 	case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
@@ -607,7 +624,7 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 		break;
 		break;
 	case UA_ATTRIBUTEID_VALUE:
 	case UA_ATTRIBUTEID_VALUE:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
-        retval = MoveValueIntoNode(server, session, (UA_VariableNode*)node, wvalue);
+        retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue);
 		break;
 		break;
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
 	case UA_ATTRIBUTEID_ACCESSLEVEL:
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
 		CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
@@ -643,10 +660,14 @@ MoveAttributeIntoNode(UA_Server *server, UA_Session *session, UA_Node *node, UA_
 		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
 		break;
 		break;
 	}
 	}
+    if(type) {
+        UA_deleteMembers(target, type);
+        retval = UA_copy(value, target, type);
+    }
     return retval;
     return retval;
 }
 }
 
 
-UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_WriteValue *wvalue) {
+UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, const UA_WriteValue *wvalue) {
     if(!wvalue->value.hasValue || !wvalue->value.value.data)
     if(!wvalue->value.hasValue || !wvalue->value.value.data)
         return UA_STATUSCODE_BADNODATA; // TODO: is this the right return code?
         return UA_STATUSCODE_BADNODATA; // TODO: is this the right return code?
     if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE) {
     if(wvalue->attributeId == UA_ATTRIBUTEID_VALUE) {
@@ -655,14 +676,13 @@ UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, UA_Wr
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
             return UA_STATUSCODE_BADNODEIDUNKNOWN;
         if(orig->nodeClass & (UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLE) &&
         if(orig->nodeClass & (UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLE) &&
            ((const UA_VariableNode*)orig)->valueSource == UA_VALUESOURCE_DATASOURCE) {
            ((const UA_VariableNode*)orig)->valueSource == UA_VALUESOURCE_DATASOURCE) {
-            UA_StatusCode retval = Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)orig, wvalue);
-            UA_NodeStore_release(orig);
+            UA_StatusCode retval =
+                Service_Write_single_ValueDataSource(server, session, (const UA_VariableNode*)orig, wvalue);
             return retval;
             return retval;
         }
         }
-        UA_NodeStore_release(orig);
     }
     }
     return UA_Server_editNode(server, session, &wvalue->nodeId,
     return UA_Server_editNode(server, session, &wvalue->nodeId,
-                              (UA_EditNodeCallback)MoveAttributeIntoNode, wvalue);
+                              (UA_EditNodeCallback)CopyAttributeIntoNode, wvalue);
 }
 }
 
 
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
 void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
@@ -677,7 +697,7 @@ void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest
         return;
         return;
     }
     }
 
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_STATUSCODE], request->nodesToWriteSize);
+    response->results = UA_Array_new(request->nodesToWriteSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
@@ -706,7 +726,7 @@ void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest
 #endif
 #endif
     
     
     response->resultsSize = request->nodesToWriteSize;
     response->resultsSize = request->nodesToWriteSize;
-    for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++) {
+    for(size_t i = 0;i < request->nodesToWriteSize;i++) {
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
 #endif
 #endif

+ 93 - 103
src/server/ua_services_call.c

@@ -5,16 +5,15 @@
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 #include "ua_nodes.h"
 #include "ua_nodes.h"
 
 
-static const UA_VariableNode
-*getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
-                          UA_String withBrowseName) {
-    const UA_Node *refTarget;
+static const UA_VariableNode *
+getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
+                         UA_String withBrowseName) {
     UA_NodeId hasProperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
     UA_NodeId hasProperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-    
-    for(UA_Int32 i = 0; i < ofMethod->referencesSize; i++) {
+    for(size_t i = 0; i < ofMethod->referencesSize; i++) {
         if(ofMethod->references[i].isInverse == UA_FALSE && 
         if(ofMethod->references[i].isInverse == UA_FALSE && 
             UA_NodeId_equal(&hasProperty, &ofMethod->references[i].referenceTypeId)) {
             UA_NodeId_equal(&hasProperty, &ofMethod->references[i].referenceTypeId)) {
-            refTarget = UA_NodeStore_get(server->nodestore, &ofMethod->references[i].targetId.nodeId);
+            const UA_Node *refTarget =
+                UA_NodeStore_get(server->nodestore, &ofMethod->references[i].targetId.nodeId);
             if(!refTarget)
             if(!refTarget)
                 continue;
                 continue;
             if(refTarget->nodeClass == UA_NODECLASS_VARIABLE && 
             if(refTarget->nodeClass == UA_NODECLASS_VARIABLE && 
@@ -22,123 +21,122 @@ static const UA_VariableNode
                 UA_String_equal(&withBrowseName, &refTarget->browseName.name)) {
                 UA_String_equal(&withBrowseName, &refTarget->browseName.name)) {
                 return (const UA_VariableNode*) refTarget;
                 return (const UA_VariableNode*) refTarget;
             }
             }
-            UA_NodeStore_release(refTarget);
         }
         }
     }
     }
     return NULL;
     return NULL;
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
-statisfySignature(UA_Variant *var, UA_Argument arg) {
-    if(!UA_NodeId_equal(&var->type->typeId, &arg.dataType) )
+satisfySignature(const UA_Variant *var, const UA_Argument *arg) {
+    if(!UA_NodeId_equal(&var->type->typeId, &arg->dataType) )
         return UA_STATUSCODE_BADINVALIDARGUMENT;
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     
     
-    // Note: The namespace compiler will compile nodes with their actual array dimensions, never -1
-    if(arg.arrayDimensionsSize > 0 && var->arrayDimensionsSize > 0)
-        if(var->arrayDimensionsSize != arg.arrayDimensionsSize) 
+    // Note: The namespace compiler will compile nodes with their actual array dimensions
+    // Todo: Check if this is standard conform for scalars
+    if(arg->arrayDimensionsSize > 0 && var->arrayDimensionsSize > 0)
+        if(var->arrayDimensionsSize != arg->arrayDimensionsSize) 
             return UA_STATUSCODE_BADINVALIDARGUMENT;
             return UA_STATUSCODE_BADINVALIDARGUMENT;
         
         
-        // Continue with jpfr's statisfySignature from here on
-        /* ValueRank Semantics
-         *  n >= 1: the value is an array with the specified number of dimens*ions.
-         *  n = 0: the value is an array with one or more dimensions.
-         *  n = -1: the value is a scalar.
-         *  n = -2: the value can be a scalar or an array with any number of dimensions.
-         *  n = -3:  the value can be a scalar or a one dimensional array. */
-        UA_Boolean scalar = UA_Variant_isScalar(var);
-        if(arg.valueRank == 0 && scalar)
-            return UA_STATUSCODE_BADINVALIDARGUMENT;
-        if(arg.valueRank == -1 && !scalar)
+    UA_UInt32 *varDims = var->arrayDimensions;
+    size_t varDimsSize = var->arrayDimensionsSize;
+    UA_Boolean scalar = UA_Variant_isScalar(var);
+
+    /* The dimension 1 is implicit in the array length */
+    UA_UInt32 fakeDims;
+    if(!scalar && !varDims) {
+        fakeDims = var->arrayLength;
+        varDims = &fakeDims;
+        varDimsSize = 1;
+    }
+
+    /* ValueRank Semantics
+     *  n >= 1: the value is an array with the specified number of dimens*ions.
+     *  n = 0: the value is an array with one or more dimensions.
+     *  n = -1: the value is a scalar.
+     *  n = -2: the value can be a scalar or an array with any number of dimensions.
+     *  n = -3:  the value can be a scalar or a one dimensional array. */
+    switch(arg->valueRank) {
+    case -3:
+        if(varDimsSize > 1)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-        if(arg.valueRank == -3 && var->arrayDimensionsSize > 1)
+        break;
+    case -2:
+        break;
+    case -1:
+        if(!scalar)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-        if(arg.valueRank > 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
+        break;
+    case 0:
+        if(scalar || !varDims)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-        
-        //variants do not always encode the dimension flag (e.g. 1d array)
-       if(var->arrayDimensionsSize==-1 && arg.arrayDimensionsSize == 1 &&
-    		   var->arrayLength > 0 && arg.arrayDimensions[0] == (UA_UInt32)var->arrayLength ){
-    	   return UA_STATUSCODE_GOOD;
-       }else{
-         if(arg.valueRank >= 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
+        break;
+    default:
+        break;
+    }
+
+    /* do the array dimensions match? */
+    if(arg->arrayDimensionsSize != varDimsSize)
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+    for(size_t i = 0; i < varDimsSize; i++) {
+        if(arg->arrayDimensions[i] != varDims[i])
             return UA_STATUSCODE_BADINVALIDARGUMENT;
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-         if(arg.arrayDimensionsSize >= 1) {
-            if(arg.arrayDimensionsSize != var->arrayDimensionsSize)
-                return UA_STATUSCODE_BADINVALIDARGUMENT;
-            for(UA_Int32 i = 0; i < arg.arrayDimensionsSize; i++) {
-                if(arg.arrayDimensions[i] != (UA_UInt32) var->arrayDimensions[i])
-                    return UA_STATUSCODE_BADINVALIDARGUMENT;
-            }
-         }
     }
     }
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
-argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefinition) {
-    if(argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_ARGUMENT] &&
-        argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_EXTENSIONOBJECT])
+argConformsToDefinition(const UA_VariableNode *argRequirements, size_t argsSize, const UA_Variant *args) {
+    if(argRequirements->value.variant.value.type != &UA_TYPES[UA_TYPES_ARGUMENT])
+        return UA_STATUSCODE_BADINTERNALERROR;
+    UA_Argument *argReqs = (UA_Argument*)argRequirements->value.variant.value.data;
+    size_t argReqsSize = argRequirements->value.variant.value.arrayLength;
+    if(argRequirements->valueSource != UA_VALUESOURCE_VARIANT)
         return UA_STATUSCODE_BADINTERNALERROR;
         return UA_STATUSCODE_BADINTERNALERROR;
-    if(rs->inputArgumentsSize < argDefinition->value.variant.value.arrayLength &&
-       argDefinition->value.variant.value.arrayLength > 0)
+    if(UA_Variant_isScalar(&argRequirements->value.variant.value))
+        argReqsSize = 1;
+    if(argReqsSize > argsSize)
         return UA_STATUSCODE_BADARGUMENTSMISSING;
         return UA_STATUSCODE_BADARGUMENTSMISSING;
-    if(rs->inputArgumentsSize > 0 &&
-       rs->inputArgumentsSize > argDefinition->value.variant.value.arrayLength)
+    if(argReqsSize != argsSize)
         return UA_STATUSCODE_BADINVALIDARGUMENT;
         return UA_STATUSCODE_BADINVALIDARGUMENT;
-    
-    const UA_ExtensionObject *thisArgDefExtObj;
-    UA_Variant *var;
-    UA_Argument arg;
-    size_t decodingOffset = 0;
+
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_NodeId ArgumentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ARGUMENT + UA_ENCODINGOFFSET_BINARY);
-    for(int i = 0; i<rs->inputArgumentsSize; i++) {
-        var = &rs->inputArguments[i];
-        if(argDefinition->value.variant.value.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) {
-            thisArgDefExtObj = &((const UA_ExtensionObject *) (argDefinition->value.variant.value.data))[i];
-            decodingOffset = 0;
-            
-            if(!UA_NodeId_equal(&ArgumentNodeId, &thisArgDefExtObj->typeId))
-                return UA_STATUSCODE_BADINTERNALERROR;
-                
-            retval |= UA_decodeBinary(&thisArgDefExtObj->body, &decodingOffset, &arg, &UA_TYPES[UA_TYPES_ARGUMENT]);
-        } else if(argDefinition->value.variant.value.type == &UA_TYPES[UA_TYPES_ARGUMENT])
-            arg = ((UA_Argument *) argDefinition->value.variant.value.data)[i];
-        retval |= statisfySignature(var, arg);
-    }
+    for(size_t i = 0; i < argReqsSize; i++)
+        retval |= satisfySignature(&args[i], &argReqs[i]);
     return retval;
     return retval;
 }
 }
 
 
 static void
 static void
 callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request,
 callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request,
            UA_CallMethodResult *result) {
            UA_CallMethodResult *result) {
-    const UA_MethodNode *methodCalled = (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
+    const UA_MethodNode *methodCalled =
+        (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
     if(!methodCalled) {
     if(!methodCalled) {
         result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
         result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
         return;
         return;
     }
     }
     
     
-    const UA_ObjectNode *withObject = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, &request->objectId);
+    const UA_ObjectNode *withObject =
+        (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, &request->objectId);
     if(!withObject) {
     if(!withObject) {
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
-        goto releaseMethodReturn;
+        return;
     }
     }
     
     
     if(methodCalled->nodeClass != UA_NODECLASS_METHOD) {
     if(methodCalled->nodeClass != UA_NODECLASS_METHOD) {
         result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
         result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
-        goto releaseBothReturn;
+        return;
     }
     }
     
     
     if(withObject->nodeClass != UA_NODECLASS_OBJECT && withObject->nodeClass != UA_NODECLASS_OBJECTTYPE) {
     if(withObject->nodeClass != UA_NODECLASS_OBJECT && withObject->nodeClass != UA_NODECLASS_OBJECTTYPE) {
         result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
         result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
-        goto releaseBothReturn;
+        return;
     }
     }
     
     
     /* Verify method/object relations */
     /* Verify method/object relations */
     // Object must have a hasComponent reference (or any inherited referenceType from sayd reference) 
     // Object must have a hasComponent reference (or any inherited referenceType from sayd reference) 
     // to be valid for a methodCall...
     // to be valid for a methodCall...
     result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
     result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
-    for(UA_Int32 i = 0; i < withObject->referencesSize; i++) {
+    for(size_t i = 0; i < withObject->referencesSize; i++) {
         if(withObject->references[i].referenceTypeId.identifier.numeric == UA_NS0ID_HASCOMPONENT) {
         if(withObject->references[i].referenceTypeId.identifier.numeric == UA_NS0ID_HASCOMPONENT) {
             // FIXME: Not checking any subtypes of HasComponent at the moment
             // FIXME: Not checking any subtypes of HasComponent at the moment
             if(UA_NodeId_equal(&withObject->references[i].targetId.nodeId, &methodCalled->nodeId)) {
             if(UA_NodeId_equal(&withObject->references[i].targetId.nodeId, &methodCalled->nodeId)) {
@@ -148,56 +146,48 @@ callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request
         }
         }
     }
     }
     if(result->statusCode != UA_STATUSCODE_GOOD)
     if(result->statusCode != UA_STATUSCODE_GOOD)
-        goto releaseBothReturn;
+        return;
         
         
     /* Verify method executable */
     /* Verify method executable */
     if(methodCalled->executable == UA_FALSE || methodCalled->userExecutable == UA_FALSE) {
     if(methodCalled->executable == UA_FALSE || methodCalled->userExecutable == UA_FALSE) {
         result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
         result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
-        goto releaseBothReturn;
+        return;
     }
     }
 
 
     /* Verify Input Argument count, types and sizes */
     /* Verify Input Argument count, types and sizes */
-    const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled,
-                                                                     UA_STRING("InputArguments"));
+    const UA_VariableNode *inputArguments;
+    inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
     if(inputArguments) {
     if(inputArguments) {
-        // Expects arguments
-        result->statusCode = argConformsToDefinition(request, inputArguments);
-        UA_NodeStore_release((const UA_Node*)inputArguments);
+        result->statusCode = argConformsToDefinition(inputArguments, request->inputArgumentsSize,
+                                                     request->inputArguments);
         if(result->statusCode != UA_STATUSCODE_GOOD)
         if(result->statusCode != UA_STATUSCODE_GOOD)
-            goto releaseBothReturn;
+            return;
     } else if(request->inputArgumentsSize > 0) {
     } else if(request->inputArgumentsSize > 0) {
-        // Expects no arguments, but got some
         result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
         result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
-        goto releaseBothReturn;
+        return;
     }
     }
 
 
-    const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled,
-                                                                      UA_STRING("OutputArguments"));
+    const UA_VariableNode *outputArguments =
+        getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
     if(!outputArguments) {
     if(!outputArguments) {
         // A MethodNode must have an OutputArguments variable (which may be empty)
         // A MethodNode must have an OutputArguments variable (which may be empty)
         result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
         result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
-        goto releaseBothReturn;
+        return;
     }
     }
     
     
-    // Call method if available
+    /* Call method if available */
     if(methodCalled->attachedMethod) {
     if(methodCalled->attachedMethod) {
-        result->outputArguments = UA_Array_new(&UA_TYPES[UA_TYPES_VARIANT],
-                                               outputArguments->value.variant.value.arrayLength);
+        result->outputArguments = UA_Array_new(outputArguments->value.variant.value.arrayLength,
+                                               &UA_TYPES[UA_TYPES_VARIANT]);
         result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
         result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
-        result->statusCode = methodCalled->attachedMethod(withObject->nodeId, request->inputArguments,
-                                                          result->outputArguments, methodCalled->methodHandle);
+        result->statusCode = methodCalled->attachedMethod(methodCalled->methodHandle, withObject->nodeId,
+                                                          request->inputArgumentsSize, request->inputArguments,
+                                                          result->outputArgumentsSize, result->outputArguments);
     }
     }
     else
     else
         result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
         result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
     
     
-    /* FIXME: Verify Output Argument count, types and sizes */
-    if(outputArguments)
-        UA_NodeStore_release((const UA_Node*)outputArguments);
-
- releaseBothReturn:
-    UA_NodeStore_release((const UA_Node*)withObject);
- releaseMethodReturn:
-    UA_NodeStore_release((const UA_Node*)methodCalled);
+    /* TODO: Verify Output Argument count, types and sizes */
 }
 }
 
 
 void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,
 void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,
@@ -207,14 +197,14 @@ void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *
         return;
         return;
     }
     }
 
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_CALLMETHODRESULT],
-                                     request->methodsToCallSize);
+    response->results = UA_Array_new(request->methodsToCallSize,
+                                     &UA_TYPES[UA_TYPES_CALLMETHODRESULT]);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
     }
     }
     response->resultsSize = request->methodsToCallSize;
     response->resultsSize = request->methodsToCallSize;
     
     
-    for(UA_Int32 i = 0; i < request->methodsToCallSize;i++)
+    for(size_t i = 0; i < request->methodsToCallSize;i++)
         callMethod(server, session, &request->methodsToCall[i], &response->results[i]);
         callMethod(server, session, &request->methodsToCall[i], &response->results[i]);
 }
 }

+ 4 - 5
src/server/ua_services_discovery.c

@@ -26,14 +26,14 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
 	UA_Boolean *relevant_endpoints = UA_alloca(sizeof(UA_Boolean)*server->endpointDescriptionsSize);
 	UA_Boolean *relevant_endpoints = UA_alloca(sizeof(UA_Boolean)*server->endpointDescriptionsSize);
 #endif /*NO_ALLOCA */
 #endif /*NO_ALLOCA */
     size_t relevant_count = 0;
     size_t relevant_count = 0;
-    for(UA_Int32 j = 0; j < server->endpointDescriptionsSize; j++) {
+    for(size_t j = 0; j < server->endpointDescriptionsSize; j++) {
         relevant_endpoints[j] = UA_FALSE;
         relevant_endpoints[j] = UA_FALSE;
         if(request->profileUrisSize <= 0) {
         if(request->profileUrisSize <= 0) {
             relevant_endpoints[j] = UA_TRUE;
             relevant_endpoints[j] = UA_TRUE;
             relevant_count++;
             relevant_count++;
             continue;
             continue;
         }
         }
-        for(UA_Int32 i = 0; i < request->profileUrisSize; i++) {
+        for(size_t i = 0; i < request->profileUrisSize; i++) {
             if(UA_String_equal(&request->profileUris[i], &server->endpointDescriptions->transportProfileUri)) {
             if(UA_String_equal(&request->profileUris[i], &server->endpointDescriptions->transportProfileUri)) {
                 relevant_endpoints[j] = UA_TRUE;
                 relevant_endpoints[j] = UA_TRUE;
                 relevant_count++;
                 relevant_count++;
@@ -55,7 +55,7 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
 
 
     size_t k = 0;
     size_t k = 0;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    for(UA_Int32 j = 0; j < server->endpointDescriptionsSize && retval == UA_STATUSCODE_GOOD; j++) {
+    for(size_t j = 0; j < server->endpointDescriptionsSize && retval == UA_STATUSCODE_GOOD; j++) {
         if(relevant_endpoints[j] != UA_TRUE)
         if(relevant_endpoints[j] != UA_TRUE)
             continue;
             continue;
         retval = UA_EndpointDescription_copy(&server->endpointDescriptions[j], &response->endpoints[k]);
         retval = UA_EndpointDescription_copy(&server->endpointDescriptions[j], &response->endpoints[k]);
@@ -64,9 +64,8 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
 
 
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         response->responseHeader.serviceResult = retval;
         response->responseHeader.serviceResult = retval;
-        UA_Array_delete(response->endpoints, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], --k);
+        UA_Array_delete(response->endpoints, --k, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
         return;
         return;
     }
     }
     response->endpointsSize = relevant_count;
     response->endpointsSize = relevant_count;
 }
 }
-

+ 197 - 198
src/server/ua_services_nodemanagement.c

@@ -10,9 +10,10 @@
 /* Add Node */
 /* Add Node */
 /************/
 /************/
 
 
-void UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
-                               const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
-                               UA_AddNodesResult *result) {
+void
+UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *node,
+                          const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          UA_AddNodesResult *result) {
     if(node->nodeId.namespaceIndex >= server->namespacesSize) {
     if(node->nodeId.namespaceIndex >= server->namespacesSize) {
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         return;
         return;
@@ -28,59 +29,53 @@ void UA_Server_addExistingNode(UA_Server *server, UA_Session *session, UA_Node *
         (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
         (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
     if(!referenceType) {
     if(!referenceType) {
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-        goto ret;
+        return;
     }
     }
 
 
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-        goto ret2;
+        return;
     }
     }
 
 
     if(referenceType->isAbstract == UA_TRUE) {
     if(referenceType->isAbstract == UA_TRUE) {
         result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
         result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
-        goto ret2;
+        return;
     }
     }
 
 
     // todo: test if the referencetype is hierarchical
     // todo: test if the referencetype is hierarchical
     // todo: namespace index is assumed to be valid
     // todo: namespace index is assumed to be valid
-    const UA_Node *managed = NULL;
+    UA_MT_CONST UA_Node *managed = NULL;
     UA_NodeId tempNodeid = node->nodeId;
     UA_NodeId tempNodeid = node->nodeId;
     tempNodeid.namespaceIndex = 0;
     tempNodeid.namespaceIndex = 0;
     if(UA_NodeId_isNull(&tempNodeid)) {
     if(UA_NodeId_isNull(&tempNodeid)) {
         if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
         if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
             result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
             result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto ret2;
+            return;
         }
         }
         result->addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
         result->addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
     } else {
     } else {
         if(UA_NodeId_copy(&node->nodeId, &result->addedNodeId) != UA_STATUSCODE_GOOD) {
         if(UA_NodeId_copy(&node->nodeId, &result->addedNodeId) != UA_STATUSCODE_GOOD) {
             result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
             result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto ret2;
+            return;
         }
         }
 
 
         if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
         if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
             result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS;
             result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS;
             UA_NodeId_deleteMembers(&result->addedNodeId);
             UA_NodeId_deleteMembers(&result->addedNodeId);
-            goto ret2;
+            return;
         }
         }
     }
     }
+    /* Careful. The node is inserted. If the nodestore makes an expand, nodes change their address */
     
     
     // reference back to the parent
     // reference back to the parent
     UA_AddReferencesItem item;
     UA_AddReferencesItem item;
     UA_AddReferencesItem_init(&item);
     UA_AddReferencesItem_init(&item);
     item.sourceNodeId = managed->nodeId;
     item.sourceNodeId = managed->nodeId;
-    item.referenceTypeId = referenceType->nodeId;
+    item.referenceTypeId = *referenceTypeId;
     item.isForward = UA_FALSE;
     item.isForward = UA_FALSE;
-    item.targetNodeId.nodeId = parent->nodeId;
+    item.targetNodeId.nodeId = *parentNodeId;
     Service_AddReferences_single(server, session, &item);
     Service_AddReferences_single(server, session, &item);
-
     // todo: error handling. remove new node from nodestore
     // todo: error handling. remove new node from nodestore
-    UA_NodeStore_release(managed);
-    
- ret2:
-    UA_NodeStore_release((const UA_Node*)referenceType);
- ret:
-    UA_NodeStore_release(parent);
 }
 }
 
 
 static UA_StatusCode
 static UA_StatusCode
@@ -98,10 +93,8 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
     const UA_VariableNode *node = (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
-    if(node->nodeClass != UA_NODECLASS_VARIABLE) {
-        UA_NodeStore_release((const UA_Node*)node);
+    if(node->nodeClass != UA_NODECLASS_VARIABLE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    }
     
     
     // copy the variable attributes
     // copy the variable attributes
     UA_VariableAttributes attr;
     UA_VariableAttributes attr;
@@ -126,17 +119,20 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     UA_NodeId_copy(referenceType, &item.referenceTypeId);
     UA_NodeId_copy(referenceType, &item.referenceTypeId);
     UA_QualifiedName_copy(&node->browseName, &item.browseName);
     UA_QualifiedName_copy(&node->browseName, &item.browseName);
     item.nodeClass = UA_NODECLASS_VARIABLE;
     item.nodeClass = UA_NODECLASS_VARIABLE;
+    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
+    item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
+    item.nodeAttributes.content.decoded.data = &attr;
     // don't add a typedefinition here.
     // don't add a typedefinition here.
 
 
     // add the new variable
     // add the new variable
     UA_AddNodesResult res;
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, (UA_NodeAttributes*)&attr, &res);
+    Service_AddNodes_single(server, session, &item, &res);
     UA_VariableAttributes_deleteMembers(&attr);
     UA_VariableAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
     UA_AddNodesItem_deleteMembers(&item);
 
 
     // now instantiate the variable for all hastypedefinition references
     // now instantiate the variable for all hastypedefinition references
-    for(UA_Int32 i = 0; i < node->referencesSize; i++) {
+    for(size_t i = 0; i < node->referencesSize; i++) {
         UA_ReferenceNode *rn = &node->references[i];
         UA_ReferenceNode *rn = &node->references[i];
         if(rn->isInverse)
         if(rn->isInverse)
             continue;
             continue;
@@ -147,7 +143,6 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     }
     }
 
 
     UA_AddNodesResult_deleteMembers(&res);
     UA_AddNodesResult_deleteMembers(&res);
-    UA_NodeStore_release((const UA_Node*)node);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -159,10 +154,9 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
     const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);
     const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
-    if(node->nodeClass != UA_NODECLASS_OBJECT) {
-        UA_NodeStore_release((const UA_Node*)node);
+    if(node->nodeClass != UA_NODECLASS_OBJECT)
         return UA_STATUSCODE_BADNODECLASSINVALID;
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    }
+
     // copy the variable attributes
     // copy the variable attributes
     UA_ObjectAttributes attr;
     UA_ObjectAttributes attr;
     UA_ObjectAttributes_init(&attr);
     UA_ObjectAttributes_init(&attr);
@@ -178,17 +172,20 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
     UA_NodeId_copy(referenceType, &item.referenceTypeId);
     UA_NodeId_copy(referenceType, &item.referenceTypeId);
     UA_QualifiedName_copy(&node->browseName, &item.browseName);
     UA_QualifiedName_copy(&node->browseName, &item.browseName);
     item.nodeClass = UA_NODECLASS_OBJECT;
     item.nodeClass = UA_NODECLASS_OBJECT;
+    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
+    item.nodeAttributes.content.decoded.type = &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES];
+    item.nodeAttributes.content.decoded.data = &attr;
     // don't add a typedefinition here.
     // don't add a typedefinition here.
 
 
     // add the new object
     // add the new object
     UA_AddNodesResult res;
     UA_AddNodesResult res;
     UA_AddNodesResult_init(&res);
     UA_AddNodesResult_init(&res);
-    Service_AddNodes_single(server, session, &item, (UA_NodeAttributes*)&attr, &res);
+    Service_AddNodes_single(server, session, &item, &res);
     UA_ObjectAttributes_deleteMembers(&attr);
     UA_ObjectAttributes_deleteMembers(&attr);
     UA_AddNodesItem_deleteMembers(&item);
     UA_AddNodesItem_deleteMembers(&item);
 
 
     // now instantiate the object for all hastypedefinition references
     // now instantiate the object for all hastypedefinition references
-    for(UA_Int32 i = 0; i < node->referencesSize; i++) {
+    for(size_t i = 0; i < node->referencesSize; i++) {
         UA_ReferenceNode *rn = &node->references[i];
         UA_ReferenceNode *rn = &node->references[i];
         if(rn->isInverse)
         if(rn->isInverse)
             continue;
             continue;
@@ -199,7 +196,6 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
     }
     }
 
 
     UA_AddNodesResult_deleteMembers(&res);
     UA_AddNodesResult_deleteMembers(&res);
-    UA_NodeStore_release((const UA_Node*)node);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -217,10 +213,8 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
-    if(type->nodeClass != UA_NODECLASS_OBJECTTYPE) {
-        UA_NodeStore_release((const UA_Node*)type);
+    if(type->nodeClass != UA_NODECLASS_OBJECTTYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    }
 
 
     /* Add all the child nodes */
     /* Add all the child nodes */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription browseChildren;
@@ -237,7 +231,7 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
     // todo: continuation points if there are too many results
     // todo: continuation points if there are too many results
     Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult);
     Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult);
 
 
-    for(UA_Int32 i = 0; i < browseResult.referencesSize; i++) {
+    for(size_t i = 0; i < browseResult.referencesSize; i++) {
         UA_ReferenceDescription *rd = &browseResult.references[i];
         UA_ReferenceDescription *rd = &browseResult.references[i];
         if(rd->nodeClass == UA_NODECLASS_METHOD) {
         if(rd->nodeClass == UA_NODECLASS_METHOD) {
             /* add a reference to the method in the objecttype */
             /* add a reference to the method in the objecttype */
@@ -270,7 +264,6 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
     if(olm->constructor)
     if(olm->constructor)
         UA_Server_editNode(server, session, nodeId,
         UA_Server_editNode(server, session, nodeId,
                            (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId));
                            (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId));
-    UA_NodeStore_release((const UA_Node*)type);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -280,10 +273,8 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
-    if(type->nodeClass != UA_NODECLASS_VARIABLETYPE) {
-        UA_NodeStore_release((const UA_Node*)type);
+    if(type->nodeClass != UA_NODECLASS_VARIABLETYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    }
 
 
     /* get the references to child properties */
     /* get the references to child properties */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription browseChildren;
@@ -301,11 +292,10 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult);
     Service_Browse_single(server, session, NULL, &browseChildren, 100, &browseResult);
 
 
     /* add the child properties */
     /* add the child properties */
-    for(UA_Int32 i = 0; i < browseResult.referencesSize; i++) {
+    for(size_t i = 0; i < browseResult.referencesSize; i++) {
         UA_ReferenceDescription *rd = &browseResult.references[i];
         UA_ReferenceDescription *rd = &browseResult.references[i];
         copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
         copyExistingVariable(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
     }
     }
-    UA_NodeStore_release((const UA_Node*)type);
 
 
     /* add a hastypedefinition reference */
     /* add a hastypedefinition reference */
     UA_AddReferencesItem addref;
     UA_AddReferencesItem addref;
@@ -320,130 +310,188 @@ instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-static void moveStandardAttributes(UA_Node *node, UA_AddNodesItem *item, UA_NodeAttributes *attr) {
-    node->nodeId = item->requestedNewNodeId.nodeId;
-    UA_NodeId_init(&item->requestedNewNodeId.nodeId);
-    node->browseName = item->browseName;
-    UA_QualifiedName_init(&item->browseName);
-    node->displayName = attr->displayName;
-    UA_LocalizedText_init(&attr->displayName);
-    node->description = attr->description;
-    UA_LocalizedText_init(&attr->description);
+static UA_StatusCode
+copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item, const UA_NodeAttributes *attr) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    retval |= UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
+    retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
+    retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
+    retval |= UA_LocalizedText_copy(&attr->description, &node->description);
     node->writeMask = attr->writeMask;
     node->writeMask = attr->writeMask;
     node->userWriteMask = attr->userWriteMask;
     node->userWriteMask = attr->userWriteMask;
+    return retval;
 }
 }
 
 
 static UA_Node *
 static UA_Node *
-variableNodeFromAttributes(UA_AddNodesItem *item, UA_VariableAttributes *attr) {
+variableNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableAttributes *attr) {
     UA_VariableNode *vnode = UA_VariableNode_new();
     UA_VariableNode *vnode = UA_VariableNode_new();
     if(!vnode)
     if(!vnode)
         return NULL;
         return NULL;
-    moveStandardAttributes((UA_Node*)vnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     // todo: test if the type / valueRank / value attributes are consistent
     // todo: test if the type / valueRank / value attributes are consistent
     vnode->accessLevel = attr->accessLevel;
     vnode->accessLevel = attr->accessLevel;
     vnode->userAccessLevel = attr->userAccessLevel;
     vnode->userAccessLevel = attr->userAccessLevel;
     vnode->historizing = attr->historizing;
     vnode->historizing = attr->historizing;
     vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
     vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
     vnode->valueRank = attr->valueRank;
     vnode->valueRank = attr->valueRank;
-    vnode->value.variant.value = attr->value;
-    UA_Variant_init(&attr->value);
+    retval |= UA_Variant_copy(&attr->value, &vnode->value.variant.value);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        return NULL;
+    }
     return (UA_Node*)vnode;
     return (UA_Node*)vnode;
 }
 }
 
 
 static UA_Node *
 static UA_Node *
-objectNodeFromAttributes(UA_AddNodesItem *item, UA_ObjectAttributes *attr) {
+objectNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectAttributes *attr) {
     UA_ObjectNode *onode = UA_ObjectNode_new();
     UA_ObjectNode *onode = UA_ObjectNode_new();
     if(!onode)
     if(!onode)
         return NULL;
         return NULL;
-    moveStandardAttributes((UA_Node*)onode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)onode, item, (const UA_NodeAttributes*)attr);
     onode->eventNotifier = attr->eventNotifier;
     onode->eventNotifier = attr->eventNotifier;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)onode);
+        return NULL;
+    }
     return (UA_Node*)onode;
     return (UA_Node*)onode;
 }
 }
 
 
 static UA_Node *
 static UA_Node *
-referenceTypeNodeFromAttributes(UA_AddNodesItem *item, UA_ReferenceTypeAttributes *attr) {
+referenceTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ReferenceTypeAttributes *attr) {
     UA_ReferenceTypeNode *rtnode = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *rtnode = UA_ReferenceTypeNode_new();
     if(!rtnode)
     if(!rtnode)
         return NULL;
         return NULL;
-    moveStandardAttributes((UA_Node*)rtnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)rtnode, item, (const UA_NodeAttributes*)attr);
     rtnode->isAbstract = attr->isAbstract;
     rtnode->isAbstract = attr->isAbstract;
     rtnode->symmetric = attr->symmetric;
     rtnode->symmetric = attr->symmetric;
-    rtnode->inverseName = attr->inverseName;
-    UA_LocalizedText_init(&attr->inverseName);
+    retval |= UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)rtnode);
+        return NULL;
+    }
     return (UA_Node*)rtnode;
     return (UA_Node*)rtnode;
 }
 }
 
 
 static UA_Node *
 static UA_Node *
-objectTypeNodeFromAttributes(UA_AddNodesItem *item, UA_ObjectTypeAttributes *attr) {
+objectTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_ObjectTypeAttributes *attr) {
     UA_ObjectTypeNode *otnode = UA_ObjectTypeNode_new();
     UA_ObjectTypeNode *otnode = UA_ObjectTypeNode_new();
     if(!otnode)
     if(!otnode)
         return NULL;
         return NULL;
-    moveStandardAttributes((UA_Node*)otnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)otnode, item, (const UA_NodeAttributes*)attr);
     otnode->isAbstract = attr->isAbstract;
     otnode->isAbstract = attr->isAbstract;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)otnode);
+        return NULL;
+    }
     return (UA_Node*)otnode;
     return (UA_Node*)otnode;
 }
 }
 
 
 static UA_Node *
 static UA_Node *
-variableTypeNodeFromAttributes(UA_AddNodesItem *item, UA_VariableTypeAttributes *attr) {
+variableTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_VariableTypeAttributes *attr) {
     UA_VariableTypeNode *vtnode = UA_VariableTypeNode_new();
     UA_VariableTypeNode *vtnode = UA_VariableTypeNode_new();
     if(!vtnode)
     if(!vtnode)
         return NULL;
         return NULL;
-    moveStandardAttributes((UA_Node*)vtnode, item, (UA_NodeAttributes*)attr);
-    vtnode->value.variant.value = attr->value;
-    UA_Variant_init(&attr->value);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)vtnode, item, (const UA_NodeAttributes*)attr);
+    UA_Variant_copy(&attr->value, &vtnode->value.variant.value);
     // datatype is taken from the value
     // datatype is taken from the value
     vtnode->valueRank = attr->valueRank;
     vtnode->valueRank = attr->valueRank;
     // array dimensions are taken from the value
     // array dimensions are taken from the value
     vtnode->isAbstract = attr->isAbstract;
     vtnode->isAbstract = attr->isAbstract;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)vtnode);
+        return NULL;
+    }
     return (UA_Node*)vtnode;
     return (UA_Node*)vtnode;
 }
 }
 
 
 static UA_Node *
 static UA_Node *
-viewNodeFromAttributes(UA_AddNodesItem *item, UA_ViewAttributes *attr) {
+viewNodeFromAttributes(const UA_AddNodesItem *item, const UA_ViewAttributes *attr) {
     UA_ViewNode *vnode = UA_ViewNode_new();
     UA_ViewNode *vnode = UA_ViewNode_new();
     if(!vnode)
     if(!vnode)
         return NULL;
         return NULL;
-    moveStandardAttributes((UA_Node*)vnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)vnode, item, (const UA_NodeAttributes*)attr);
     vnode->containsNoLoops = attr->containsNoLoops;
     vnode->containsNoLoops = attr->containsNoLoops;
     vnode->eventNotifier = attr->eventNotifier;
     vnode->eventNotifier = attr->eventNotifier;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)vnode);
+        return NULL;
+    }
     return (UA_Node*)vnode;
     return (UA_Node*)vnode;
 }
 }
 
 
 static UA_Node *
 static UA_Node *
-dataTypeNodeFromAttributes(UA_AddNodesItem *item, UA_DataTypeAttributes *attr) {
+dataTypeNodeFromAttributes(const UA_AddNodesItem *item, const UA_DataTypeAttributes *attr) {
     UA_DataTypeNode *dtnode = UA_DataTypeNode_new();
     UA_DataTypeNode *dtnode = UA_DataTypeNode_new();
     if(!dtnode)
     if(!dtnode)
         return NULL;
         return NULL;
-    moveStandardAttributes((UA_Node*)dtnode, item, (UA_NodeAttributes*)attr);
+    UA_StatusCode retval = copyStandardAttributes((UA_Node*)dtnode, item, (const UA_NodeAttributes*)attr);
     dtnode->isAbstract = attr->isAbstract;
     dtnode->isAbstract = attr->isAbstract;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Node_deleteAnyNodeClass((UA_Node*)dtnode);
+        return NULL;
+    }
     return (UA_Node*)dtnode;
     return (UA_Node*)dtnode;
 }
 }
 
 
-void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
-                             UA_NodeAttributes *attr, UA_AddNodesResult *result) {
+void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
+                             UA_AddNodesResult *result) {
+    if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
+       !item->nodeAttributes.content.decoded.type) {
+        result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+        return;
+    }
+    
     /* create the node */
     /* create the node */
     UA_Node *node;
     UA_Node *node;
     switch(item->nodeClass) {
     switch(item->nodeClass) {
     case UA_NODECLASS_OBJECT:
     case UA_NODECLASS_OBJECT:
-        node = objectNodeFromAttributes(item, (UA_ObjectAttributes*)attr);
+        if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES]) {
+            result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+            return;
+        }
+        node = objectNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
         break;
         break;
     case UA_NODECLASS_VARIABLE:
     case UA_NODECLASS_VARIABLE:
-        node = variableNodeFromAttributes(item, (UA_VariableAttributes*)attr);
+        if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]) {
+            result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+            return;
+        }
+        node = variableNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
         break;
         break;
     case UA_NODECLASS_OBJECTTYPE:
     case UA_NODECLASS_OBJECTTYPE:
-        node = objectTypeNodeFromAttributes(item, (UA_ObjectTypeAttributes*)attr);
+        if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]) {
+            result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+            return;
+        }
+        node = objectTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
         break;
         break;
     case UA_NODECLASS_VARIABLETYPE:
     case UA_NODECLASS_VARIABLETYPE:
-        node = variableTypeNodeFromAttributes(item, (UA_VariableTypeAttributes*)attr);
+        if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]) {
+            result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+            return;
+        }
+        node = variableTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
         break;
         break;
     case UA_NODECLASS_REFERENCETYPE:
     case UA_NODECLASS_REFERENCETYPE:
-        node = referenceTypeNodeFromAttributes(item, (UA_ReferenceTypeAttributes*)attr);
+        if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]) {
+            result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+            return;
+        }
+        node = referenceTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
         break;
         break;
     case UA_NODECLASS_DATATYPE:
     case UA_NODECLASS_DATATYPE:
-        node = dataTypeNodeFromAttributes(item, (UA_DataTypeAttributes*)attr);
+        if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]) {
+            result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+            return;
+        }
+        node = dataTypeNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
         break;
         break;
     case UA_NODECLASS_VIEW:
     case UA_NODECLASS_VIEW:
-        node = viewNodeFromAttributes(item, (UA_ViewAttributes*)attr);
+        if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_VIEWATTRIBUTES]) {
+            result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+            return;
+        }
+        node = viewNodeFromAttributes(item, item->nodeAttributes.content.decoded.data);
         break;
         break;
     case UA_NODECLASS_METHOD:
     case UA_NODECLASS_METHOD:
     case UA_NODECLASS_UNSPECIFIED:
     case UA_NODECLASS_UNSPECIFIED:
@@ -480,55 +528,6 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodes
         Service_DeleteNodes_single(server, session, &result->addedNodeId, UA_TRUE);
         Service_DeleteNodes_single(server, session, &result->addedNodeId, UA_TRUE);
 }
 }
 
 
-static void Service_AddNodes_single_unparsed(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
-                                             UA_AddNodesResult *result) {
-    /* adding nodes to ns0 is not allowed over the wire */
-    if(item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
-        result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
-        return;
-    }
-
-    const UA_DataType *attributeType;
-    switch (item->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        attributeType = &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES];
-        break;
-    case UA_NODECLASS_OBJECTTYPE:
-        attributeType = &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES];
-        break;
-    case UA_NODECLASS_REFERENCETYPE:
-        attributeType = &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES];
-        break;
-    case UA_NODECLASS_VARIABLE:
-        attributeType = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
-        break;
-    case UA_NODECLASS_VIEW:
-        attributeType = &UA_TYPES[UA_TYPES_VIEWATTRIBUTES];
-        break;
-    case UA_NODECLASS_DATATYPE:
-        attributeType = &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES];
-        break;
-    default:
-        result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
-        return;
-    }
-
-    if(!UA_NodeId_equal(&item->nodeAttributes.typeId, &attributeType->typeId)) {
-        result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
-        return;
-    }
-
-    UA_NodeAttributes *attr = UA_alloca(attributeType->memSize);
-    UA_init(attr, attributeType);
-    size_t pos = 0;
-    result->statusCode = UA_decodeBinary(&item->nodeAttributes.body, &pos, attr, attributeType);
-    if(result->statusCode != UA_STATUSCODE_GOOD)
-        return;
-
-    Service_AddNodes_single(server, session, item, attr, result);
-    UA_deleteMembers(attr, attributeType);
-}
-
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response) {
                       UA_AddNodesResponse *response) {
     if(request->nodesToAddSize <= 0) {
     if(request->nodesToAddSize <= 0) {
@@ -537,7 +536,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
     }
     }
     size_t size = request->nodesToAddSize;
     size_t size = request->nodesToAddSize;
 
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_ADDNODESRESULT], size);
+    response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
@@ -571,11 +570,11 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
 #endif
 #endif
     
     
     response->resultsSize = size;
     response->resultsSize = size;
-    for(size_t i = 0;i < size;i++) {
+    for(size_t i = 0; i < size; i++) {
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
         if(!isExternal[i])
 #endif
 #endif
-            Service_AddNodes_single_unparsed(server, session, &request->nodesToAdd[i], &response->results[i]);
+            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i]);
     }
     }
 }
 }
 
 
@@ -587,7 +586,8 @@ UA_StatusCode UA_EXPORT
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                     const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
                                     const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                                    const UA_VariableAttributes attr, const UA_DataSource dataSource, UA_NodeId *outNewNodeId) {
+                                    const UA_VariableAttributes attr, const UA_DataSource dataSource,
+                                    UA_NodeId *outNewNodeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
     UA_AddNodesResult_init(&result);
 
 
@@ -615,7 +615,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
     }
 
 
-    moveStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
+    copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
     node->valueSource = UA_VALUESOURCE_DATASOURCE;
     node->valueSource = UA_VALUESOURCE_DATASOURCE;
     node->value.dataSource = dataSource;
     node->value.dataSource = dataSource;
     node->accessLevel = attr.accessLevel;
     node->accessLevel = attr.accessLevel;
@@ -675,7 +675,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
         return result.statusCode;
         return result.statusCode;
     }
     }
     
     
-    moveStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
+    copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
     node->executable = attrCopy.executable;
     node->executable = attrCopy.executable;
     node->userExecutable = attrCopy.executable;
     node->userExecutable = attrCopy.executable;
     node->attachedMethod = method;
     node->attachedMethod = method;
@@ -685,47 +685,47 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 
 
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
     UA_Server_addExistingNode(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
                               &item.referenceTypeId, &result);
                               &item.referenceTypeId, &result);
-    if(result.statusCode != UA_STATUSCODE_GOOD)
+    if(result.statusCode != UA_STATUSCODE_GOOD) {
         UA_MethodNode_delete(node);
         UA_MethodNode_delete(node);
+        return result.statusCode;
+    }
     
     
-    if(result.statusCode == UA_STATUSCODE_GOOD && method != NULL) {
-        UA_ExpandedNodeId parent;
-        UA_ExpandedNodeId_init(&parent);
-        parent.nodeId = result.addedNodeId;
+    UA_ExpandedNodeId parent;
+    UA_ExpandedNodeId_init(&parent);
+    parent.nodeId = result.addedNodeId;
     
     
-        /* create InputArguments */
-        UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
-        inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-        inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
-        inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-        inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
-        inputArgumentsVariableNode->valueRank = 1;
-        UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
-                                inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-        UA_AddNodesResult inputAddRes;
-        const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-        UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
-                                  &parent.nodeId, &hasproperty, &inputAddRes);
-        // todo: check if adding succeeded
-        UA_AddNodesResult_deleteMembers(&inputAddRes);
-
-        /* create OutputArguments */
-        UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
-        outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
-        outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
-        outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-        outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
-        outputArgumentsVariableNode->valueRank = 1;
-        UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
-                                outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
-        UA_AddNodesResult outputAddRes;
-        UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
-                                  &parent.nodeId, &hasproperty, &outputAddRes);
-        // todo: check if adding succeeded
-        UA_AddNodesResult_deleteMembers(&outputAddRes);
-    }
-
-    if(outNewNodeId && result.statusCode == UA_STATUSCODE_GOOD)
+    /* create InputArguments */
+    UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
+    inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
+    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
+                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult inputAddRes;
+    const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
+    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
+                              &parent.nodeId, &hasproperty, &inputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&inputAddRes);
+
+    /* create OutputArguments */
+    UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
+    outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
+    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
+                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult outputAddRes;
+    UA_Server_addExistingNode(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
+                              &parent.nodeId, &hasproperty, &outputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&outputAddRes);
+
+    if(outNewNodeId)
         *outNewNodeId = result.addedNodeId;
         *outNewNodeId = result.addedNodeId;
     else
     else
         UA_AddNodesResult_deleteMembers(&result);
         UA_AddNodesResult_deleteMembers(&result);
@@ -741,8 +741,6 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 static UA_StatusCode
 static UA_StatusCode
 addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, const UA_AddReferencesItem *item) {
 addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, const UA_AddReferencesItem *item) {
 	size_t i = node->referencesSize;
 	size_t i = node->referencesSize;
-	if(node->referencesSize < 0)
-		i = 0;
     size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
     size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
 	UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
 	UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
 	if(!new_refs)
 	if(!new_refs)
@@ -759,8 +757,8 @@ addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node, const
 	return retval;
 	return retval;
 }
 }
 
 
-UA_StatusCode Service_AddReferences_single(UA_Server *server, UA_Session *session,
-                                           const UA_AddReferencesItem *item) {
+UA_StatusCode
+Service_AddReferences_single(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
     if(item->targetServerUri.length > 0)
     if(item->targetServerUri.length > 0)
         return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
         return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
 
 
@@ -825,7 +823,7 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 #endif
 #endif
 
 
 	response->resultsSize = size;
 	response->resultsSize = size;
-	for(UA_Int32 i = 0; i < response->resultsSize; i++) {
+	for(size_t i = 0; i < response->resultsSize; i++) {
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
 		if(!isExternal[i])
 		if(!isExternal[i])
 #endif
 #endif
@@ -839,9 +837,10 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 
 
 // TODO: Check consistency constraints, remove the references.
 // TODO: Check consistency constraints, remove the references.
 
 
-UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                                         UA_Boolean deleteReferences) {
-    const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
+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);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(deleteReferences == UA_TRUE) {
     if(deleteReferences == UA_TRUE) {
@@ -849,7 +848,7 @@ UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session,
         UA_DeleteReferencesItem_init(&delItem);
         UA_DeleteReferencesItem_init(&delItem);
         delItem.deleteBidirectional = UA_FALSE;
         delItem.deleteBidirectional = UA_FALSE;
         delItem.targetNodeId.nodeId = *nodeId;
         delItem.targetNodeId.nodeId = *nodeId;
-        for(int i = 0; i < node->referencesSize; i++) {
+        for(size_t i = 0; i < node->referencesSize; i++) {
             delItem.sourceNodeId = node->references[i].targetId.nodeId;
             delItem.sourceNodeId = node->references[i].targetId.nodeId;
             delItem.isForward = node->references[i].isInverse;
             delItem.isForward = node->references[i].isInverse;
             Service_DeleteReferences_single(server, session, &delItem);
             Service_DeleteReferences_single(server, session, &delItem);
@@ -871,24 +870,22 @@ UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session,
         UA_BrowseResult result;
         UA_BrowseResult result;
         UA_BrowseResult_init(&result);
         UA_BrowseResult_init(&result);
         Service_Browse_single(server, &adminSession, NULL, &bd, UA_UINT32_MAX, &result);
         Service_Browse_single(server, &adminSession, NULL, &bd, UA_UINT32_MAX, &result);
-        for(int i = 0; i < result.referencesSize; i++) {
+        for(size_t i = 0; i < result.referencesSize; i++) {
             /* call the destructor */
             /* call the destructor */
             UA_ReferenceDescription *rd = &result.references[i];
             UA_ReferenceDescription *rd = &result.references[i];
-            const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId);
+            const UA_ObjectTypeNode *type =
+                (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId);
             if(!type)
             if(!type)
                 continue;
                 continue;
-            if(type->nodeClass != UA_NODECLASS_OBJECTTYPE || !type->lifecycleManagement.destructor) {
-                UA_NodeStore_release((const UA_Node*)type);
+            if(type->nodeClass != UA_NODECLASS_OBJECTTYPE || !type->lifecycleManagement.destructor)
                 continue;
                 continue;
-            }
+
             /* if there are several types with lifecycle management, call all the destructors */
             /* if there are several types with lifecycle management, call all the destructors */
             type->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle);
             type->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle);
-            UA_NodeStore_release((const UA_Node*)type);
         }
         }
         UA_BrowseResult_deleteMembers(&result);
         UA_BrowseResult_deleteMembers(&result);
     }
     }
     
     
-    UA_NodeStore_release(node);
     return UA_NodeStore_remove(server->nodestore, nodeId);
     return UA_NodeStore_remove(server->nodestore, nodeId);
 }
 }
 
 
@@ -904,7 +901,7 @@ void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_Delete
         return;
         return;
     }
     }
     response->resultsSize = request->nodesToDeleteSize;
     response->resultsSize = request->nodesToDeleteSize;
-    for(int i=0; i<request->nodesToDeleteSize; i++) {
+    for(size_t i=0; i<request->nodesToDeleteSize; i++) {
         UA_DeleteNodesItem *item = &request->nodesToDelete[i];
         UA_DeleteNodesItem *item = &request->nodesToDelete[i];
         response->results[i] = Service_DeleteNodes_single(server, session, &item->nodeId,
         response->results[i] = Service_DeleteNodes_single(server, session, &item->nodeId,
                                                           item->deleteTargetReferences);
                                                           item->deleteTargetReferences);
@@ -931,19 +928,21 @@ deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
         node->references[i] = node->references[node->referencesSize-1];
         node->references[i] = node->references[node->referencesSize-1];
         node->referencesSize--;
         node->referencesSize--;
         edited = UA_TRUE;
         edited = UA_TRUE;
+        break;
     }
     }
     if(!edited)
     if(!edited)
         return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
         return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
     /* we removed the last reference */
     /* we removed the last reference */
-    if(node->referencesSize <= 0 && node->references)
+    if(node->referencesSize == 0 && node->references)
         UA_free(node->references);
         UA_free(node->references);
     return UA_STATUSCODE_GOOD;;
     return UA_STATUSCODE_GOOD;;
 }
 }
 
 
 UA_StatusCode
 UA_StatusCode
-Service_DeleteReferences_single(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item) {
+Service_DeleteReferences_single(UA_Server *server, UA_Session *session,
+                                const UA_DeleteReferencesItem *item) {
     UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
     UA_StatusCode retval = UA_Server_editNode(server, session, &item->sourceNodeId,
-                                       (UA_EditNodeCallback)deleteOneWayReference, item);
+                                              (UA_EditNodeCallback)deleteOneWayReference, item);
     if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
     if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
         return retval;
         return retval;
     UA_DeleteReferencesItem secondItem;
     UA_DeleteReferencesItem secondItem;
@@ -955,9 +954,9 @@ Service_DeleteReferences_single(UA_Server *server, UA_Session *session, const UA
                               (UA_EditNodeCallback)deleteOneWayReference, &secondItem);
                               (UA_EditNodeCallback)deleteOneWayReference, &secondItem);
 }
 }
 
 
-void Service_DeleteReferences(UA_Server *server, UA_Session *session,
-                              const UA_DeleteReferencesRequest *request,
-                              UA_DeleteReferencesResponse *response) {
+void
+Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
+                         UA_DeleteReferencesResponse *response) {
     if(request->referencesToDeleteSize <= 0) {
     if(request->referencesToDeleteSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
         return;
@@ -968,7 +967,7 @@ void Service_DeleteReferences(UA_Server *server, UA_Session *session,
         return;
         return;
     }
     }
     response->resultsSize = request->referencesToDeleteSize;
     response->resultsSize = request->referencesToDeleteSize;
-    for(int i=0; i<request->referencesToDeleteSize; i++)
-        response->results[i] = Service_DeleteReferences_single(server, session,
-                                                               &request->referencesToDelete[i]);
+    for(size_t i = 0; i < request->referencesToDeleteSize; i++)
+        response->results[i] =
+            Service_DeleteReferences_single(server, session, &request->referencesToDelete[i]);
 }
 }

+ 77 - 62
src/server/ua_services_session.c

@@ -3,17 +3,17 @@
 #include "ua_session_manager.h"
 #include "ua_session_manager.h"
 #include "ua_types_generated_encoding_binary.h"
 #include "ua_types_generated_encoding_binary.h"
 
 
-void
-Service_CreateSession(UA_Server *server, UA_Session *session, const UA_CreateSessionRequest *request,
-                      UA_CreateSessionResponse *response) {
+void Service_CreateSession(UA_Server *server, UA_Session *session,
+                           const UA_CreateSessionRequest *request,
+                           UA_CreateSessionResponse *response) {
     UA_SecureChannel *channel = session->channel;
     UA_SecureChannel *channel = session->channel;
     if(channel->securityToken.channelId == 0) {
     if(channel->securityToken.channelId == 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
         return;
         return;
     }
     }
     response->responseHeader.serviceResult =
     response->responseHeader.serviceResult =
-        UA_Array_copy(server->endpointDescriptions, (void**)&response->serverEndpoints,
-                      &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], server->endpointDescriptionsSize);
+        UA_Array_copy(server->endpointDescriptions, server->endpointDescriptionsSize,
+                      (void**)&response->serverEndpoints, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
     if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
         return;
         return;
     response->serverEndpointsSize = server->endpointDescriptionsSize;
     response->serverEndpointsSize = server->endpointDescriptionsSize;
@@ -22,9 +22,9 @@ Service_CreateSession(UA_Server *server, UA_Session *session, const UA_CreateSes
     response->responseHeader.serviceResult =
     response->responseHeader.serviceResult =
         UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession);
         UA_SessionManager_createSession(&server->sessionManager, channel, request, &newSession);
 	if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
 	if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
-                 "Processing CreateSessionRequest on SecureChannel %i failed",
-                 channel->securityToken.channelId);
+        UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+                     "Processing CreateSessionRequest on SecureChannel %i failed",
+                     channel->securityToken.channelId);
 		return;
 		return;
     }
     }
 
 
@@ -48,98 +48,113 @@ Service_CreateSession(UA_Server *server, UA_Session *session, const UA_CreateSes
 }
 }
 
 
 void
 void
-Service_ActivateSession(UA_Server *server, UA_Session *session, const UA_ActivateSessionRequest *request,
+Service_ActivateSession(UA_Server *server, UA_Session *session,
+                        const UA_ActivateSessionRequest *request,
                         UA_ActivateSessionResponse *response) {
                         UA_ActivateSessionResponse *response) {
     UA_SecureChannel *channel = session->channel;
     UA_SecureChannel *channel = session->channel;
     // make the channel know about the session
     // make the channel know about the session
 	UA_Session *foundSession =
 	UA_Session *foundSession =
-        UA_SessionManager_getSession(&server->sessionManager,
-                                     (const UA_NodeId*)&request->requestHeader.authenticationToken);
+        UA_SessionManager_getSession(&server->sessionManager, &request->requestHeader.authenticationToken);
 
 
-	if(foundSession == NULL) {
+	if(!foundSession) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
         UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
                      "Processing ActivateSessionRequest on SecureChannel %i, but no session found for the authentication token",
                      "Processing ActivateSessionRequest on SecureChannel %i, but no session found for the authentication token",
                      channel->securityToken.channelId);
                      channel->securityToken.channelId);
         return;
         return;
-	} else if(foundSession->validTill < UA_DateTime_now()) {
+	}
+
+    if(foundSession->validTill < UA_DateTime_now()) {
         UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
         UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
                      "Processing ActivateSessionRequest on SecureChannel %i, but the session has timed out",
                      "Processing ActivateSessionRequest on SecureChannel %i, but the session has timed out",
                      channel->securityToken.channelId);
                      channel->securityToken.channelId);
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         return;
         return;
 	}
 	}
+
+    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,
+                     "Invalided UserIdentityToken on SecureChannel %i for Session (ns=%i,i=%i)",
+                     channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
+                     foundSession->sessionId.identifier.numeric);
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
+        return;
+    }
+
     UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
     UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
                  "Processing ActivateSessionRequest on SecureChannel %i for Session (ns=%i,i=%i)",
                  "Processing ActivateSessionRequest on SecureChannel %i for Session (ns=%i,i=%i)",
                  channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                  channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
                  foundSession->sessionId.identifier.numeric);
                  foundSession->sessionId.identifier.numeric);
 
 
-    UA_UserIdentityToken token;
-    UA_UserIdentityToken_init(&token);
-    size_t offset = 0;
-    UA_UserIdentityToken_decodeBinary(&request->userIdentityToken.body, &offset, &token);
-
-    UA_UserNameIdentityToken username_token;
-    UA_UserNameIdentityToken_init(&username_token);
-
     UA_String ap = UA_STRING(ANONYMOUS_POLICY);
     UA_String ap = UA_STRING(ANONYMOUS_POLICY);
     UA_String up = UA_STRING(USERNAME_POLICY);
     UA_String up = UA_STRING(USERNAME_POLICY);
-    //(Compatibility notice)
-    //Siemens OPC Scout v10 provides an empty policyId, this is not okay
-    //For compatibility we will assume that empty policyId == ANONYMOUS_POLICY
-    //if(token.policyId.data == NULL) {
-    //    /* 1) no policy defined */
-    //    response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-    //} else
-    //(End Compatibility notice)
-    if(server->config.Login_enableAnonymous && (token.policyId.data == NULL || UA_String_equal(&token.policyId, &ap))) {
-        /* 2) anonymous logins */
+
+    /* Compatibility notice: Siemens OPC Scout v10 provides an empty policyId,
+       this is not okay For compatibility we will assume that empty policyId ==
+       ANONYMOUS_POLICY
+       if(token.policyId->data == NULL)
+           response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+    */
+
+    /* anonymous login */
+    if(server->config.Login_enableAnonymous &&
+       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)) {
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+            return;
+        }
         if(foundSession->channel && foundSession->channel != channel)
         if(foundSession->channel && foundSession->channel != channel)
             UA_SecureChannel_detachSession(foundSession->channel, foundSession);
             UA_SecureChannel_detachSession(foundSession->channel, foundSession);
         UA_SecureChannel_attachSession(channel, foundSession);
         UA_SecureChannel_attachSession(channel, foundSession);
         foundSession->activated = UA_TRUE;
         foundSession->activated = UA_TRUE;
         UA_Session_updateLifetime(foundSession);
         UA_Session_updateLifetime(foundSession);
-    } else if(server->config.Login_enableUsernamePassword && UA_String_equal(&token.policyId, &up)) {
-        /* 3) username logins */
-        offset = 0;
-        UA_UserNameIdentityToken_decodeBinary(&request->userIdentityToken.body, &offset, &username_token);
-        if(username_token.encryptionAlgorithm.data != NULL) {
-            /* 3.1) we only support encryption */
+        return;
+    }
+
+    /* username login */
+    if(server->config.Login_enableUsernamePassword &&
+       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)) {
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+            return;
+        }
+        if(token->encryptionAlgorithm.data) {
+            /* we don't support encryption */
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-        } else  if(username_token.userName.length == -1 && username_token.password.length == -1){
-            /* 3.2) empty username and password */
+        } else  if(!token->userName.data && !token->password.data) {
+            /* empty username and password */
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
         } else {
         } else {
-            /* 3.3) ok, trying to match the username */
-            UA_UInt32 i = 0;
-            for(; i < server->config.Login_loginsCount; ++i) {
+            /* 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 user = UA_STRING(server->config.Login_usernames[i]);
                 UA_String pw = UA_STRING(server->config.Login_passwords[i]);
                 UA_String pw = UA_STRING(server->config.Login_passwords[i]);
-                if(UA_String_equal(&username_token.userName, &user) &&
-                   UA_String_equal(&username_token.password, &pw)) {
-                    /* success - activate */
-                    if(foundSession->channel && foundSession->channel != channel)
-                        UA_SecureChannel_detachSession(foundSession->channel, foundSession);
-                    UA_SecureChannel_attachSession(channel, foundSession);
-                    foundSession->activated = UA_TRUE;
-                    UA_Session_updateLifetime(foundSession);
-                    break;
-                }
+                if(!UA_String_equal(&token->userName, &user) || !UA_String_equal(&token->password, &pw))
+                    continue;
+                /* success - activate */
+                if(foundSession->channel && foundSession->channel != channel)
+                    UA_SecureChannel_detachSession(foundSession->channel, foundSession);
+                UA_SecureChannel_attachSession(channel, foundSession);
+                foundSession->activated = UA_TRUE;
+                UA_Session_updateLifetime(foundSession);
+                return;
             }
             }
-            /* no username/pass matched */
-            if(i >= server->config.Login_loginsCount)
-                response->responseHeader.serviceResult = UA_STATUSCODE_BADUSERACCESSDENIED;
+            /* no match */
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADUSERACCESSDENIED;
         }
         }
-    } else {
-        response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+        return;
     }
     }
-    UA_UserIdentityToken_deleteMembers(&token);
-    UA_UserNameIdentityToken_deleteMembers(&username_token);
-    return;
+    response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
 }
 }
 
 
-void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_CloseSessionRequest *request,
-                          UA_CloseSessionResponse *response) {
+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->logger, UA_LOGCATEGORY_SESSION,
                  "Processing CloseSessionRequest for Session (ns=%i,i=%i)",
                  "Processing CloseSessionRequest for Session (ns=%i,i=%i)",
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);
                  session->sessionId.namespaceIndex, session->sessionId.identifier.numeric);

+ 33 - 31
src/server/ua_services_subscription.c

@@ -17,6 +17,10 @@ void Service_CreateSubscription(UA_Server *server, UA_Session *session,
                                 UA_CreateSubscriptionResponse *response) {
                                 UA_CreateSubscriptionResponse *response) {
     response->subscriptionId = SubscriptionManager_getUniqueUIntID(&session->subscriptionManager);
     response->subscriptionId = SubscriptionManager_getUniqueUIntID(&session->subscriptionManager);
     UA_Subscription *newSubscription = UA_Subscription_new(response->subscriptionId);
     UA_Subscription *newSubscription = UA_Subscription_new(response->subscriptionId);
+    if(!newSubscription) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
+    }
     
     
     /* set the publishing interval */
     /* set the publishing interval */
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
     UA_BOUNDEDVALUE_SETWBOUNDS(session->subscriptionManager.globalPublishingInterval,
@@ -63,7 +67,6 @@ static void createMonitoredItems(UA_Server *server, UA_Session *session, UA_Subs
     UA_MonitoredItem *newMon = UA_MonitoredItem_new();
     UA_MonitoredItem *newMon = UA_MonitoredItem_new();
     if(!newMon) {
     if(!newMon) {
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-        UA_NodeStore_release(target);
         return;
         return;
     }
     }
 
 
@@ -71,7 +74,6 @@ static void createMonitoredItems(UA_Server *server, UA_Session *session, UA_Subs
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         MonitoredItem_delete(newMon);
         MonitoredItem_delete(newMon);
-        UA_NodeStore_release(target);
         return;
         return;
     }
     }
 
 
@@ -100,8 +102,6 @@ static void createMonitoredItems(UA_Server *server, UA_Session *session, UA_Subs
 
 
     // todo: add a job that samples the value (for fixed intervals)
     // todo: add a job that samples the value (for fixed intervals)
     // todo: add a pointer to the monitoreditem to the variable, so that events get propagated
     // todo: add a pointer to the monitoreditem to the variable, so that events get propagated
-    
-    UA_NodeStore_release(target);
 }
 }
 
 
 void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
 void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
@@ -119,14 +119,14 @@ void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
         return;
         return;
     }
     }
 
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], request->itemsToCreateSize);
+    response->results = UA_Array_new(request->itemsToCreateSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
     }
     }
     response->resultsSize = request->itemsToCreateSize;
     response->resultsSize = request->itemsToCreateSize;
 
 
-    for(UA_Int32 i = 0; i<request->itemsToCreateSize; i++)
+    for(size_t i = 0; i < request->itemsToCreateSize; i++)
         createMonitoredItems(server, session, sub, &request->itemsToCreate[i], &response->results[i]);
         createMonitoredItems(server, session, sub, &request->itemsToCreate[i], &response->results[i]);
 }
 }
 
 
@@ -139,7 +139,7 @@ void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishReq
     // Delete Acknowledged Subscription Messages
     // Delete Acknowledged Subscription Messages
     response->resultsSize = request->subscriptionAcknowledgementsSize;
     response->resultsSize = request->subscriptionAcknowledgementsSize;
     response->results     = UA_malloc(sizeof(UA_StatusCode)*(response->resultsSize));
     response->results     = UA_malloc(sizeof(UA_StatusCode)*(response->resultsSize));
-    for(UA_Int32 i = 0; i < request->subscriptionAcknowledgementsSize; i++) {
+    for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; i++) {
         response->results[i] = UA_STATUSCODE_GOOD;
         response->results[i] = UA_STATUSCODE_GOOD;
         UA_Subscription *sub =
         UA_Subscription *sub =
             SubscriptionManager_getSubscriptionByID(&session->subscriptionManager,
             SubscriptionManager_getSubscriptionByID(&session->subscriptionManager,
@@ -167,31 +167,31 @@ void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishReq
             Subscription_updateNotifications(sub);
             Subscription_updateNotifications(sub);
         }
         }
         
         
-        if(Subscription_queuedNotifications(sub) <= 0)
+        if(sub->unpublishedNotificationsSize == 0)
             continue;
             continue;
         
         
-	// This subscription has notifications in its queue (top NotificationMessage exists in the queue). 
-	// Due to republish, we need to check if there are any unplublished notifications first ()
-	UA_unpublishedNotification *notification = NULL;
-	LIST_FOREACH(notification, &sub->unpublishedNotifications, listEntry) {
-	  if (notification->publishedOnce == UA_FALSE)
-	    break;
-	}
-	if (notification == NULL)
-	  continue;
-	
-	// We found an unpublished notification message in this subscription, which we will now publish.
+        // This subscription has notifications in its queue (top NotificationMessage exists in the queue). 
+        // Due to republish, we need to check if there are any unplublished notifications first ()
+        UA_unpublishedNotification *notification = NULL;
+        LIST_FOREACH(notification, &sub->unpublishedNotifications, listEntry) {
+            if (notification->publishedOnce == UA_FALSE)
+                break;
+        }
+        if (notification == NULL)
+            continue;
+    
+        // We found an unpublished notification message in this subscription, which we will now publish.
         response->subscriptionId = sub->subscriptionID;
         response->subscriptionId = sub->subscriptionID;
         Subscription_copyNotificationMessage(&response->notificationMessage, notification);
         Subscription_copyNotificationMessage(&response->notificationMessage, notification);
-	// Mark this notification as published
-	notification->publishedOnce = UA_TRUE;
-        if(notification->notification->sequenceNumber > sub->sequenceNumber) {
+        // Mark this notification as published
+        notification->publishedOnce = UA_TRUE;
+        if(notification->notification.sequenceNumber > sub->sequenceNumber) {
             // If this is a keepalive message, its seqNo is the next seqNo to be used for an actual msg.
             // If this is a keepalive message, its seqNo is the next seqNo to be used for an actual msg.
             response->availableSequenceNumbersSize = 0;
             response->availableSequenceNumbersSize = 0;
             // .. and must be deleted
             // .. and must be deleted
             Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
             Subscription_deleteUnpublishedNotification(sub->sequenceNumber + 1, false, sub);
         } else {
         } else {
-            response->availableSequenceNumbersSize = Subscription_queuedNotifications(sub);
+            response->availableSequenceNumbersSize = sub->unpublishedNotificationsSize;
             response->availableSequenceNumbers = Subscription_getAvailableSequenceNumbers(sub);
             response->availableSequenceNumbers = Subscription_getAvailableSequenceNumbers(sub);
         }	  
         }	  
         // FIXME: This should be in processMSG();
         // FIXME: This should be in processMSG();
@@ -261,9 +261,10 @@ void Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
     }
     }
     response->resultsSize = request->subscriptionIdsSize;
     response->resultsSize = request->subscriptionIdsSize;
 
 
-    for(UA_Int32 i = 0; i < request->subscriptionIdsSize; i++)
-        response->results[i] = SubscriptionManager_deleteSubscription(server, &session->subscriptionManager,
-                                                                      request->subscriptionIds[i]);
+    for(size_t i = 0; i < request->subscriptionIdsSize; i++)
+        response->results[i] =
+            SubscriptionManager_deleteSubscription(server, &session->subscriptionManager,
+                                                   request->subscriptionIds[i]);
 } 
 } 
 
 
 void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
 void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
@@ -283,9 +284,10 @@ void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
     }
     }
     response->resultsSize = request->monitoredItemIdsSize;
     response->resultsSize = request->monitoredItemIdsSize;
 
 
-    for(UA_Int32 i = 0; i < request->monitoredItemIdsSize; i++)
-        response->results[i] = SubscriptionManager_deleteMonitoredItem(manager, sub->subscriptionID,
-                                                                       request->monitoredItemIds[i]);
+    for(size_t i = 0; i < request->monitoredItemIdsSize; i++)
+        response->results[i] =
+            SubscriptionManager_deleteMonitoredItem(manager, sub->subscriptionID,
+                                                    request->monitoredItemIds[i]);
 }
 }
 
 
 void Service_Republish(UA_Server *server, UA_Session *session,
 void Service_Republish(UA_Server *server, UA_Session *session,
@@ -301,7 +303,7 @@ void Service_Republish(UA_Server *server, UA_Session *session,
     // Find the notification in question
     // Find the notification in question
     UA_unpublishedNotification *notification;
     UA_unpublishedNotification *notification;
     LIST_FOREACH(notification, &sub->unpublishedNotifications, listEntry) {
     LIST_FOREACH(notification, &sub->unpublishedNotifications, listEntry) {
-      if (notification->notification->sequenceNumber == request->retransmitSequenceNumber)
+      if (notification->notification.sequenceNumber == request->retransmitSequenceNumber)
 	break;
 	break;
     }
     }
     if (!notification) {
     if (!notification) {
@@ -324,4 +326,4 @@ void Service_Republish(UA_Server *server, UA_Session *session,
     notification->publishedOnce = UA_TRUE;
     notification->publishedOnce = UA_TRUE;
     
     
     return;
     return;
-}
+}

+ 62 - 119
src/server/ua_services_view.c

@@ -9,9 +9,6 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
                          UA_UInt32 mask, UA_ReferenceDescription *descr) {
                          UA_UInt32 mask, UA_ReferenceDescription *descr) {
     UA_ReferenceDescription_init(descr);
     UA_ReferenceDescription_init(descr);
     UA_StatusCode retval = UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
     UA_StatusCode retval = UA_NodeId_copy(&curr->nodeId, &descr->nodeId.nodeId);
-    descr->nodeId.serverIndex = 0;
-    descr->nodeId.namespaceUri.length = -1;
-
     if(mask & UA_BROWSERESULTMASK_REFERENCETYPEID)
     if(mask & UA_BROWSERESULTMASK_REFERENCETYPEID)
         retval |= UA_NodeId_copy(&ref->referenceTypeId, &descr->referenceTypeId);
         retval |= UA_NodeId_copy(&ref->referenceTypeId, &descr->referenceTypeId);
     if(mask & UA_BROWSERESULTMASK_ISFORWARD)
     if(mask & UA_BROWSERESULTMASK_ISFORWARD)
@@ -24,7 +21,7 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
         retval |= UA_LocalizedText_copy(&curr->displayName, &descr->displayName);
         retval |= UA_LocalizedText_copy(&curr->displayName, &descr->displayName);
     if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION){
     if(mask & UA_BROWSERESULTMASK_TYPEDEFINITION){
         if(curr->nodeClass == UA_NODECLASS_OBJECT || curr->nodeClass == UA_NODECLASS_VARIABLE) {
         if(curr->nodeClass == UA_NODECLASS_OBJECT || curr->nodeClass == UA_NODECLASS_VARIABLE) {
-            for(UA_Int32 i = 0; i < curr->referencesSize; i++) {
+            for(size_t i = 0; i < curr->referencesSize; i++) {
                 UA_ReferenceNode *refnode = &curr->references[i];
                 UA_ReferenceNode *refnode = &curr->references[i];
                 if(refnode->referenceTypeId.identifier.numeric != UA_NS0ID_HASTYPEDEFINITION)
                 if(refnode->referenceTypeId.identifier.numeric != UA_NS0ID_HASTYPEDEFINITION)
                     continue;
                     continue;
@@ -33,15 +30,13 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
             }
             }
         }
         }
     }
     }
-
-    if(retval)
-        UA_ReferenceDescription_deleteMembers(descr);
     return retval;
     return retval;
 }
 }
 
 
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
-static const UA_Node * returnRelevantNodeExternal(UA_ExternalNodeStore *ens, const UA_BrowseDescription *descr,
-                                                  const UA_ReferenceNode *reference) {
+static const UA_Node *
+returnRelevantNodeExternal(UA_ExternalNodeStore *ens, const UA_BrowseDescription *descr,
+                           const UA_ReferenceNode *reference) {
     /*	prepare a read request in the external nodestore	*/
     /*	prepare a read request in the external nodestore	*/
     UA_ReadValueId *readValueIds = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], 6);
     UA_ReadValueId *readValueIds = UA_Array_new(&UA_TYPES[UA_TYPES_READVALUEID], 6);
     UA_UInt32 *indices = UA_Array_new(&UA_TYPES[UA_TYPES_UINT32], 6);
     UA_UInt32 *indices = UA_Array_new(&UA_TYPES[UA_TYPES_UINT32], 6);
@@ -127,10 +122,8 @@ returnRelevantNode(UA_Server *server, const UA_BrowseDescription *descr, UA_Bool
 
 
     /* return from the internal nodestore */
     /* return from the internal nodestore */
     const UA_Node *node = UA_NodeStore_get(server->nodestore, &reference->targetId.nodeId);
     const UA_Node *node = UA_NodeStore_get(server->nodestore, &reference->targetId.nodeId);
-    if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0) {
-    	UA_NodeStore_release(node);
+    if(node && descr->nodeClassMask != 0 && (node->nodeClass & descr->nodeClassMask) == 0)
         return NULL;
         return NULL;
-    }
     *isExternal = UA_FALSE;
     *isExternal = UA_FALSE;
     return node;
     return node;
 }
 }
@@ -146,11 +139,8 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
     const UA_Node *node = UA_NodeStore_get(ns, root);
     const UA_Node *node = UA_NodeStore_get(ns, root);
     if(!node)
     if(!node)
         return UA_STATUSCODE_BADNOMATCH;
         return UA_STATUSCODE_BADNOMATCH;
-    if(node->nodeClass != UA_NODECLASS_REFERENCETYPE)  {
-        UA_NodeStore_release(node);
+    if(node->nodeClass != UA_NODECLASS_REFERENCETYPE)
         return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-    }
-    UA_NodeStore_release(node);
 
 
     size_t results_size = 20; // probably too big, but saves mallocs
     size_t results_size = 20; // probably too big, but saves mallocs
     UA_NodeId *results = UA_malloc(sizeof(UA_NodeId) * results_size);
     UA_NodeId *results = UA_malloc(sizeof(UA_NodeId) * results_size);
@@ -169,7 +159,7 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
         node = UA_NodeStore_get(ns, &results[index]);
         node = UA_NodeStore_get(ns, &results[index]);
         if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
         if(!node || node->nodeClass != UA_NODECLASS_REFERENCETYPE)
             continue;
             continue;
-        for(UA_Int32 i = 0; i < node->referencesSize; i++) {
+        for(size_t i = 0; i < node->referencesSize; i++) {
             if(node->references[i].referenceTypeId.identifier.numeric != UA_NS0ID_HASSUBTYPE ||
             if(node->references[i].referenceTypeId.identifier.numeric != UA_NS0ID_HASSUBTYPE ||
                node->references[i].isInverse == UA_TRUE)
                node->references[i].isInverse == UA_TRUE)
                 continue;
                 continue;
@@ -190,11 +180,10 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
                 break;
                 break;
             }
             }
         }
         }
-        UA_NodeStore_release(node);
     } while(++index <= last && retval == UA_STATUSCODE_GOOD);
     } while(++index <= last && retval == UA_STATUSCODE_GOOD);
 
 
-    if(retval) {
-        UA_Array_delete(results, &UA_TYPES[UA_TYPES_NODEID], last);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Array_delete(results, last, &UA_TYPES[UA_TYPES_NODEID]);
         return retval;
         return retval;
     }
     }
 
 
@@ -204,11 +193,11 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
 }
 }
 
 
 static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session) {
 static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session) {
-    session->availableContinuationPoints++;
+    LIST_REMOVE(cp, pointers);
     UA_ByteString_deleteMembers(&cp->identifier);
     UA_ByteString_deleteMembers(&cp->identifier);
     UA_BrowseDescription_deleteMembers(&cp->browseDescription);
     UA_BrowseDescription_deleteMembers(&cp->browseDescription);
-    LIST_REMOVE(cp, pointers);
     UA_free(cp);
     UA_free(cp);
+    session->availableContinuationPoints++;
 }
 }
 
 
 /**
 /**
@@ -223,12 +212,11 @@ static void removeCp(struct ContinuationPointEntry *cp, UA_Session* session) {
  */
  */
 void
 void
 Service_Browse_single(UA_Server *server, UA_Session *session, struct ContinuationPointEntry *cp,
 Service_Browse_single(UA_Server *server, UA_Session *session, struct ContinuationPointEntry *cp,
-                      const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) {
-    UA_UInt32 continuationIndex = 0;
+                      const UA_BrowseDescription *descr, UA_UInt32 maxrefs, UA_BrowseResult *result) { 
     size_t referencesCount = 0;
     size_t referencesCount = 0;
-    UA_Int32 referencesIndex = 0;
-    
+    size_t referencesIndex = 0;
     /* set the browsedescription if a cp is given */
     /* set the browsedescription if a cp is given */
+    UA_UInt32 continuationIndex = 0;
     if(cp) {
     if(cp) {
         descr = &cp->browseDescription;
         descr = &cp->browseDescription;
         maxrefs = cp->maxReferences;
         maxrefs = cp->maxReferences;
@@ -255,16 +243,10 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
                 return;
                 return;
         } else {
         } else {
             const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &descr->referenceTypeId);
             const UA_Node *rootRef = UA_NodeStore_get(server->nodestore, &descr->referenceTypeId);
-            if(!rootRef) {
+            if(!rootRef || rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
                 return;
                 return;
             }
             }
-            if(rootRef->nodeClass != UA_NODECLASS_REFERENCETYPE) {
-                UA_NodeStore_release(rootRef);
-                result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
-                return;
-            }
-            UA_NodeStore_release(rootRef);
             relevant_refs = (UA_NodeId*)(uintptr_t)&descr->referenceTypeId;
             relevant_refs = (UA_NodeId*)(uintptr_t)&descr->referenceTypeId;
             relevant_refs_size = 1;
             relevant_refs_size = 1;
         }
         }
@@ -275,16 +257,15 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
     if(!node) {
     if(!node) {
         result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         if(!all_refs && descr->includeSubtypes)
         if(!all_refs && descr->includeSubtypes)
-            UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
+            UA_Array_delete(relevant_refs, relevant_refs_size, &UA_TYPES[UA_TYPES_NODEID]);
         return;
         return;
     }
     }
 
 
     /* if the node has no references, just return */
     /* if the node has no references, just return */
     if(node->referencesSize <= 0) {
     if(node->referencesSize <= 0) {
         result->referencesSize = 0;
         result->referencesSize = 0;
-        UA_NodeStore_release(node);
         if(!all_refs && descr->includeSubtypes)
         if(!all_refs && descr->includeSubtypes)
-            UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
+            UA_Array_delete(relevant_refs, relevant_refs_size, &UA_TYPES[UA_TYPES_NODEID]);
         return;
         return;
     }
     }
 
 
@@ -294,9 +275,9 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
         real_maxrefs = node->referencesSize;
         real_maxrefs = node->referencesSize;
     if(node->referencesSize <= 0)
     if(node->referencesSize <= 0)
         real_maxrefs = 0;
         real_maxrefs = 0;
-    else if(real_maxrefs > (UA_UInt32)node->referencesSize)
+    else if(real_maxrefs > node->referencesSize)
         real_maxrefs = node->referencesSize;
         real_maxrefs = node->referencesSize;
-    result->references = UA_malloc(sizeof(UA_ReferenceDescription) * real_maxrefs);
+    result->references = UA_Array_new(real_maxrefs, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
     if(!result->references) {
     if(!result->references) {
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         goto cleanup;
         goto cleanup;
@@ -305,6 +286,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
     /* loop over the node's references */
     /* loop over the node's references */
     size_t skipped = 0;
     size_t skipped = 0;
     UA_Boolean isExternal = UA_FALSE;
     UA_Boolean isExternal = UA_FALSE;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
     	isExternal = UA_FALSE;
     	isExternal = UA_FALSE;
     	const UA_Node *current =
     	const UA_Node *current =
@@ -312,39 +294,20 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
                                relevant_refs, relevant_refs_size, &isExternal);
                                relevant_refs, relevant_refs_size, &isExternal);
         if(!current)
         if(!current)
             continue;
             continue;
+
         if(skipped < continuationIndex) {
         if(skipped < continuationIndex) {
-#ifdef UA_EXTERNAL_NAMESPACES
-        	if(isExternal == UA_TRUE)
-        		/* relevant_node returns a node malloced with UA_ObjectNode_new
-                   if it is external (there is no UA_Node_new function) */
-        		UA_ObjectNode_delete((UA_ObjectNode*)(uintptr_t)current);
-        	else
-        		UA_NodeStore_release(current);
-#else
-        	UA_NodeStore_release(current);
-#endif
             skipped++;
             skipped++;
-            continue;
+        } else {
+            retval |= fillReferenceDescription(server->nodestore, current, &node->references[referencesIndex],
+                                               descr->resultMask, &result->references[referencesCount]);
+            referencesCount++;
         }
         }
-        UA_StatusCode retval =
-            fillReferenceDescription(server->nodestore, current, &node->references[referencesIndex],
-                                     descr->resultMask, &result->references[referencesCount]);
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef UA_EXTERNAL_NAMESPACES
+        /* relevant_node returns a node malloced with UA_ObjectNode_new
+           if it is external (there is no UA_Node_new function) */
         if(isExternal == UA_TRUE)
         if(isExternal == UA_TRUE)
         	UA_ObjectNode_delete((UA_ObjectNode*)(uintptr_t)current);
         	UA_ObjectNode_delete((UA_ObjectNode*)(uintptr_t)current);
-        else
-        	UA_NodeStore_release(current);
-#else
-        UA_NodeStore_release(current);
 #endif
 #endif
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_Array_delete(result->references, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], referencesCount);
-            result->references = NULL;
-            result->referencesSize = 0;
-            result->statusCode = UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE;
-            goto cleanup;
-        }
-        referencesCount++;
     }
     }
 
 
     result->referencesSize = referencesCount;
     result->referencesSize = referencesCount;
@@ -353,10 +316,16 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
         result->references = NULL;
         result->references = NULL;
     }
     }
 
 
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Array_delete(result->references, result->referencesSize, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
+        result->references = NULL;
+        result->referencesSize = 0;
+        result->statusCode = retval;
+    }
+
     cleanup:
     cleanup:
-    UA_NodeStore_release(node);
     if(!all_refs && descr->includeSubtypes)
     if(!all_refs && descr->includeSubtypes)
-        UA_Array_delete(relevant_refs, &UA_TYPES[UA_TYPES_NODEID], relevant_refs_size);
+        UA_Array_delete(relevant_refs, relevant_refs_size, &UA_TYPES[UA_TYPES_NODEID]);
     if(result->statusCode != UA_STATUSCODE_GOOD)
     if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
         return;
 
 
@@ -409,7 +378,7 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
     }
     }
 
 
     size_t size = request->nodesToBrowseSize;
     size_t size = request->nodesToBrowseSize;
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
+    response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_BROWSERESULT]);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
@@ -461,43 +430,25 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
         return;
         return;
    }
    }
    size_t size = request->continuationPointsSize;
    size_t size = request->continuationPointsSize;
-   if(!request->releaseContinuationPoints) {
-       /* continue with the cp */
-       response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
-       if(!response->results) {
-           response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
-           return;
-       }
-       response->resultsSize = size;
-       for(size_t i = 0; i < size; i++) {
-           struct ContinuationPointEntry *cp, *temp;
-           LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) {
-               if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
+   response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_BROWSERESULT]);
+   if(!response->results) {
+       response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+       return;
+   }
+
+   response->resultsSize = size;
+   for(size_t i = 0; i < size; i++) {
+       response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
+       struct ContinuationPointEntry *cp, *temp;
+       LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) {
+           if(UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
+               response->results[i].statusCode = UA_STATUSCODE_GOOD;
+               if(!request->releaseContinuationPoints)
                    Service_Browse_single(server, session, cp, NULL, 0, &response->results[i]);
                    Service_Browse_single(server, session, cp, NULL, 0, &response->results[i]);
-                   break;
-               }
-           }
-           if(!cp)
-               response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
-       }
-   } else {
-       /* remove the cp */
-       response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSERESULT], size);
-       if(!response->results) {
-           response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
-           return;
-       }
-       response->resultsSize = size;
-       for(size_t i = 0; i < size; i++) {
-           struct ContinuationPointEntry *cp, *temp;
-           LIST_FOREACH_SAFE(cp, &session->continuationPoints, pointers, temp) {
-               if(!UA_ByteString_equal(&cp->identifier, &request->continuationPoints[i])) {
+               else
                    removeCp(cp, session);
                    removeCp(cp, session);
-                   break;
-               }
+               break;
            }
            }
-           if(!cp)
-               response->results[i].statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        }
        }
    }
    }
 }
 }
@@ -508,12 +459,9 @@ void Service_BrowseNext(UA_Server *server, UA_Session *session, const UA_BrowseN
 
 
 static UA_StatusCode
 static UA_StatusCode
 walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_RelativePath *path,
 walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, const UA_RelativePath *path,
-               UA_Int32 pathindex, UA_BrowsePathTarget **targets, UA_Int32 *targets_size,
-               UA_Int32 *target_count) {
+               size_t pathindex, UA_BrowsePathTarget **targets, size_t *targets_size,
+               size_t *target_count) {
     const UA_RelativePathElement *elem = &path->elements[pathindex];
     const UA_RelativePathElement *elem = &path->elements[pathindex];
-    if(elem->targetName.name.length == -1)
-        return UA_STATUSCODE_BADBROWSENAMEINVALID;
-
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_NodeId *reftypes = NULL;
     UA_NodeId *reftypes = NULL;
     size_t reftypes_count = 1; // all_refs or no subtypes => 1
     size_t reftypes_count = 1; // all_refs or no subtypes => 1
@@ -528,7 +476,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
             return retval;
             return retval;
     }
     }
 
 
-    for(UA_Int32 i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; i++) {
+    for(size_t i = 0; i < node->referencesSize && retval == UA_STATUSCODE_GOOD; i++) {
         UA_Boolean match = all_refs;
         UA_Boolean match = all_refs;
         for(size_t j = 0; j < reftypes_count && !match; j++) {
         for(size_t j = 0; j < reftypes_count && !match; j++) {
             if(node->references[i].isInverse == elem->isInverse &&
             if(node->references[i].isInverse == elem->isInverse &&
@@ -546,7 +494,6 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
         // test the browsename
         // test the browsename
         if(elem->targetName.namespaceIndex != next->browseName.namespaceIndex ||
         if(elem->targetName.namespaceIndex != next->browseName.namespaceIndex ||
            !UA_String_equal(&elem->targetName.name, &next->browseName.name)) {
            !UA_String_equal(&elem->targetName.name, &next->browseName.name)) {
-            UA_NodeStore_release(next);
             continue;
             continue;
         }
         }
 
 
@@ -554,7 +501,6 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
             // recursion if the path is longer
             // recursion if the path is longer
             retval = walkBrowsePath(server, session, next, path, pathindex + 1,
             retval = walkBrowsePath(server, session, next, path, pathindex + 1,
                                     targets, targets_size, target_count);
                                     targets, targets_size, target_count);
-            UA_NodeStore_release(next);
         } else {
         } else {
             // add the browsetarget
             // add the browsetarget
             if(*target_count >= *targets_size) {
             if(*target_count >= *targets_size) {
@@ -562,7 +508,6 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
                 newtargets = UA_realloc(targets, sizeof(UA_BrowsePathTarget) * (*targets_size) * 2);
                 newtargets = UA_realloc(targets, sizeof(UA_BrowsePathTarget) * (*targets_size) * 2);
                 if(!newtargets) {
                 if(!newtargets) {
                     retval = UA_STATUSCODE_BADOUTOFMEMORY;
                     retval = UA_STATUSCODE_BADOUTOFMEMORY;
-                    UA_NodeStore_release(next);
                     break;
                     break;
                 }
                 }
                 *targets = newtargets;
                 *targets = newtargets;
@@ -572,7 +517,6 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
             UA_BrowsePathTarget *res = *targets;
             UA_BrowsePathTarget *res = *targets;
             UA_ExpandedNodeId_init(&res[*target_count].targetId);
             UA_ExpandedNodeId_init(&res[*target_count].targetId);
             retval = UA_NodeId_copy(&next->nodeId, &res[*target_count].targetId.nodeId);
             retval = UA_NodeId_copy(&next->nodeId, &res[*target_count].targetId.nodeId);
-            UA_NodeStore_release(next);
             if(retval != UA_STATUSCODE_GOOD)
             if(retval != UA_STATUSCODE_GOOD)
                 break;
                 break;
             res[*target_count].remainingPathIndex = UA_UINT32_MAX;
             res[*target_count].remainingPathIndex = UA_UINT32_MAX;
@@ -581,7 +525,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
     }
     }
 
 
     if(!all_refs && elem->includeSubtypes)
     if(!all_refs && elem->includeSubtypes)
-        UA_Array_delete(reftypes, &UA_TYPES[UA_TYPES_NODEID], (UA_Int32)reftypes_count);
+        UA_Array_delete(reftypes, reftypes_count, &UA_TYPES[UA_TYPES_NODEID]);
     return retval;
     return retval;
 }
 }
 
 
@@ -592,7 +536,7 @@ void Service_TranslateBrowsePathsToNodeIds_single(UA_Server *server, UA_Session
         return;
         return;
     }
     }
         
         
-    UA_Int32 arraySize = 10;
+    size_t arraySize = 10;
     result->targets = UA_malloc(sizeof(UA_BrowsePathTarget) * arraySize);
     result->targets = UA_malloc(sizeof(UA_BrowsePathTarget) * arraySize);
     if(!result->targets) {
     if(!result->targets) {
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
@@ -608,13 +552,12 @@ void Service_TranslateBrowsePathsToNodeIds_single(UA_Server *server, UA_Session
     }
     }
     result->statusCode = walkBrowsePath(server, session, firstNode, &path->relativePath, 0,
     result->statusCode = walkBrowsePath(server, session, firstNode, &path->relativePath, 0,
                                         &result->targets, &arraySize, &result->targetsSize);
                                         &result->targets, &arraySize, &result->targetsSize);
-    UA_NodeStore_release(firstNode);
     if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD)
     if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD)
         result->statusCode = UA_STATUSCODE_BADNOMATCH;
         result->statusCode = UA_STATUSCODE_BADNOMATCH;
     if(result->statusCode != UA_STATUSCODE_GOOD) {
     if(result->statusCode != UA_STATUSCODE_GOOD) {
-        UA_Array_delete(result->targets, &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], result->targetsSize);
+        UA_Array_delete(result->targets, result->targetsSize, &UA_TYPES[UA_TYPES_BROWSEPATHTARGET]);
         result->targets = NULL;
         result->targets = NULL;
-        result->targetsSize = -1;
+        result->targetsSize = 0;
     }
     }
 }
 }
 
 
@@ -630,7 +573,7 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
     }
     }
 
 
     size_t size = request->browsePathsSize;
     size_t size = request->browsePathsSize;
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_BROWSEPATHRESULT], size);
+    response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]);
     if(!response->results) {
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
         return;
@@ -684,8 +627,8 @@ void Service_RegisterNodes(UA_Server *server, UA_Session *session, const UA_Regi
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
     else {
     else {
         response->responseHeader.serviceResult =
         response->responseHeader.serviceResult =
-            UA_Array_copy(request->nodesToRegister, (void**)&response->registeredNodeIds,
-                          &UA_TYPES[UA_TYPES_NODEID], request->nodesToRegisterSize);
+            UA_Array_copy(request->nodesToRegister, request->nodesToRegisterSize,
+                          (void**)&response->registeredNodeIds, &UA_TYPES[UA_TYPES_NODEID]);
         if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
         if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
             response->registeredNodeIdsSize = request->nodesToRegisterSize;
             response->registeredNodeIdsSize = request->nodesToRegisterSize;
     }
     }

+ 43 - 96
src/server/ua_subscription.c

@@ -18,17 +18,17 @@ UA_Subscription *UA_Subscription_new(UA_Int32 subscriptionID) {
     new->timedUpdateIsRegistered = UA_FALSE;
     new->timedUpdateIsRegistered = UA_FALSE;
     LIST_INIT(&new->MonitoredItems);
     LIST_INIT(&new->MonitoredItems);
     LIST_INIT(&new->unpublishedNotifications);
     LIST_INIT(&new->unpublishedNotifications);
+    new->unpublishedNotificationsSize = 0;
     return new;
     return new;
 }
 }
 
 
 void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *server) {
 void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *server) {
-    UA_MonitoredItem *mon, *tmp_mon;
-    
     // Just in case any parallel process attempts to access this subscription
     // Just in case any parallel process attempts to access this subscription
     // while we are deleting it... make it vanish.
     // while we are deleting it... make it vanish.
     subscription->subscriptionID = 0;
     subscription->subscriptionID = 0;
     
     
     // Delete monitored Items
     // Delete monitored Items
+    UA_MonitoredItem *mon, *tmp_mon;
     LIST_FOREACH_SAFE(mon, &subscription->MonitoredItems, listEntry, tmp_mon) {
     LIST_FOREACH_SAFE(mon, &subscription->MonitoredItems, listEntry, tmp_mon) {
         LIST_REMOVE(mon, listEntry);
         LIST_REMOVE(mon, listEntry);
         MonitoredItem_delete(mon);
         MonitoredItem_delete(mon);
@@ -38,39 +38,27 @@ void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *ser
     Subscription_deleteUnpublishedNotification(0, true, subscription);
     Subscription_deleteUnpublishedNotification(0, true, subscription);
     
     
     // Unhook/Unregister any timed work assiociated with this subscription
     // Unhook/Unregister any timed work assiociated with this subscription
-    if(subscription->timedUpdateJob != NULL){
+    if(subscription->timedUpdateJob) {
         Subscription_unregisterUpdateJob(server, subscription);
         Subscription_unregisterUpdateJob(server, subscription);
         UA_free(subscription->timedUpdateJob);
         UA_free(subscription->timedUpdateJob);
     }
     }
 }
 }
 
 
-UA_UInt32 Subscription_queuedNotifications(UA_Subscription *subscription) {
-    if(!subscription)
-        return 0;
-
-    UA_UInt32 j = 0;
-    UA_unpublishedNotification *i;
-    LIST_FOREACH(i, &subscription->unpublishedNotifications, listEntry)
-        j++;
-    return j;
-}
-
 void Subscription_generateKeepAlive(UA_Subscription *subscription) {
 void Subscription_generateKeepAlive(UA_Subscription *subscription) {
     if(subscription->keepAliveCount.currentValue > subscription->keepAliveCount.minValue &&
     if(subscription->keepAliveCount.currentValue > subscription->keepAliveCount.minValue &&
        subscription->keepAliveCount.currentValue <= subscription->keepAliveCount.maxValue)
        subscription->keepAliveCount.currentValue <= subscription->keepAliveCount.maxValue)
         return;
         return;
 
 
-    UA_unpublishedNotification *msg = UA_malloc(sizeof(UA_unpublishedNotification));
+    UA_unpublishedNotification *msg = UA_calloc(1,sizeof(UA_unpublishedNotification));
     if(!msg)
     if(!msg)
         return;
         return;
-    msg->notification = NULL;
-    msg->notification = UA_malloc(sizeof(UA_NotificationMessage));
-    msg->notification->notificationData = NULL;
+    msg->notification.notificationData = NULL;
     // KeepAlive uses next message, but does not increment counter
     // KeepAlive uses next message, but does not increment counter
-    msg->notification->sequenceNumber = subscription->sequenceNumber + 1;
-    msg->notification->publishTime    = UA_DateTime_now();
-    msg->notification->notificationDataSize = 0;
+    msg->notification.sequenceNumber = subscription->sequenceNumber + 1;
+    msg->notification.publishTime    = UA_DateTime_now();
+    msg->notification.notificationDataSize = 0;
     LIST_INSERT_HEAD(&subscription->unpublishedNotifications, msg, listEntry);
     LIST_INSERT_HEAD(&subscription->unpublishedNotifications, msg, listEntry);
+    subscription->unpublishedNotificationsSize += 1;
     subscription->keepAliveCount.currentValue = subscription->keepAliveCount.maxValue;
     subscription->keepAliveCount.currentValue = subscription->keepAliveCount.maxValue;
 }
 }
 
 
@@ -79,8 +67,6 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
     //MonitoredItem_queuedValue *queuedValue;
     //MonitoredItem_queuedValue *queuedValue;
     UA_unpublishedNotification *msg;
     UA_unpublishedNotification *msg;
     UA_UInt32 monItemsChangeT = 0, monItemsStatusT = 0, monItemsEventT = 0;
     UA_UInt32 monItemsChangeT = 0, monItemsStatusT = 0, monItemsEventT = 0;
-    UA_DataChangeNotification *changeNotification;
-    size_t notificationOffset;
     
     
     if(!subscription || subscription->lastPublished + subscription->publishingInterval > UA_DateTime_now())
     if(!subscription || subscription->lastPublished + subscription->publishingInterval > UA_DateTime_now())
         return;
         return;
@@ -100,7 +86,7 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
     }
     }
     
     
     // FIXME: This is hardcoded to 100 because it is not covered by the spec but we need to protect the server!
     // FIXME: This is hardcoded to 100 because it is not covered by the spec but we need to protect the server!
-    if(Subscription_queuedNotifications(subscription) >= 10) {
+    if(subscription->unpublishedNotificationsSize >= 10) {
         // Remove last entry
         // Remove last entry
         Subscription_deleteUnpublishedNotification(0, true, subscription);
         Subscription_deleteUnpublishedNotification(0, true, subscription);
     }
     }
@@ -115,33 +101,27 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
         return;
         return;
     }
     }
     
     
-    msg = (UA_unpublishedNotification *) UA_malloc(sizeof(UA_unpublishedNotification));
-    msg->notification = UA_malloc(sizeof(UA_NotificationMessage));
-    INITPOINTER(msg->notification->notificationData);
-    msg->publishedOnce = UA_FALSE;
-    msg->notification->sequenceNumber = subscription->sequenceNumber++;
-    msg->notification->publishTime    = UA_DateTime_now();
+    msg = UA_calloc(1, sizeof(UA_unpublishedNotification));
+    msg->notification.sequenceNumber = subscription->sequenceNumber++;
+    msg->notification.publishTime = UA_DateTime_now();
     
     
     // NotificationData is an array of Change, Status and Event messages, each containing the appropriate
     // NotificationData is an array of Change, Status and Event messages, each containing the appropriate
     // list of Queued values from all monitoredItems of that type
     // list of Queued values from all monitoredItems of that type
-    msg->notification->notificationDataSize = ISNOTZERO(monItemsChangeT);
+    msg->notification.notificationDataSize = !!monItemsChangeT; // 1 if the pointer is not null, else 0
     // + ISNOTZERO(monItemsEventT) + ISNOTZERO(monItemsStatusT);
     // + ISNOTZERO(monItemsEventT) + ISNOTZERO(monItemsStatusT);
-    msg->notification->notificationData = UA_Array_new(&UA_TYPES[UA_TYPES_EXTENSIONOBJECT], 
-                                                       msg->notification->notificationDataSize);
+    msg->notification.notificationData =
+        UA_Array_new(msg->notification.notificationDataSize, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
     
     
-    for(int notmsgn=0; notmsgn < msg->notification->notificationDataSize; notmsgn++) {
+    for(size_t notmsgn = 0; notmsgn < msg->notification.notificationDataSize; notmsgn++) {
         // Set the notification message type and encoding for each of 
         // Set the notification message type and encoding for each of 
         //   the three possible NotificationData Types
         //   the three possible NotificationData Types
-        msg->notification->notificationData[notmsgn].encoding = 1; // Encoding is always binary
-        msg->notification->notificationData[notmsgn].typeId = UA_NODEID_NUMERIC(0, 811);
-        
+
+        /* msg->notification->notificationData[notmsgn].encoding = 1; // Encoding is always binary */
+        /* msg->notification->notificationData[notmsgn].typeId = UA_NODEID_NUMERIC(0, 811); */
+      
         if(notmsgn == 0) {
         if(notmsgn == 0) {
-            // Construct a DataChangeNotification
-            changeNotification = UA_malloc(sizeof(UA_DataChangeNotification));
-	
-            // Create one DataChangeNotification for each queue item held in each monitoredItems queue:
-            changeNotification->monitoredItems = UA_Array_new(&UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION],
-                                                              monItemsChangeT);
+            UA_DataChangeNotification *changeNotification = UA_DataChangeNotification_new();
+            changeNotification->monitoredItems = UA_Array_new(monItemsChangeT, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]);
 	
 	
             // Scan all monitoredItems in this subscription and have their queue transformed into an Array of
             // Scan all monitoredItems in this subscription and have their queue transformed into an Array of
             // the propper NotificationMessageType (Status, Change, Event)
             // the propper NotificationMessageType (Status, Change, Event)
@@ -153,29 +133,10 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
                 monItemsChangeT += MonitoredItem_QueueToDataChangeNotifications(&changeNotification->monitoredItems[monItemsChangeT], mon);
                 monItemsChangeT += MonitoredItem_QueueToDataChangeNotifications(&changeNotification->monitoredItems[monItemsChangeT], mon);
                 MonitoredItem_ClearQueue(mon);
                 MonitoredItem_ClearQueue(mon);
             }
             }
-            
-            changeNotification->monitoredItemsSize  = monItemsChangeT;
-            changeNotification->diagnosticInfosSize = 0;
-            changeNotification->diagnosticInfos     = NULL;
-        
-            msg->notification->notificationData[notmsgn].body.length =
-                UA_calcSizeBinary(changeNotification, &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]);
-            msg->notification->notificationData[notmsgn].body.data   =
-                UA_calloc(msg->notification->notificationData[notmsgn].body.length, sizeof(UA_Byte));
-        
-            notificationOffset = 0;
-            UA_StatusCode retval = UA_encodeBinary(changeNotification, &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION],
-                                                   &msg->notification->notificationData[notmsgn].body, &notificationOffset);
-            if(retval != UA_STATUSCODE_GOOD)
-                UA_ByteString_deleteMembers(&msg->notification->notificationData[notmsgn].body);
-	
-            // FIXME: Not properly freed!
-            for(unsigned int i=0; i<monItemsChangeT; i++) {
-                UA_MonitoredItemNotification *thisNotification = &(changeNotification->monitoredItems[i]);
-                UA_DataValue_deleteMembers(&(thisNotification->value));
-            }
-            UA_free(changeNotification->monitoredItems);
-            UA_free(changeNotification);
+            changeNotification->monitoredItemsSize = monItemsChangeT;
+            msg->notification.notificationData[notmsgn].encoding = UA_EXTENSIONOBJECT_DECODED;
+            msg->notification.notificationData[notmsgn].content.decoded.type = &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION];
+            msg->notification.notificationData[notmsgn].content.decoded.data = changeNotification;
         } else if(notmsgn == 1) {
         } else if(notmsgn == 1) {
             // FIXME: Constructing a StatusChangeNotification is not implemented
             // FIXME: Constructing a StatusChangeNotification is not implemented
         } else if(notmsgn == 2) {
         } else if(notmsgn == 2) {
@@ -183,17 +144,18 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
         }
         }
     }
     }
     LIST_INSERT_HEAD(&subscription->unpublishedNotifications, msg, listEntry);
     LIST_INSERT_HEAD(&subscription->unpublishedNotifications, msg, listEntry);
+    subscription->unpublishedNotificationsSize += 1;
 }
 }
 
 
 UA_UInt32 *Subscription_getAvailableSequenceNumbers(UA_Subscription *sub) {
 UA_UInt32 *Subscription_getAvailableSequenceNumbers(UA_Subscription *sub) {
-    UA_UInt32 *seqArray = UA_malloc(sizeof(UA_UInt32) * Subscription_queuedNotifications(sub));
+    UA_UInt32 *seqArray = UA_malloc(sizeof(UA_UInt32) * sub->unpublishedNotificationsSize);
     if(!seqArray)
     if(!seqArray)
         return NULL;
         return NULL;
   
   
     int i = 0;
     int i = 0;
     UA_unpublishedNotification *not;
     UA_unpublishedNotification *not;
     LIST_FOREACH(not, &sub->unpublishedNotifications, listEntry) {
     LIST_FOREACH(not, &sub->unpublishedNotifications, listEntry) {
-        seqArray[i] = not->notification->sequenceNumber;
+        seqArray[i] = not->notification.sequenceNumber;
         i++;
         i++;
     }
     }
     return seqArray;
     return seqArray;
@@ -203,36 +165,27 @@ void Subscription_copyNotificationMessage(UA_NotificationMessage *dst, UA_unpubl
     if(!dst)
     if(!dst)
         return;
         return;
     
     
-    UA_NotificationMessage *latest = src->notification;
+    UA_NotificationMessage *latest = &src->notification;
     dst->notificationDataSize = latest->notificationDataSize;
     dst->notificationDataSize = latest->notificationDataSize;
     dst->publishTime = latest->publishTime;
     dst->publishTime = latest->publishTime;
     dst->sequenceNumber = latest->sequenceNumber;
     dst->sequenceNumber = latest->sequenceNumber;
     
     
     if(latest->notificationDataSize == 0)
     if(latest->notificationDataSize == 0)
         return;
         return;
-    
-    dst->notificationData = (UA_ExtensionObject *) UA_malloc(sizeof(UA_ExtensionObject));
-    dst->notificationData->encoding = latest->notificationData->encoding;
-    dst->notificationData->typeId   = latest->notificationData->typeId;
-    UA_ByteString_copy(&latest->notificationData->body,
-                       &dst->notificationData->body);
+
+    dst->notificationData = UA_ExtensionObject_new();
+    UA_ExtensionObject_copy(latest->notificationData, dst->notificationData);
 }
 }
 
 
 UA_UInt32 Subscription_deleteUnpublishedNotification(UA_UInt32 seqNo, UA_Boolean bDeleteAll, UA_Subscription *sub) {
 UA_UInt32 Subscription_deleteUnpublishedNotification(UA_UInt32 seqNo, UA_Boolean bDeleteAll, UA_Subscription *sub) {
     UA_UInt32 deletedItems = 0;
     UA_UInt32 deletedItems = 0;
     UA_unpublishedNotification *not, *tmp;
     UA_unpublishedNotification *not, *tmp;
     LIST_FOREACH_SAFE(not, &sub->unpublishedNotifications, listEntry, tmp) {
     LIST_FOREACH_SAFE(not, &sub->unpublishedNotifications, listEntry, tmp) {
-        if (!bDeleteAll && not->notification->sequenceNumber != seqNo)
+        if(!bDeleteAll && not->notification.sequenceNumber != seqNo)
             continue;
             continue;
         LIST_REMOVE(not, listEntry);
         LIST_REMOVE(not, listEntry);
-        if(not->notification) {
-            if(not->notification->notificationData) {
-                if(not->notification->notificationData->body.data)
-                    UA_free(not->notification->notificationData->body.data);
-                UA_free(not->notification->notificationData);
-            }
-            UA_free(not->notification);
-        }
+        sub->unpublishedNotificationsSize -= 1;
+        UA_NotificationMessage_deleteMembers(&not->notification);
         UA_free(not);
         UA_free(not);
         deletedItems++;
         deletedItems++;
     }
     }
@@ -280,13 +233,11 @@ UA_StatusCode Subscription_createdUpdateJob(UA_Server *server, UA_Guid jobId, UA
 }
 }
 
 
 UA_StatusCode Subscription_registerUpdateJob(UA_Server *server, UA_Subscription *sub) {
 UA_StatusCode Subscription_registerUpdateJob(UA_Server *server, UA_Subscription *sub) {
-    if(server == NULL || sub == NULL)
-        return UA_STATUSCODE_BADSERVERINDEXINVALID;
-    
     if(sub->publishingInterval <= 5 ) 
     if(sub->publishingInterval <= 5 ) 
         return UA_STATUSCODE_BADNOTSUPPORTED;
         return UA_STATUSCODE_BADNOTSUPPORTED;
     
     
-    // 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
+    /* 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, sub->publishingInterval,
                                                     &sub->timedUpdateJobGuid);
                                                     &sub->timedUpdateJobGuid);
     if(retval == UA_STATUSCODE_GOOD)
     if(retval == UA_STATUSCODE_GOOD)
@@ -295,18 +246,15 @@ UA_StatusCode Subscription_registerUpdateJob(UA_Server *server, UA_Subscription
 }
 }
 
 
 UA_StatusCode Subscription_unregisterUpdateJob(UA_Server *server, UA_Subscription *sub) {
 UA_StatusCode Subscription_unregisterUpdateJob(UA_Server *server, UA_Subscription *sub) {
-    if(server == NULL || sub == NULL)
-        return UA_STATUSCODE_BADSERVERINDEXINVALID;
-    UA_Int32 retval = UA_Server_removeRepeatedJob(server, sub->timedUpdateJobGuid);
     sub->timedUpdateIsRegistered = UA_FALSE;
     sub->timedUpdateIsRegistered = UA_FALSE;
-    return retval;
+    return UA_Server_removeRepeatedJob(server, sub->timedUpdateJobGuid);
 }
 }
 
 
 /*****************/
 /*****************/
 /* MonitoredItem */
 /* MonitoredItem */
 /*****************/
 /*****************/
 
 
-UA_MonitoredItem *UA_MonitoredItem_new() {
+UA_MonitoredItem * UA_MonitoredItem_new() {
     UA_MonitoredItem *new = (UA_MonitoredItem *) UA_malloc(sizeof(UA_MonitoredItem));
     UA_MonitoredItem *new = (UA_MonitoredItem *) UA_malloc(sizeof(UA_MonitoredItem));
     new->queueSize   = (UA_UInt32_BoundedValue) { .minValue = 0, .maxValue = 0, .currentValue = 0};
     new->queueSize   = (UA_UInt32_BoundedValue) { .minValue = 0, .maxValue = 0, .currentValue = 0};
     new->lastSampled = 0;
     new->lastSampled = 0;
@@ -314,7 +262,7 @@ UA_MonitoredItem *UA_MonitoredItem_new() {
     new->monitoredItemType = MONITOREDITEM_TYPE_CHANGENOTIFY;
     new->monitoredItemType = MONITOREDITEM_TYPE_CHANGENOTIFY;
     TAILQ_INIT(&new->queue);
     TAILQ_INIT(&new->queue);
     UA_NodeId_init(&new->monitoredNodeId);
     UA_NodeId_init(&new->monitoredNodeId);
-    INITPOINTER(new->lastSampledValue.data );
+    new->lastSampledValue.data = 0;
     return new;
     return new;
 }
 }
 
 
@@ -500,7 +448,6 @@ void MonitoredItem_QueuePushDataValue(UA_Server *server, UA_MonitoredItem *monit
     UA_Boolean samplingError = MonitoredItem_CopyMonitoredValueToVariant(monitoredItem->attributeID, target,
     UA_Boolean samplingError = MonitoredItem_CopyMonitoredValueToVariant(monitoredItem->attributeID, target,
                                                                          &newvalue->value);
                                                                          &newvalue->value);
 
 
-    UA_NodeStore_release(target);
     if(samplingError != UA_FALSE || !newvalue->value.value.type) {
     if(samplingError != UA_FALSE || !newvalue->value.value.type) {
         UA_DataValue_deleteMembers(&newvalue->value);
         UA_DataValue_deleteMembers(&newvalue->value);
         UA_free(newvalue);
         UA_free(newvalue);
@@ -520,7 +467,7 @@ void MonitoredItem_QueuePushDataValue(UA_Server *server, UA_MonitoredItem *monit
     }
     }
   
   
     // encode the data to find if its different to the previous
     // encode the data to find if its different to the previous
-    newValueAsByteString.length = UA_calcSizeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE]);
+    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);
     newValueAsByteString.data   = UA_malloc(newValueAsByteString.length);
     UA_StatusCode retval = UA_encodeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE], &newValueAsByteString, &encodingOffset);
     UA_StatusCode retval = UA_encodeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE], &newValueAsByteString, &encodingOffset);
     if(retval != UA_STATUSCODE_GOOD)
     if(retval != UA_STATUSCODE_GOOD)

+ 5 - 9
src/server/ua_subscription.h

@@ -6,9 +6,6 @@
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
 #include "ua_nodes.h"
 #include "ua_nodes.h"
 
 
-#define INITPOINTER(src) (src) = NULL;
-#define ISNOTZERO(value) ((value == 0) ? 0 : 1)
-
 /*****************/
 /*****************/
 /* MonitoredItem */
 /* MonitoredItem */
 /*****************/
 /*****************/
@@ -71,7 +68,7 @@ int MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *d
 typedef struct UA_unpublishedNotification {
 typedef struct UA_unpublishedNotification {
     UA_Boolean publishedOnce;
     UA_Boolean publishedOnce;
     LIST_ENTRY(UA_unpublishedNotification) listEntry;
     LIST_ENTRY(UA_unpublishedNotification) listEntry;
-    UA_NotificationMessage *notification;
+    UA_NotificationMessage notification;
 } UA_unpublishedNotification;
 } UA_unpublishedNotification;
 
 
 typedef struct UA_Subscription {
 typedef struct UA_Subscription {
@@ -89,21 +86,20 @@ typedef struct UA_Subscription {
     UA_Job *timedUpdateJob;
     UA_Job *timedUpdateJob;
     UA_Boolean timedUpdateIsRegistered;
     UA_Boolean timedUpdateIsRegistered;
     LIST_HEAD(UA_ListOfUnpublishedNotifications, UA_unpublishedNotification) unpublishedNotifications;
     LIST_HEAD(UA_ListOfUnpublishedNotifications, UA_unpublishedNotification) unpublishedNotifications;
+    size_t unpublishedNotificationsSize;
     LIST_HEAD(UA_ListOfUAMonitoredItems, UA_MonitoredItem) MonitoredItems;
     LIST_HEAD(UA_ListOfUAMonitoredItems, UA_MonitoredItem) MonitoredItems;
 } UA_Subscription;
 } UA_Subscription;
 
 
 UA_Subscription *UA_Subscription_new(UA_Int32 subscriptionID);
 UA_Subscription *UA_Subscription_new(UA_Int32 subscriptionID);
 void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *server);
 void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *server);
 void Subscription_updateNotifications(UA_Subscription *subscription);
 void Subscription_updateNotifications(UA_Subscription *subscription);
-UA_UInt32 Subscription_queuedNotifications(UA_Subscription *subscription);
 UA_UInt32 *Subscription_getAvailableSequenceNumbers(UA_Subscription *sub);
 UA_UInt32 *Subscription_getAvailableSequenceNumbers(UA_Subscription *sub);
-void Subscription_copyNotificationMessage(UA_NotificationMessage *dst, UA_unpublishedNotification *sub);
-UA_UInt32 Subscription_deleteUnpublishedNotification(UA_UInt32 seqNo, UA_Boolean bDeleteAll, UA_Subscription *sub);
 void Subscription_generateKeepAlive(UA_Subscription *subscription);
 void Subscription_generateKeepAlive(UA_Subscription *subscription);
+void Subscription_copyTopNotificationMessage(UA_NotificationMessage *dst, UA_Subscription *sub);
+UA_UInt32 Subscription_deleteUnpublishedNotification(UA_UInt32 seqNo, UA_Boolean bDeleteAll, UA_Subscription *sub);
+void Subscription_copyNotificationMessage(UA_NotificationMessage *dst, UA_unpublishedNotification *src);
 UA_StatusCode Subscription_createdUpdateJob(UA_Server *server, UA_Guid jobId, UA_Subscription *sub);
 UA_StatusCode Subscription_createdUpdateJob(UA_Server *server, UA_Guid jobId, UA_Subscription *sub);
 UA_StatusCode Subscription_registerUpdateJob(UA_Server *server, UA_Subscription *sub);
 UA_StatusCode Subscription_registerUpdateJob(UA_Server *server, UA_Subscription *sub);
 UA_StatusCode Subscription_unregisterUpdateJob(UA_Server *server, UA_Subscription *sub);
 UA_StatusCode Subscription_unregisterUpdateJob(UA_Server *server, UA_Subscription *sub);
 
 
-static void Subscription_timedUpdateNotificationsJob(UA_Server *server, void *data);
-
 #endif /* UA_SUBSCRIPTION_H_ */
 #endif /* UA_SUBSCRIPTION_H_ */

+ 66 - 58
src/ua_connection.c

@@ -1,6 +1,7 @@
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_connection.h"
 #include "ua_connection.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
+#include "ua_types_generated_encoding_binary.h"
 #include "ua_securechannel.h"
 #include "ua_securechannel.h"
 
 
 // max message size is 64k
 // max message size is 64k
@@ -28,97 +29,104 @@ void UA_Connection_deleteMembers(UA_Connection *connection) {
     UA_ByteString_deleteMembers(&connection->incompleteMessage);
     UA_ByteString_deleteMembers(&connection->incompleteMessage);
 }
 }
 
 
-UA_Job UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString received) {
-    UA_Job job = (UA_Job){.type = UA_JOBTYPE_NOTHING};
-    if(received.length == -1)
-        return job;
-
-    UA_ByteString current;
-    if(connection->incompleteMessage.length <= 0)
-        current = received;
-    else {
+UA_StatusCode
+UA_Connection_completeMessages(UA_Connection *connection, UA_ByteString * UA_RESTRICT message,
+                              UA_Boolean * UA_RESTRICT realloced) {
+    UA_ByteString *current = message;
+    *realloced = UA_FALSE;
+    if(connection->incompleteMessage.length > 0) {
         /* concat the existing incomplete message with the new message */
         /* concat the existing incomplete message with the new message */
-        current.data = UA_realloc(connection->incompleteMessage.data,
-                                  connection->incompleteMessage.length + received.length);
-        if(!current.data) {
+        UA_Byte *data = UA_realloc(connection->incompleteMessage.data,
+                                   connection->incompleteMessage.length + message->length);
+        if(!data) {
             /* not enough memory */
             /* not enough memory */
             UA_ByteString_deleteMembers(&connection->incompleteMessage);
             UA_ByteString_deleteMembers(&connection->incompleteMessage);
-            connection->releaseRecvBuffer(connection, &received);
-            return job;
+            connection->releaseRecvBuffer(connection, message);
+            return UA_STATUSCODE_BADOUTOFMEMORY;
         }
         }
-        memcpy(current.data + connection->incompleteMessage.length, received.data, received.length);
-        current.length = connection->incompleteMessage.length + received.length;
-        connection->releaseRecvBuffer(connection, &received);
-        UA_ByteString_init(&connection->incompleteMessage);
+        memcpy(&data[connection->incompleteMessage.length], message->data, message->length);
+        connection->incompleteMessage.data = data;
+        connection->incompleteMessage.length += message->length;
+        connection->releaseRecvBuffer(connection, message);
+        current = &connection->incompleteMessage;
+        *realloced = UA_TRUE;
     }
     }
 
 
     /* the while loop sets pos to the first element after the last complete message. if a message
     /* the while loop sets pos to the first element after the last complete message. if a message
        contains garbage, the buffer length is set to contain only the "good" messages before. */
        contains garbage, the buffer length is set to contain only the "good" messages before. */
     size_t pos = 0;
     size_t pos = 0;
-    while(current.length - pos >= 16) {
-        UA_UInt32 msgtype = current.data[pos] + (current.data[pos+1] << 8) + (current.data[pos+2] << 16);
+    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);
         if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
         if(msgtype != ('M' + ('S' << 8) + ('G' << 16)) &&
            msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
            msgtype != ('O' + ('P' << 8) + ('N' << 16)) &&
            msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
            msgtype != ('H' + ('E' << 8) + ('L' << 16)) &&
            msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&
            msgtype != ('A' + ('C' << 8) + ('K' << 16)) &&
            msgtype != ('C' + ('L' << 8) + ('O' << 16))) {
            msgtype != ('C' + ('L' << 8) + ('O' << 16))) {
-            /* the message type is not recognized. throw the remaining bytestring away */
-            current.length = pos;
+            /* the message type is not recognized */
+            delete_at = pos; // throw the remaining message away
             break;
             break;
         }
         }
         UA_Int32 length = 0;
         UA_Int32 length = 0;
         size_t length_pos = pos + 4;
         size_t length_pos = pos + 4;
-        UA_StatusCode retval = UA_Int32_decodeBinary(&current, &length_pos, &length);
-        if(retval != UA_STATUSCODE_GOOD || length < 16 ||
-           length > (UA_Int32)connection->localConf.maxMessageSize) {
+        UA_StatusCode retval = UA_Int32_decodeBinary(current, &length_pos, &length);
+        if(retval != UA_STATUSCODE_GOOD || length < 16 || length > (UA_Int32)connection->localConf.maxMessageSize) {
             /* the message size is not allowed. throw the remaining bytestring away */
             /* the message size is not allowed. throw the remaining bytestring away */
-            current.length = pos;
+            delete_at = pos;
             break;
             break;
         }
         }
-        if(length + (UA_Int32)pos > current.length)
+        if(length + pos > current->length)
             break; /* the message is incomplete. keep the beginning */
             break; /* the message is incomplete. keep the beginning */
         pos += length;
         pos += length;
     }
     }
 
 
-    if(current.length == 0) {
-        /* throw everything away */
-        if(current.data == received.data)
-            connection->releaseRecvBuffer(connection, &received);
-        else
-            UA_ByteString_deleteMembers(&current);
-        return job;
+    /* throw the message away */
+    if(delete_at == 0) {
+        if(!*realloced) {
+            connection->releaseRecvBuffer(connection, message);
+            *realloced = UA_TRUE;
+        } else
+            UA_ByteString_deleteMembers(current);
+        return UA_STATUSCODE_GOOD;
     }
     }
 
 
+    /* no complete message at all */
     if(pos == 0) {
     if(pos == 0) {
-        /* no complete message in current */
-        if(current.data == received.data) {
-            /* copy the data into the connection */
-            UA_ByteString_copy(&current, &connection->incompleteMessage);
-            connection->releaseRecvBuffer(connection, &received);
-        } else {
-            /* the data is already copied off the network stack */
-            connection->incompleteMessage = current;
-        }
-        return job;
+        if(!*realloced) {
+            /* store the buffer in the connection */
+            UA_ByteString_copy(current, &connection->incompleteMessage);
+            connection->releaseRecvBuffer(connection, message);
+            *realloced = UA_TRUE;
+        } 
+        return UA_STATUSCODE_GOOD;
     }
     }
 
 
-    if(current.length != (UA_Int32)pos) {
-        /* there is an incomplete message at the end of current */
-        connection->incompleteMessage.data = UA_malloc(current.length - pos);
-        if(connection->incompleteMessage.data) {
-            memcpy(connection->incompleteMessage.data, &current.data[pos], current.length - pos);
-            connection->incompleteMessage.length = current.length - pos;
+    /* there remains an incomplete message at the end */
+    if(current->length != pos) {
+        UA_Byte *data = UA_malloc(current->length - pos);
+        if(!data) {
+            UA_ByteString_deleteMembers(&connection->incompleteMessage);
+            if(!*realloced) {
+                connection->releaseRecvBuffer(connection, message);
+                *realloced = UA_TRUE;
+            }
+            return UA_STATUSCODE_BADOUTOFMEMORY;
         }
         }
-        current.length = pos;
+        size_t newlength = current->length - pos;
+        memcpy(data, &current->data[pos], newlength);
+        current->length = pos;
+        if(*realloced)
+            *message = *current;
+        connection->incompleteMessage.data = data;
+        connection->incompleteMessage.length = newlength;
+        return UA_STATUSCODE_GOOD;
     }
     }
 
 
-    job.job.binaryMessage.message = current;
-    job.job.binaryMessage.connection = connection;
-    if(current.data == received.data)
-        job.type = UA_JOBTYPE_BINARYMESSAGE_NETWORKLAYER;
-    else
-        job.type = UA_JOBTYPE_BINARYMESSAGE_ALLOCATED;
-    return job;
+    if(current == &connection->incompleteMessage) {
+        *message = *current;
+        connection->incompleteMessage = UA_BYTESTRING_NULL;
+    }
+    return UA_STATUSCODE_GOOD;
 }
 }
 
 
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {
 void UA_Connection_detachSecureChannel(UA_Connection *connection) {

+ 1 - 0
src/ua_securechannel.c

@@ -2,6 +2,7 @@
 #include "ua_securechannel.h"
 #include "ua_securechannel.h"
 #include "ua_session.h"
 #include "ua_session.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
+#include "ua_types_generated_encoding_binary.h"
 #include "ua_transport_generated_encoding_binary.h"
 #include "ua_transport_generated_encoding_binary.h"
 
 
 void UA_SecureChannel_init(UA_SecureChannel *channel) {
 void UA_SecureChannel_init(UA_SecureChannel *channel) {

+ 1 - 1
src/ua_securechannel.h

@@ -2,7 +2,7 @@
 #define UA_SECURECHANNEL_H_
 #define UA_SECURECHANNEL_H_
 
 
 #include "queue.h"
 #include "queue.h"
-#include "ua_types_generated.h"
+#include "ua_types.h"
 #include "ua_transport_generated.h"
 #include "ua_transport_generated.h"
 #include "ua_connection.h"
 #include "ua_connection.h"
 
 

+ 8 - 8
src/ua_session.c

@@ -3,11 +3,11 @@
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"
 
 
 UA_Session anonymousSession = {
 UA_Session anonymousSession = {
-    .clientDescription =  {.applicationUri = {-1, NULL}, .productUri = {-1, NULL},
-                           .applicationName = {.locale = {-1, NULL}, .text = {-1, NULL}},
+    .clientDescription =  {.applicationUri = {0, NULL}, .productUri = {0, NULL},
+                           .applicationName = {.locale = {0, NULL}, .text = {0, NULL}},
                            .applicationType = UA_APPLICATIONTYPE_CLIENT,
                            .applicationType = UA_APPLICATIONTYPE_CLIENT,
-                           .gatewayServerUri = {-1, NULL}, .discoveryProfileUri = {-1, NULL},
-                           .discoveryUrlsSize = -1, .discoveryUrls = NULL},
+                           .gatewayServerUri = {0, NULL}, .discoveryProfileUri = {0, NULL},
+                           .discoveryUrlsSize = 0, .discoveryUrls = NULL},
     .sessionName = {sizeof("Anonymous Session")-1, (UA_Byte*)"Anonymous Session"},
     .sessionName = {sizeof("Anonymous Session")-1, (UA_Byte*)"Anonymous Session"},
     .authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
     .authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
                             .identifier.numeric = 0}, 
                             .identifier.numeric = 0}, 
@@ -17,11 +17,11 @@ UA_Session anonymousSession = {
     .continuationPoints = {NULL}};
     .continuationPoints = {NULL}};
 
 
 UA_Session adminSession = {
 UA_Session adminSession = {
-    .clientDescription =  {.applicationUri = {-1, NULL}, .productUri = {-1, NULL},
-                           .applicationName = {.locale = {-1, NULL}, .text = {-1, NULL}},
+    .clientDescription =  {.applicationUri = {0, NULL}, .productUri = {0, NULL},
+                           .applicationName = {.locale = {0, NULL}, .text = {0, NULL}},
                            .applicationType = UA_APPLICATIONTYPE_CLIENT,
                            .applicationType = UA_APPLICATIONTYPE_CLIENT,
-                           .gatewayServerUri = {-1, NULL}, .discoveryProfileUri = {-1, NULL},
-                           .discoveryUrlsSize = -1, .discoveryUrls = NULL},
+                           .gatewayServerUri = {0, NULL}, .discoveryProfileUri = {0, NULL},
+                           .discoveryUrlsSize = 0, .discoveryUrls = NULL},
     .sessionName = {sizeof("Administrator Session")-1, (UA_Byte*)"Administrator Session"},
     .sessionName = {sizeof("Administrator Session")-1, (UA_Byte*)"Administrator Session"},
     .authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
     .authenticationToken = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
                             .identifier.numeric = 1},
                             .identifier.numeric = 1},

File diff suppressed because it is too large
+ 338 - 587
src/ua_types.c


File diff suppressed because it is too large
+ 716 - 831
src/ua_types_encoding_binary.c


+ 3 - 75
src/ua_types_encoding_binary.h

@@ -2,83 +2,11 @@
 #define UA_TYPES_ENCODING_BINARY_H_
 #define UA_TYPES_ENCODING_BINARY_H_
 
 
 #include "ua_types.h"
 #include "ua_types.h"
-#include "ua_util.h"
 
 
-/**
- * @ingroup types
- *
- * @defgroup encoding_binary Binary Encoding
- *
- * @brief Functions for binary en- and decoding of built-in datatypes as defined
- * in the standard. The encoding of the remaining datatypes is autogenerated
- * from XML descriptions.
- *
- * All datatypes have similar functions with a common postfix. DO NOT CALL THESE
- * FUNCTIONS WITH NULL-POINTERS IF IT IS NOT EXPLICITLY PERMITTED.
- *
- * - _encode: Encodes a variable into a bytestring. If an error occurs
- *   (indicated by the return value), the bytestring may be left in an
- *   inconsistent state.
- *
- * - _decode: Decodes a variable stored in a bytestring. The destination is
- *   cleaned up (init) before decoding into it. If an error occurs (indicated by
- *   the return value), the destination is cleaned up (deleteMembers, but no
- *   init) before returning.
- *
- * @{
- */
-
-#define UA_TYPE_BINARY_ENCODING(TYPE)                                   \
-    UA_StatusCode TYPE##_encodeBinary(TYPE const *src, UA_ByteString *dst, size_t *UA_RESTRICT offset); \
-    UA_StatusCode TYPE##_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset, TYPE *dst);
-
-UA_TYPE_BINARY_ENCODING(UA_Boolean)
-UA_TYPE_BINARY_ENCODING(UA_Byte)
-#define UA_SByte_encodeBinary(src, dst, offset) UA_Byte_encodeBinary((const UA_Byte *)src, dst, offset)
-#define UA_SByte_decodeBinary(src, offset, dst) UA_Byte_decodeBinary(src, offset, (UA_Byte *)dst)
-UA_TYPE_BINARY_ENCODING(UA_UInt16)
-#define UA_Int16_encodeBinary(src, dst, offset) UA_UInt16_encodeBinary((const UA_UInt16 *)src, dst, offset)
-#define UA_Int16_decodeBinary(src, offset, dst) UA_UInt16_decodeBinary(src, offset, (UA_UInt16 *)dst)
-UA_TYPE_BINARY_ENCODING(UA_UInt32)
-#define UA_Int32_encodeBinary(src, dst, offset) UA_UInt32_encodeBinary((const UA_UInt32 *)src, dst, offset)
-#define UA_Int32_decodeBinary(src, offset, dst) UA_UInt32_decodeBinary(src, offset, (UA_UInt32 *)dst)
-UA_TYPE_BINARY_ENCODING(UA_UInt64)
-#define UA_Int64_encodeBinary(src, dst, offset) UA_UInt64_encodeBinary((const UA_UInt64 *)src, dst, offset)
-#define UA_Int64_decodeBinary(src, offset, dst) UA_UInt64_decodeBinary(src, offset, (UA_UInt64 *)dst)
-#ifdef UA_MIXED_ENDIAN
- UA_TYPE_BINARY_ENCODING(UA_Float)
- UA_TYPE_BINARY_ENCODING(UA_Double)
-#else
- #define UA_Float_encodeBinary(src, dst, offset) UA_UInt32_encodeBinary((const UA_UInt32 *)src, dst, offset)
- #define UA_Float_decodeBinary(src, offset, dst) UA_UInt32_decodeBinary(src, offset, (UA_UInt32 *)dst)
- #define UA_Double_encodeBinary(src, dst, offset) UA_UInt64_encodeBinary((const UA_UInt64 *)src, dst, offset)
- #define UA_Double_decodeBinary(src, offset, dst) UA_UInt64_decodeBinary(src, offset, (UA_UInt64 *)dst)
-#endif
-UA_TYPE_BINARY_ENCODING(UA_String)
-#define UA_DateTime_encodeBinary(src, dst, offset) UA_UInt64_encodeBinary((const UA_UInt64 *)src, dst, offset)
-#define UA_DateTime_decodeBinary(src, offset, dst) UA_UInt64_decodeBinary(src, offset, (UA_UInt64 *)dst)
-UA_TYPE_BINARY_ENCODING(UA_Guid)
-#define UA_ByteString_encodeBinary(src, dst, offset) UA_String_encodeBinary((const UA_String *)src, dst, offset)
-#define UA_ByteString_decodeBinary(src, offset, dst) UA_String_decodeBinary(src, offset, (UA_String *)dst)
-#define UA_XmlElement_encodeBinary(src, dst, offset) UA_String_encodeBinary((const UA_String *)src, dst, offset)
-#define UA_XmlElement_decodeBinary(src, offset, dst) UA_String_decodeBinary(src, offset, (UA_String *)dst)
-UA_TYPE_BINARY_ENCODING(UA_NodeId)
-UA_TYPE_BINARY_ENCODING(UA_ExpandedNodeId)
-#define UA_StatusCode_encodeBinary(src, dst, offset) UA_UInt32_encodeBinary((const UA_UInt32 *)src, dst, offset)
-#define UA_StatusCode_decodeBinary(src, offset, dst) UA_UInt32_decodeBinary(src, offset, (UA_UInt32 *)dst)
-UA_TYPE_BINARY_ENCODING(UA_QualifiedName)
-UA_TYPE_BINARY_ENCODING(UA_LocalizedText)
-UA_TYPE_BINARY_ENCODING(UA_ExtensionObject)
-UA_TYPE_BINARY_ENCODING(UA_DataValue)
-UA_TYPE_BINARY_ENCODING(UA_Variant)
-UA_TYPE_BINARY_ENCODING(UA_DiagnosticInfo)
-
-UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_ByteString *dst,
+UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *type, UA_ByteString *dst,
                               size_t *UA_RESTRICT offset) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
                               size_t *UA_RESTRICT offset) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
-UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t * UA_RESTRICT offset, void *dst,
-                              const UA_DataType *dataType) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
-size_t UA_calcSizeBinary(const void *p, const UA_DataType *dataType) UA_FUNC_ATTR_PURE;
 
 
-/// @}
+UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t * UA_RESTRICT offset, void *dst,
+                              const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
 
 #endif /* UA_TYPES_ENCODING_BINARY_H_ */
 #endif /* UA_TYPES_ENCODING_BINARY_H_ */

+ 18 - 1
src/ua_util.h

@@ -85,7 +85,24 @@
 # include <urcu/wfcqueue.h>
 # include <urcu/wfcqueue.h>
 # include <urcu/uatomic.h>
 # include <urcu/uatomic.h>
 # include <urcu/rculfhash.h>
 # include <urcu/rculfhash.h>
-#include <urcu/lfstack.h>
+# include <urcu/lfstack.h>
+# ifdef NDEBUG
+# define UA_RCU_LOCK() rcu_read_lock()
+# define UA_RCU_UNLOCK() rcu_read_unlock()
+# else
+extern UA_THREAD_LOCAL bool rcu_locked;
+# define UA_RCU_LOCK() do {     \
+        assert(!rcu_locked);    \
+        rcu_locked = UA_TRUE;   \
+        rcu_read_lock(); } while(0)
+# define UA_RCU_UNLOCK() do { \
+        assert(rcu_locked);   \
+        rcu_locked = UA_FALSE;    \
+        rcu_read_lock(); } while(0)
+# endif
+#else
+# define UA_RCU_LOCK()
+# define UA_RCU_UNLOCK()
 #endif
 #endif
 
 
 #endif /* UA_UTIL_H_ */
 #endif /* UA_UTIL_H_ */

+ 148 - 464
tests/check_builtin.c

@@ -15,303 +15,6 @@ enum UA_VARIANT_ENCODINGMASKTYPE_enum {
     UA_VARIANT_ENCODINGMASKTYPE_ARRAY       = (0x01 << 7)      // bit 7
     UA_VARIANT_ENCODINGMASKTYPE_ARRAY       = (0x01 << 7)      // bit 7
 };
 };
 
 
-START_TEST(UA_ExtensionObject_calcSizeShallWorkOnExample) {
-    // given
-    UA_Byte data[3] = { 1, 2, 3 };
-    UA_ExtensionObject extensionObject;
-
-    // empty ExtensionObject, handcoded
-    // when
-    UA_ExtensionObject_init(&extensionObject);
-    extensionObject.typeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-    extensionObject.typeId.identifier.numeric = 0;
-    extensionObject.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED;
-    // then
-    ck_assert_int_eq(UA_calcSizeBinary(&extensionObject, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]), 1 + 1 + 1);
-
-    // ExtensionObject with ByteString-Body
-    // when
-    extensionObject.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-    extensionObject.body.data   = data;
-    extensionObject.body.length = 3;
-    // then
-    ck_assert_int_eq(UA_calcSizeBinary(&extensionObject, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]), 3 + 4 + 3);
-}
-END_TEST
-
-START_TEST(UA_DataValue_calcSizeShallWorkOnExample) {
-    // given
-    UA_DataValue dataValue;
-    UA_DataValue_init(&dataValue);
-    dataValue.status       = 12;
-    dataValue.hasStatus = UA_TRUE;
-    dataValue.sourceTimestamp = 80;
-    dataValue.hasSourceTimestamp = UA_TRUE;
-    dataValue.sourcePicoseconds = 214;
-    dataValue.hasSourcePicoseconds = UA_TRUE;
-    int size = 0;
-    // when
-    size = UA_calcSizeBinary(&dataValue, &UA_TYPES[UA_TYPES_DATAVALUE]);
-    // then
-    // 1 (bitfield) + 4 (status) + 8 (timestamp) + 2 (picoseconds)
-    ck_assert_int_eq(size, 15);
-}
-END_TEST
-
-START_TEST(UA_DiagnosticInfo_calcSizeShallWorkOnExample) {
-    // given
-    UA_DiagnosticInfo diagnosticInfo;
-    UA_DiagnosticInfo_init(&diagnosticInfo);
-    diagnosticInfo.symbolicId    = 30;
-    diagnosticInfo.hasSymbolicId = UA_TRUE;
-    diagnosticInfo.namespaceUri  = 25;
-    diagnosticInfo.hasNamespaceUri = UA_TRUE;
-    diagnosticInfo.localizedText = 22;
-    diagnosticInfo.hasLocalizedText = UA_TRUE;
-    UA_Byte additionalInfoData = 'd';
-    diagnosticInfo.additionalInfo.data = &additionalInfoData; //"OPCUA";
-    diagnosticInfo.additionalInfo.length = 1;
-    diagnosticInfo.hasAdditionalInfo = UA_TRUE;
-    // when & then
-    // 1 (bitfield) + 4 (symbolic id) + 4 (namespaceuri) + 4 (localizedtext) + 5 (additionalinfo)
-    ck_assert_int_eq(UA_calcSizeBinary(&diagnosticInfo, &UA_TYPES[UA_TYPES_DIAGNOSTICINFO]), 18);
-}
-END_TEST
-
-START_TEST(UA_String_calcSizeWithNegativLengthShallReturnEncodingSize) {
-    // given
-    UA_String arg = { -1, NULL };
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_STRING]);
-    // then
-    ck_assert_int_eq(encodingSize, 4);
-}
-END_TEST
-
-START_TEST(UA_String_calcSizeWithNegativLengthAndValidPointerShallReturnEncodingSize) {
-    // given
-    UA_String arg = { -1, (UA_Byte *)"OPC" };
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_STRING]);
-    // then
-    ck_assert_int_eq(encodingSize, 4);
-}
-END_TEST
-
-START_TEST(UA_String_calcSizeWithZeroLengthShallReturnEncodingSize) {
-    // given
-    UA_String arg = { 0, NULL };
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_STRING]);
-    // then
-    ck_assert_int_eq(encodingSize, 4);
-}
-END_TEST
-
-START_TEST(UA_String_calcSizeWithZeroLengthAndValidPointerShallReturnEncodingSize) {
-    // given
-    UA_String arg = { 0, (UA_Byte *)"OPC" };
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_STRING]);
-    // then
-    ck_assert_int_eq(encodingSize, 4);
-}
-END_TEST
-
-START_TEST(UA_String_calcSizeShallReturnEncodingSize) {
-    // given
-    UA_String arg = { 3, (UA_Byte *)"OPC" };
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_STRING]);
-    // then
-    ck_assert_int_eq(encodingSize, 4+3);
-}
-END_TEST
-
-START_TEST(UA_NodeId_calcSizeEncodingTwoByteShallReturnEncodingSize) {
-    // given
-    UA_NodeId arg;
-    arg.identifierType = UA_NODEIDTYPE_NUMERIC;
-    arg.namespaceIndex = 0;
-    arg.identifier.numeric = 1;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_NODEID]);
-    // then
-    ck_assert_int_eq(encodingSize, 2);
-}
-END_TEST
-
-START_TEST(UA_NodeId_calcSizeEncodingFourByteShallReturnEncodingSize) {
-    // given
-    UA_NodeId arg;
-    arg.identifierType = UA_NODEIDTYPE_NUMERIC;
-    arg.namespaceIndex = 1;
-    arg.identifier.numeric = 1;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_NODEID]);
-    // then
-    ck_assert_int_eq(encodingSize, 4);
-}
-END_TEST
-
-START_TEST(UA_NodeId_calcSizeEncodingStringShallReturnEncodingSize) {
-    // given
-    UA_NodeId arg;
-    arg.identifierType = UA_NODEIDTYPE_STRING;
-    arg.identifier.string.length = 3;
-    arg.identifier.string.data   = (UA_Byte *)"PLT";
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_NODEID]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+2+4+3);
-}
-END_TEST
-
-START_TEST(UA_NodeId_calcSizeEncodingStringNegativLengthShallReturnEncodingSize) {
-    // given
-    UA_NodeId arg;
-    arg.identifierType = UA_NODEIDTYPE_STRING;
-    arg.identifier.string.length = -1;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_NODEID]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+2+4+0);
-}
-END_TEST
-
-START_TEST(UA_NodeId_calcSizeEncodingStringZeroLengthShallReturnEncodingSize) {
-    // given
-    UA_NodeId arg;
-    arg.identifierType = UA_NODEIDTYPE_STRING;
-    arg.identifier.string.length = 0;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_NODEID]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+2+4+0);
-}
-END_TEST
-
-START_TEST(UA_ExpandedNodeId_calcSizeEncodingStringAndServerIndexShallReturnEncodingSize) {
-    // given
-    UA_ExpandedNodeId arg;
-    UA_ExpandedNodeId_init(&arg);
-    arg.nodeId.identifierType = UA_NODEIDTYPE_STRING;
-    arg.serverIndex = 1;
-    arg.nodeId.identifier.string.length = 3;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+2+4+3+4);
-}
-END_TEST
-
-START_TEST(UA_ExpandedNodeId_calcSizeEncodingStringAndNamespaceUriShallReturnEncodingSize) {
-    // given
-    UA_ExpandedNodeId arg;
-    UA_ExpandedNodeId_init(&arg);
-    arg.nodeId.identifierType = UA_NODEIDTYPE_STRING;
-    arg.nodeId.identifier.string.length = 3;
-    arg.namespaceUri.length = 7;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+2+4+3+4+7);
-}
-END_TEST
-
-START_TEST(UA_Guid_calcSizeShallReturnEncodingSize) {
-    // given
-    UA_Guid   arg;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_GUID]);
-    // then
-    ck_assert_int_eq(encodingSize, 16);
-}
-END_TEST
-
-START_TEST(UA_LocalizedText_calcSizeTextOnlyShallReturnEncodingSize) {
-    // given
-    UA_LocalizedText arg;
-    UA_LocalizedText_init(&arg);
-    arg.text = (UA_String) {8, (UA_Byte *)"12345678"};
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+4+8);
-    // finally
-    UA_LocalizedText_init(&arg); // do not delete text
-    UA_LocalizedText_deleteMembers(&arg);
-}
-END_TEST
-
-START_TEST(UA_LocalizedText_calcSizeLocaleOnlyShallReturnEncodingSize) {
-    // given
-    UA_LocalizedText arg;
-    UA_LocalizedText_init(&arg);
-    arg.locale = (UA_String) {8, (UA_Byte *)"12345678"};
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+4+8);
-    UA_LocalizedText_init(&arg); // do not delete locale
-    UA_LocalizedText_deleteMembers(&arg);
-}
-END_TEST
-
-START_TEST(UA_LocalizedText_calcSizeTextAndLocaleShallReturnEncodingSize) {
-    // given
-    UA_LocalizedText arg;
-    UA_LocalizedText_init(&arg);
-    arg.locale = (UA_String) {8, (UA_Byte *)"12345678"};
-    arg.text = (UA_String) {8, (UA_Byte *)"12345678"};
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+4+8+4+8);
-    UA_LocalizedText_init(&arg); // do not delete locale and text
-    UA_LocalizedText_deleteMembers(&arg);
-}
-END_TEST
-
-START_TEST(UA_Variant_calcSizeFixedSizeArrayShallReturnEncodingSize) {
-    // given
-    UA_Variant arg;
-    UA_Variant_init(&arg);
-    arg.type = &UA_TYPES[UA_TYPES_INT32];
-#define ARRAY_LEN 8
-    arg.arrayLength = ARRAY_LEN;
-    UA_Int32 *data[ARRAY_LEN];
-    arg.data = (void *)data;
-
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_VARIANT]);
-
-    // then
-    ck_assert_int_eq(encodingSize, 1+4+ARRAY_LEN*4);
-#undef ARRAY_LEN
-}
-END_TEST
-
-START_TEST(UA_Variant_calcSizeVariableSizeArrayShallReturnEncodingSize) {
-    // given
-    UA_Variant arg;
-    UA_Variant_init(&arg);
-    arg.type = &UA_TYPES[UA_TYPES_STRING];
-#define ARRAY_LEN 3
-    arg.arrayLength = ARRAY_LEN;
-    UA_String strings[3];
-    strings[0] = (UA_String) {-1, NULL };
-    strings[1] = (UA_String) {3, (UA_Byte *)"PLT" };
-    strings[2] = (UA_String) {47, NULL };
-    arg.data   = (void *)strings;
-    // when
-    UA_UInt32 encodingSize = UA_calcSizeBinary(&arg, &UA_TYPES[UA_TYPES_VARIANT]);
-    // then
-    ck_assert_int_eq(encodingSize, 1+4+(4+0)+(4+3)+(4+47));
-#undef ARRAY_LEN
-}
-END_TEST
-
 START_TEST(UA_Byte_decodeShallCopyAndAdvancePosition) {
 START_TEST(UA_Byte_decodeShallCopyAndAdvancePosition) {
     // given
     // given
     UA_Byte dst;
     UA_Byte dst;
@@ -610,7 +313,7 @@ START_TEST(UA_String_decodeWithNegativeSizeShallNotAllocateMemoryAndNullPtr) {
     UA_StatusCode retval = UA_String_decodeBinary(&src, &pos, &dst);
     UA_StatusCode retval = UA_String_decodeBinary(&src, &pos, &dst);
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    ck_assert_int_eq(dst.length, -1);
+    ck_assert_int_eq(dst.length, 0);
     ck_assert_ptr_eq(dst.data, NULL);
     ck_assert_ptr_eq(dst.data, NULL);
 }
 }
 END_TEST
 END_TEST
@@ -627,7 +330,7 @@ START_TEST(UA_String_decodeWithZeroSizeShallNotAllocateMemoryAndNullPtr) {
     // then
     // then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(dst.length, 0);
     ck_assert_int_eq(dst.length, 0);
-    ck_assert_ptr_eq(dst.data, NULL);
+    ck_assert_ptr_eq(dst.data, UA_EMPTY_ARRAY_SENTINEL);
 }
 }
 END_TEST
 END_TEST
 
 
@@ -698,7 +401,8 @@ START_TEST(UA_Variant_decodeWithOutArrayFlagSetShallSetVTAndAllocateMemoryForArr
     ck_assert_int_eq(pos, 5);
     ck_assert_int_eq(pos, 5);
     //ck_assert_ptr_eq((const void *)dst.type, (const void *)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     //ck_assert_ptr_eq((const void *)dst.type, (const void *)&UA_TYPES[UA_TYPES_INT32]); //does not compile in gcc 4.6
     ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
     ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_INT32]); 
-    ck_assert_int_eq(dst.arrayLength, -1);
+    ck_assert_int_eq(dst.arrayLength, 0);
+    ck_assert_int_ne((uintptr_t)dst.data, 0);
     ck_assert_int_eq(*(UA_Int32 *)dst.data, 255);
     ck_assert_int_eq(*(UA_Int32 *)dst.data, 255);
     // finally
     // finally
     UA_Variant_deleteMembers(&dst);
     UA_Variant_deleteMembers(&dst);
@@ -729,56 +433,57 @@ START_TEST(UA_Variant_decodeWithArrayFlagSetShallSetVTAndAllocateMemoryForArray)
 END_TEST
 END_TEST
 
 
 START_TEST(UA_Variant_decodeSingleExtensionObjectShallSetVTAndAllocateMemory){
 START_TEST(UA_Variant_decodeSingleExtensionObjectShallSetVTAndAllocateMemory){
-    // given
-    size_t pos = 0;
-    UA_Variant dst;
-    UA_NodeId tmpNodeId;
-    UA_ByteString srcByteString;
-
-    UA_NodeId_init(&tmpNodeId);
-    tmpNodeId.identifier.numeric = 22;
-    tmpNodeId.namespaceIndex = 2;
-    tmpNodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-
-    UA_ExtensionObject tmpExtensionObject;
-    UA_ExtensionObject_init(&tmpExtensionObject);
-    UA_ByteString_newMembers(&tmpExtensionObject.body,3);
-    tmpExtensionObject.body.data[0]= 10;
-    tmpExtensionObject.body.data[1]= 20;
-    tmpExtensionObject.body.data[2]= 30;
-    tmpExtensionObject.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-    tmpExtensionObject.typeId = tmpNodeId;
-
-    UA_Variant tmpVariant;
-    UA_Variant_init(&tmpVariant);
-    tmpVariant.arrayDimensions = NULL;
-    tmpVariant.arrayDimensionsSize = -1;
-    tmpVariant.arrayLength = -1;
-    tmpVariant.storageType = UA_VARIANT_DATA_NODELETE;
-    tmpVariant.type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
-    tmpVariant.data = &tmpExtensionObject;
-
-    UA_ByteString_newMembers(&srcByteString,200);
-    pos = 0;
-    UA_Variant_encodeBinary(&tmpVariant,&srcByteString,&pos);
-
-    // when
-    pos = 0;
-    UA_StatusCode retval = UA_Variant_decodeBinary(&srcByteString, &pos, &dst);
-    // then
-    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
-    ck_assert_int_eq((uintptr_t)dst.type, (uintptr_t)&UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
-    ck_assert_int_eq(dst.arrayLength, -1);
-    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[0], 10);
-    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[1], 20);
-    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[2], 30);
-    ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.length, 3);
-
-
-    // finally
-    UA_Variant_deleteMembers(&dst);
-    UA_ByteString_deleteMembers(&srcByteString);
-    UA_ExtensionObject_deleteMembers(&tmpExtensionObject);
+    /* // given */
+    /* size_t pos = 0; */
+    /* UA_Variant dst; */
+    /* UA_NodeId tmpNodeId; */
+
+    /* UA_NodeId_init(&tmpNodeId); */
+    /* tmpNodeId.identifier.numeric = 22; */
+    /* tmpNodeId.namespaceIndex = 2; */
+    /* tmpNodeId.identifierType = UA_NODEIDTYPE_NUMERIC; */
+
+    /* UA_ExtensionObject tmpExtensionObject; */
+    /* UA_ExtensionObject_init(&tmpExtensionObject); */
+    /* tmpExtensionObject.encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; */
+    /* tmpExtensionObject.content.encoded.body = UA_ByteString_withSize(3); */
+    /* tmpExtensionObject.content.encoded.body.data[0]= 10; */
+    /* tmpExtensionObject.content.encoded.body.data[1]= 20; */
+    /* tmpExtensionObject.content.encoded.body.data[2]= 30; */
+    /* tmpExtensionObject.content.encoded.typeId = tmpNodeId; */
+
+    /* UA_Variant tmpVariant; */
+    /* UA_Variant_init(&tmpVariant); */
+    /* tmpVariant.arrayDimensions = NULL; */
+    /* tmpVariant.arrayDimensionsSize = -1; */
+    /* tmpVariant.arrayLength = -1; */
+    /* tmpVariant.storageType = UA_VARIANT_DATA_NODELETE; */
+    /* tmpVariant.type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]; */
+    /* tmpVariant.data = &tmpExtensionObject; */
+
+    /* UA_ByteString srcByteString = UA_ByteString_withSize(200); */
+    /* pos = 0; */
+    /* UA_Variant_encodeBinary(&tmpVariant,&srcByteString,&pos); */
+
+    /* // when */
+    /* pos = 0; */
+    /* UA_StatusCode retval = UA_Variant_decodeBinary(&srcByteString, &pos, &dst); */
+    /* // then */
+    /* ck_assert_int_eq(retval, UA_STATUSCODE_GOOD); */
+    /* // TODO!! */
+    /* /\* ck_assert_int_eq(dst.encoding, UA_EXTENSIONOBJECT_DECODED); *\/ */
+    /* /\* ck_assert_int_eq((uintptr_t)dst.content.decoded.type, (uintptr_t)&UA_TYPES[UA_TYPES_EXTENSIONOBJECT]); *\/ */
+    /* /\* ck_assert_int_eq(dst.arrayLength, -1); *\/ */
+    /* /\* ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[0], 10); *\/ */
+    /* /\* ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[1], 20); *\/ */
+    /* /\* ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.data[2], 30); *\/ */
+    /* /\* ck_assert_int_eq(((UA_ExtensionObject *)dst.data)->body.length, 3); *\/ */
+
+
+    /* // finally */
+    /* UA_Variant_deleteMembers(&dst); */
+    /* UA_ByteString_deleteMembers(&srcByteString); */
+    /* UA_ExtensionObject_deleteMembers(&tmpExtensionObject); */
 
 
 }
 }
 END_TEST
 END_TEST
@@ -1175,12 +880,12 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithoutVariant) {
     src.serverTimestamp = 80;
     src.serverTimestamp = 80;
     src.hasServerTimestamp = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
 
 
-    UA_Byte data[] = {  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,       0x55,
-            0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,       0x55,
-            0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,       0x55 };
+    UA_Byte data[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                       0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+                       0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
     UA_ByteString dst = { 24, data };
     UA_ByteString dst = { 24, data };
 
 
-    UA_Int32  retval  = 0;
+    UA_Int32 retval = 0;
     size_t pos     = 0;
     size_t pos     = 0;
 
 
     // when
     // when
@@ -1208,8 +913,8 @@ START_TEST(UA_DataValue_encodeShallWorkOnExampleWithVariant) {
     src.hasValue = UA_TRUE;
     src.hasValue = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
     src.hasServerTimestamp = UA_TRUE;
     src.value.type = &UA_TYPES[UA_TYPES_INT32];
     src.value.type = &UA_TYPES[UA_TYPES_INT32];
-    src.value.arrayLength  = -1; // one element (encoded as not an array)
-    UA_Int32  vdata  = 45;
+    src.value.arrayLength  = 0; // one element (encoded as not an array)
+    UA_Int32 vdata = 45;
     src.value.data = (void *)&vdata;
     src.value.data = (void *)&vdata;
 
 
     UA_Byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     UA_Byte data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -1269,7 +974,7 @@ START_TEST(UA_DateTime_toStringShallWorkOnExample) {
     UA_String dst;
     UA_String dst;
 
 
     // when
     // when
-    UA_DateTime_toString(src, &dst);
+    dst = UA_DateTime_toString(src);
     // then
     // then
     ck_assert_int_eq(dst.data[0], '0');
     ck_assert_int_eq(dst.data[0], '0');
     ck_assert_int_eq(dst.data[1], '4');
     ck_assert_int_eq(dst.data[1], '4');
@@ -1282,32 +987,33 @@ END_TEST
 
 
 START_TEST(UA_ExtensionObject_copyShallWorkOnExample) {
 START_TEST(UA_ExtensionObject_copyShallWorkOnExample) {
     // given
     // given
-    UA_Byte data[3] = { 1, 2, 3 };
+    /* UA_Byte data[3] = { 1, 2, 3 }; */
 
 
-    UA_ExtensionObject value, valueCopied;
-    UA_ExtensionObject_init(&value);
-    UA_ExtensionObject_init(&valueCopied);
+    /* UA_ExtensionObject value, valueCopied; */
+    /* UA_ExtensionObject_init(&value); */
+    /* UA_ExtensionObject_init(&valueCopied); */
 
 
-    value.typeId = UA_TYPES[UA_TYPES_BYTE].typeId;
-    value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED;
-    value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-    value.body.data   = data;
-    value.body.length = 3;
+    //Todo!!
+    /* value.typeId = UA_TYPES[UA_TYPES_BYTE].typeId; */
+    /* value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_NOBODYISENCODED; */
+    /* value.encoding    = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING; */
+    /* value.body.data   = data; */
+    /* value.body.length = 3; */
 
 
-    //when
-    UA_ExtensionObject_copy(&value, &valueCopied);
+    /* //when */
+    /* UA_ExtensionObject_copy(&value, &valueCopied); */
 
 
-    for(UA_Int32 i = 0;i < 3;i++)
-        ck_assert_int_eq(valueCopied.body.data[i], value.body.data[i]);
+    /* for(UA_Int32 i = 0;i < 3;i++) */
+    /*     ck_assert_int_eq(valueCopied.body.data[i], value.body.data[i]); */
 
 
-    ck_assert_int_eq(valueCopied.encoding, value.encoding);
-    ck_assert_int_eq(valueCopied.typeId.identifierType, value.typeId.identifierType);
-    ck_assert_int_eq(valueCopied.typeId.identifier.numeric, value.typeId.identifier.numeric);
+    /* ck_assert_int_eq(valueCopied.encoding, value.encoding); */
+    /* ck_assert_int_eq(valueCopied.typeId.identifierType, value.typeId.identifierType); */
+    /* ck_assert_int_eq(valueCopied.typeId.identifier.numeric, value.typeId.identifier.numeric); */
 
 
-    //finally
-    value.body.data = NULL; // we cannot free the static string
-    UA_ExtensionObject_deleteMembers(&value);
-    UA_ExtensionObject_deleteMembers(&valueCopied);
+    /* //finally */
+    /* value.body.data = NULL; // we cannot free the static string */
+    /* UA_ExtensionObject_deleteMembers(&value); */
+    /* UA_ExtensionObject_deleteMembers(&valueCopied); */
 }
 }
 END_TEST
 END_TEST
 
 
@@ -1326,7 +1032,9 @@ START_TEST(UA_Array_copyByteArrayShallWorkOnExample) {
     testString.length  = 5;
     testString.length  = 5;
 
 
     //when
     //when
-    UA_Array_copy((const void *)testString.data, (void **)&dstArray, &UA_TYPES[UA_TYPES_BYTE], 5);
+    UA_StatusCode retval;
+    retval = UA_Array_copy((const void *)testString.data, 5, (void **)&dstArray, &UA_TYPES[UA_TYPES_BYTE]);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     //then
     //then
     for(i = 0;i < size;i++)
     for(i = 0;i < size;i++)
         ck_assert_int_eq(testString.data[i], dstArray[i]);
         ck_assert_int_eq(testString.data[i], dstArray[i]);
@@ -1341,14 +1049,16 @@ END_TEST
 START_TEST(UA_Array_copyUA_StringShallWorkOnExample) {
 START_TEST(UA_Array_copyUA_StringShallWorkOnExample) {
     // given
     // given
     UA_Int32   i, j;
     UA_Int32   i, j;
-    UA_String *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 3);
+    UA_String *srcArray = UA_Array_new(3, &UA_TYPES[UA_TYPES_STRING]);
     UA_String *dstArray;
     UA_String *dstArray;
 
 
     srcArray[0] = UA_STRING_ALLOC("open");
     srcArray[0] = UA_STRING_ALLOC("open");
     srcArray[1] = UA_STRING_ALLOC("62541");
     srcArray[1] = UA_STRING_ALLOC("62541");
     srcArray[2] = UA_STRING_ALLOC("opc ua");
     srcArray[2] = UA_STRING_ALLOC("opc ua");
     //when
     //when
-    UA_Array_copy((const void *)srcArray, (void **)&dstArray, &UA_TYPES[UA_TYPES_STRING], 3);
+    UA_StatusCode retval;
+    retval = UA_Array_copy((const void *)srcArray, 3, (void **)&dstArray, &UA_TYPES[UA_TYPES_STRING]);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     //then
     //then
     for(i = 0;i < 3;i++) {
     for(i = 0;i < 3;i++) {
         for(j = 0;j < 3;j++)
         for(j = 0;j < 3;j++)
@@ -1356,8 +1066,8 @@ START_TEST(UA_Array_copyUA_StringShallWorkOnExample) {
         ck_assert_int_eq(srcArray[i].length, dstArray[i].length);
         ck_assert_int_eq(srcArray[i].length, dstArray[i].length);
     }
     }
     //finally
     //finally
-    UA_Array_delete(srcArray, &UA_TYPES[UA_TYPES_STRING], 3);
-    UA_Array_delete(dstArray, &UA_TYPES[UA_TYPES_STRING], 3);
+    UA_Array_delete(srcArray, 3, &UA_TYPES[UA_TYPES_STRING]);
+    UA_Array_delete(dstArray, 3, &UA_TYPES[UA_TYPES_STRING]);
 }
 }
 END_TEST
 END_TEST
 
 
@@ -1377,7 +1087,7 @@ START_TEST(UA_DiagnosticInfo_copyShallWorkOnExample) {
     UA_DiagnosticInfo_copy(&value, &copiedValue);
     UA_DiagnosticInfo_copy(&value, &copiedValue);
 
 
     //then
     //then
-    for(UA_Int32 i = 0;i < testString.length;i++)
+    for(size_t i = 0;i < testString.length;i++)
         ck_assert_int_eq(copiedValue.additionalInfo.data[i], value.additionalInfo.data[i]);
         ck_assert_int_eq(copiedValue.additionalInfo.data[i], value.additionalInfo.data[i]);
     ck_assert_int_eq(copiedValue.additionalInfo.length, value.additionalInfo.length);
     ck_assert_int_eq(copiedValue.additionalInfo.length, value.additionalInfo.length);
 
 
@@ -1425,15 +1135,15 @@ START_TEST(UA_ApplicationDescription_copyShallWorkOnExample) {
     //then
     //then
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
 
-    for(UA_Int32 i = 0;i < appString.length;i++)
+    for(size_t i = 0; i < appString.length; i++)
         ck_assert_int_eq(copiedValue.applicationUri.data[i], value.applicationUri.data[i]);
         ck_assert_int_eq(copiedValue.applicationUri.data[i], value.applicationUri.data[i]);
     ck_assert_int_eq(copiedValue.applicationUri.length, value.applicationUri.length);
     ck_assert_int_eq(copiedValue.applicationUri.length, value.applicationUri.length);
 
 
-    for(UA_Int32 i = 0;i < discString.length;i++)
+    for(size_t i = 0; i < discString.length; i++)
         ck_assert_int_eq(copiedValue.discoveryProfileUri.data[i], value.discoveryProfileUri.data[i]);
         ck_assert_int_eq(copiedValue.discoveryProfileUri.data[i], value.discoveryProfileUri.data[i]);
     ck_assert_int_eq(copiedValue.discoveryProfileUri.length, value.discoveryProfileUri.length);
     ck_assert_int_eq(copiedValue.discoveryProfileUri.length, value.discoveryProfileUri.length);
 
 
-    for(UA_Int32 i = 0;i < gateWayString.length;i++)
+    for(size_t i = 0; i < gateWayString.length; i++)
         ck_assert_int_eq(copiedValue.gatewayServerUri.data[i], value.gatewayServerUri.data[i]);
         ck_assert_int_eq(copiedValue.gatewayServerUri.data[i], value.gatewayServerUri.data[i]);
     ck_assert_int_eq(copiedValue.gatewayServerUri.length, value.gatewayServerUri.length);
     ck_assert_int_eq(copiedValue.gatewayServerUri.length, value.gatewayServerUri.length);
 
 
@@ -1557,13 +1267,13 @@ END_TEST
 
 
 START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
 START_TEST(UA_Variant_copyShallWorkOn1DArrayExample) {
     // given
     // given
-    UA_String *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 3);
+    UA_String *srcArray = UA_Array_new(3, &UA_TYPES[UA_TYPES_STRING]);
     srcArray[0] = UA_STRING_ALLOC("__open");
     srcArray[0] = UA_STRING_ALLOC("__open");
     srcArray[1] = UA_STRING_ALLOC("_62541");
     srcArray[1] = UA_STRING_ALLOC("_62541");
     srcArray[2] = UA_STRING_ALLOC("opc ua");
     srcArray[2] = UA_STRING_ALLOC("opc ua");
 
 
-    UA_Int32 *dimensions;
-    dimensions = UA_malloc(sizeof(UA_Int32));
+    UA_UInt32 *dimensions;
+    dimensions = UA_malloc(sizeof(UA_UInt32));
     dimensions[0] = 3;
     dimensions[0] = 3;
 
 
     UA_Variant value, copiedValue;
     UA_Variant value, copiedValue;
@@ -1605,7 +1315,7 @@ END_TEST
 
 
 START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
     // given
     // given
-    UA_Int32 *srcArray = UA_Array_new(&UA_TYPES[UA_TYPES_INT32], 6);
+    UA_Int32 *srcArray = UA_Array_new(6, &UA_TYPES[UA_TYPES_INT32]);
     srcArray[0] = 0;
     srcArray[0] = 0;
     srcArray[1] = 1;
     srcArray[1] = 1;
     srcArray[2] = 2;
     srcArray[2] = 2;
@@ -1613,7 +1323,7 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
     srcArray[4] = 4;
     srcArray[4] = 4;
     srcArray[5] = 5;
     srcArray[5] = 5;
 
 
-    UA_Int32 *dimensions = UA_Array_new(&UA_TYPES[UA_TYPES_INT32], 2);
+    UA_UInt32 *dimensions = UA_Array_new(2, &UA_TYPES[UA_TYPES_UINT32]);
     UA_Int32 dim1 = 3;
     UA_Int32 dim1 = 3;
     UA_Int32 dim2 = 2;
     UA_Int32 dim2 = 2;
     dimensions[0] = dim1;
     dimensions[0] = dim1;
@@ -1664,85 +1374,59 @@ START_TEST(UA_Variant_copyShallWorkOn2DArrayExample) {
 END_TEST
 END_TEST
 
 
 START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
 START_TEST(UA_ExtensionObject_encodeDecodeShallWorkOnExtensionObject) {
-    UA_Int32 val = 42;
-    UA_VariableAttributes varAttr;
-    UA_VariableAttributes_init(&varAttr);
-    varAttr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
-    UA_Variant_init(&varAttr.value);
-    varAttr.value.type = &UA_TYPES[UA_TYPES_INT32];
-    varAttr.value.data = &val;
-    varAttr.value.arrayLength = -1;
-    varAttr.userWriteMask = 41;
-    varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DATATYPE;
-    varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
-    varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERWRITEMASK;
-
-    /* wrap it into a extension object attributes */
-    UA_ExtensionObject extensionObject;
-    UA_ExtensionObject_init(&extensionObject);
-    extensionObject.typeId = UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES].typeId;
-    UA_Byte extensionData[50];
-    extensionObject.body = (UA_ByteString){.data = extensionData, .length=50};
-    size_t posEncode = 0;
-    UA_VariableAttributes_encodeBinary(&varAttr, &extensionObject.body, &posEncode);
-    extensionObject.body.length = posEncode;
-    extensionObject.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
-
-    UA_Byte data[50];
-    UA_ByteString dst = {.data = data, .length=50};
-
-    posEncode = 0;
-    UA_ExtensionObject_encodeBinary(&extensionObject, &dst, &posEncode);
-
-    UA_ExtensionObject extensionObjectDecoded;
-    size_t posDecode = 0;
-    UA_ExtensionObject_decodeBinary(&dst, &posDecode, &extensionObjectDecoded);
-
-    ck_assert_int_eq(posEncode, posDecode);
-    ck_assert_int_eq(extensionObjectDecoded.body.length, extensionObject.body.length);
-
-    UA_VariableAttributes varAttrDecoded;
-    UA_VariableAttributes_init(&varAttrDecoded);
-    posDecode = 0;
-    UA_VariableAttributes_decodeBinary(&extensionObjectDecoded.body, &posDecode, &varAttrDecoded);
-    ck_assert_uint_eq(41, varAttrDecoded.userWriteMask);
-    ck_assert_int_eq(-1, varAttrDecoded.value.arrayLength);
-
-    // finally
-    UA_ExtensionObject_deleteMembers(&extensionObjectDecoded);
-    UA_Variant_deleteMembers(&varAttrDecoded.value);
+    /* UA_Int32 val = 42; */
+    /* UA_VariableAttributes varAttr; */
+    /* UA_VariableAttributes_init(&varAttr); */
+    /* varAttr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; */
+    /* UA_Variant_init(&varAttr.value); */
+    /* varAttr.value.type = &UA_TYPES[UA_TYPES_INT32]; */
+    /* varAttr.value.data = &val; */
+    /* varAttr.value.arrayLength = -1; */
+    /* varAttr.userWriteMask = 41; */
+    /* varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DATATYPE; */
+    /* varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE; */
+    /* varAttr.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERWRITEMASK; */
+
+    /* /\* wrap it into a extension object attributes *\/ */
+    /* UA_ExtensionObject extensionObject; */
+    /* UA_ExtensionObject_init(&extensionObject); */
+    /* extensionObject.typeId = UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES].typeId; */
+    /* UA_Byte extensionData[50]; */
+    /* extensionObject.body = (UA_ByteString){.data = extensionData, .length=50}; */
+    /* size_t posEncode = 0; */
+    /* UA_VariableAttributes_encodeBinary(&varAttr, &extensionObject.body, &posEncode); */
+    /* extensionObject.body.length = posEncode; */
+    /* extensionObject.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING; */
+
+    /* UA_Byte data[50]; */
+    /* UA_ByteString dst = {.data = data, .length=50}; */
+
+    /* posEncode = 0; */
+    /* UA_ExtensionObject_encodeBinary(&extensionObject, &dst, &posEncode); */
+
+    /* UA_ExtensionObject extensionObjectDecoded; */
+    /* size_t posDecode = 0; */
+    /* UA_ExtensionObject_decodeBinary(&dst, &posDecode, &extensionObjectDecoded); */
+
+    /* ck_assert_int_eq(posEncode, posDecode); */
+    /* ck_assert_int_eq(extensionObjectDecoded.body.length, extensionObject.body.length); */
+
+    /* UA_VariableAttributes varAttrDecoded; */
+    /* UA_VariableAttributes_init(&varAttrDecoded); */
+    /* posDecode = 0; */
+    /* UA_VariableAttributes_decodeBinary(&extensionObjectDecoded.body, &posDecode, &varAttrDecoded); */
+    /* ck_assert_uint_eq(41, varAttrDecoded.userWriteMask); */
+    /* ck_assert_int_eq(-1, varAttrDecoded.value.arrayLength); */
+
+    /* // finally */
+    /* UA_ExtensionObject_deleteMembers(&extensionObjectDecoded); */
+    /* UA_Variant_deleteMembers(&varAttrDecoded.value); */
 }
 }
 END_TEST
 END_TEST
 
 
 static Suite *testSuite_builtin(void) {
 static Suite *testSuite_builtin(void) {
     Suite *s = suite_create("Built-in Data Types 62541-6 Table 1");
     Suite *s = suite_create("Built-in Data Types 62541-6 Table 1");
 
 
-    TCase *tc_calcSize = tcase_create("calcSize");
-    tcase_add_test(tc_calcSize, UA_ExtensionObject_calcSizeShallWorkOnExample);
-    tcase_add_test(tc_calcSize, UA_DataValue_calcSizeShallWorkOnExample);
-    tcase_add_test(tc_calcSize, UA_DiagnosticInfo_calcSizeShallWorkOnExample);
-    tcase_add_test(tc_calcSize, UA_String_calcSizeShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_String_calcSizeWithNegativLengthShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_String_calcSizeWithNegativLengthAndValidPointerShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_String_calcSizeWithZeroLengthShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_String_calcSizeWithZeroLengthAndValidPointerShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_NodeId_calcSizeEncodingTwoByteShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_NodeId_calcSizeEncodingFourByteShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_NodeId_calcSizeEncodingStringShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_NodeId_calcSizeEncodingStringNegativLengthShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_NodeId_calcSizeEncodingStringZeroLengthShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_ExpandedNodeId_calcSizeEncodingStringAndServerIndexShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_ExpandedNodeId_calcSizeEncodingStringAndNamespaceUriShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_Guid_calcSizeShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_Guid_calcSizeShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_LocalizedText_calcSizeTextOnlyShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_LocalizedText_calcSizeLocaleOnlyShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_LocalizedText_calcSizeTextAndLocaleShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_Variant_calcSizeFixedSizeArrayShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_Variant_calcSizeVariableSizeArrayShallReturnEncodingSize);
-    tcase_add_test(tc_calcSize, UA_Variant_decodeWithOutDeleteMembersShallFailInCheckMem);
-    suite_add_tcase(s, tc_calcSize);
-
     TCase *tc_decode = tcase_create("decode");
     TCase *tc_decode = tcase_create("decode");
     tcase_add_test(tc_decode, UA_Byte_decodeShallCopyAndAdvancePosition);
     tcase_add_test(tc_decode, UA_Byte_decodeShallCopyAndAdvancePosition);
     tcase_add_test(tc_decode, UA_Byte_decodeShallModifyOnlyCurrentPosition);
     tcase_add_test(tc_decode, UA_Byte_decodeShallModifyOnlyCurrentPosition);

+ 13 - 11
tests/check_memory.c

@@ -1,5 +1,4 @@
 #define _XOPEN_SOURCE 500
 #define _XOPEN_SOURCE 500
-#include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 #include "ua_types.h"
 #include "ua_types.h"
@@ -26,7 +25,7 @@ START_TEST(arrayCopyShallMakeADeepCopy) {
 	a1[2] = (UA_String){3, (UA_Byte*)"ccc"};
 	a1[2] = (UA_String){3, (UA_Byte*)"ccc"};
 	// when
 	// when
 	UA_String *a2;
 	UA_String *a2;
-	UA_Int32   retval = UA_Array_copy((const void *)a1, (void **)&a2, &UA_TYPES[UA_TYPES_STRING], 3);
+	UA_Int32 retval = UA_Array_copy((const void *)a1, 3, (void **)&a2, &UA_TYPES[UA_TYPES_STRING]);
 	// then
 	// then
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(a1[0].length, 1);
 	ck_assert_int_eq(a1[0].length, 1);
@@ -42,7 +41,7 @@ START_TEST(arrayCopyShallMakeADeepCopy) {
 	ck_assert_int_eq(a1[1].data[0], a2[1].data[0]);
 	ck_assert_int_eq(a1[1].data[0], a2[1].data[0]);
 	ck_assert_int_eq(a1[2].data[0], a2[2].data[0]);
 	ck_assert_int_eq(a1[2].data[0], a2[2].data[0]);
 	// finally
 	// finally
-	UA_Array_delete((void *)a2, &UA_TYPES[UA_TYPES_STRING], 3);
+	UA_Array_delete((void *)a2, 3, &UA_TYPES[UA_TYPES_STRING]);
 }
 }
 END_TEST
 END_TEST
 
 
@@ -51,8 +50,9 @@ START_TEST(encodeShallYieldDecode) {
 	UA_ByteString msg1, msg2;
 	UA_ByteString msg1, msg2;
 	size_t pos = 0;
 	size_t pos = 0;
 	void *obj1 = UA_new(&UA_TYPES[_i]);
 	void *obj1 = UA_new(&UA_TYPES[_i]);
-	UA_ByteString_newMembers(&msg1, 65000); // fixed buf size
-    UA_StatusCode retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size
+	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+    retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
     msg1.length = pos;
     msg1.length = pos;
 	if(retval != UA_STATUSCODE_GOOD) {
 	if(retval != UA_STATUSCODE_GOOD) {
 		UA_delete(obj1, &UA_TYPES[_i]);
 		UA_delete(obj1, &UA_TYPES[_i]);
@@ -63,8 +63,10 @@ START_TEST(encodeShallYieldDecode) {
 	// when
 	// when
 	void *obj2 = UA_new(&UA_TYPES[_i]);
 	void *obj2 = UA_new(&UA_TYPES[_i]);
 	pos = 0; retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
 	pos = 0; retval = UA_decodeBinary(&msg1, &pos, obj2, &UA_TYPES[_i]);
-	ck_assert_msg(retval == UA_STATUSCODE_GOOD, "messages differ idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric);
-	retval = UA_ByteString_newMembers(&msg2, 65000);
+	ck_assert_msg(retval == UA_STATUSCODE_GOOD, "could not decode idx=%d,nodeid=%i", _i, UA_TYPES[_i].typeId.identifier.numeric);
+	ck_assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize)); // bit identical decoding
+    assert(!memcmp(obj1, obj2, UA_TYPES[_i].memSize));
+	retval = UA_ByteString_allocBuffer(&msg2, 65000);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	pos = 0; retval = UA_encodeBinary(obj2, &UA_TYPES[_i], &msg2, &pos);
 	pos = 0; retval = UA_encodeBinary(obj2, &UA_TYPES[_i], &msg2, &pos);
     msg2.length = pos;
     msg2.length = pos;
@@ -87,8 +89,8 @@ START_TEST(decodeShallFailWithTruncatedBufferButSurvive) {
 	UA_ByteString msg1;
 	UA_ByteString msg1;
 	void *obj1 = UA_new(&UA_TYPES[_i]);
 	void *obj1 = UA_new(&UA_TYPES[_i]);
 	size_t pos = 0;
 	size_t pos = 0;
-	UA_ByteString_newMembers(&msg1, 65000); // fixed buf size
-    UA_StatusCode retval = UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
+    UA_StatusCode retval = UA_ByteString_allocBuffer(&msg1, 65000); // fixed buf size
+    retval |= UA_encodeBinary(obj1, &UA_TYPES[_i], &msg1, &pos);
 	UA_delete(obj1, &UA_TYPES[_i]);
 	UA_delete(obj1, &UA_TYPES[_i]);
     if(retval != UA_STATUSCODE_GOOD) {
     if(retval != UA_STATUSCODE_GOOD) {
         UA_ByteString_deleteMembers(&msg1);
         UA_ByteString_deleteMembers(&msg1);
@@ -117,7 +119,7 @@ START_TEST(decodeScalarBasicTypeFromRandomBufferShallSucceed) {
 	UA_ByteString msg1;
 	UA_ByteString msg1;
 	UA_Int32 retval = UA_STATUSCODE_GOOD;
 	UA_Int32 retval = UA_STATUSCODE_GOOD;
 	UA_Int32 buflen = 256;
 	UA_Int32 buflen = 256;
-	UA_ByteString_newMembers(&msg1, buflen); // fixed size
+	retval = UA_ByteString_allocBuffer(&msg1, buflen); // fixed size
 #ifdef _WIN32
 #ifdef _WIN32
 	srand(42);
 	srand(42);
 #else
 #else
@@ -150,7 +152,7 @@ START_TEST(decodeComplexTypeFromRandomBufferShallSurvive) {
 	UA_ByteString msg1;
 	UA_ByteString msg1;
 	UA_Int32 retval = UA_STATUSCODE_GOOD;
 	UA_Int32 retval = UA_STATUSCODE_GOOD;
 	UA_Int32 buflen = 256;
 	UA_Int32 buflen = 256;
-	UA_ByteString_newMembers(&msg1, buflen); // fixed size
+	retval = UA_ByteString_allocBuffer(&msg1, buflen); // fixed size
 #ifdef _WIN32
 #ifdef _WIN32
 	srand(42);
 	srand(42);
 #else
 #else

+ 6 - 16
tests/check_nodestore.c

@@ -35,11 +35,10 @@ static UA_Node* createNode(UA_Int16 nsid, UA_Int32 id) {
 START_TEST(replaceExistingNode) {
 START_TEST(replaceExistingNode) {
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
-    const UA_Node *inserted;
+    UA_MT_CONST UA_Node *inserted;
 	UA_NodeStore_insert(ns, n1, &inserted);
 	UA_NodeStore_insert(ns, n1, &inserted);
 	UA_Node* n2 = createNode(0,2253);
 	UA_Node* n2 = createNode(0,2253);
     UA_StatusCode retval = UA_NodeStore_replace(ns, inserted, n2, NULL);
     UA_StatusCode retval = UA_NodeStore_replace(ns, inserted, n2, NULL);
-    UA_NodeStore_release(inserted);
     
     
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     
     
@@ -67,15 +66,13 @@ START_TEST(findNodeInUA_NodeStoreWithSingleEntry) {
 #endif
 #endif
 	// given
 	// given
 	UA_NodeStore *ns = UA_NodeStore_new();
 	UA_NodeStore *ns = UA_NodeStore_new();
-    const UA_Node *inserted;
+    UA_MT_CONST UA_Node *inserted;
 	UA_Node* n1 = createNode(0,2253);
 	UA_Node* n1 = createNode(0,2253);
 	UA_NodeStore_insert(ns, n1, &inserted);
 	UA_NodeStore_insert(ns, n1, &inserted);
 	const UA_Node* nr = UA_NodeStore_get(ns,&inserted->nodeId);
 	const UA_Node* nr = UA_NodeStore_get(ns,&inserted->nodeId);
 	// then
 	// then
 	ck_assert_int_eq((uintptr_t)inserted, (uintptr_t)nr);
 	ck_assert_int_eq((uintptr_t)inserted, (uintptr_t)nr);
 	// finally
 	// finally
-	UA_NodeStore_release(inserted);
-	UA_NodeStore_release(nr);
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -118,7 +115,7 @@ START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
 	UA_Node* n2 = createNode(0,2255);
 	UA_Node* n2 = createNode(0,2255);
     UA_NodeStore_insert(ns, n2, NULL);
     UA_NodeStore_insert(ns, n2, NULL);
 	UA_Node* n3 = createNode(0,2257);
 	UA_Node* n3 = createNode(0,2257);
-    const UA_Node *inserted;
+    UA_MT_CONST UA_Node *inserted;
     UA_NodeStore_insert(ns, n3, &inserted);
     UA_NodeStore_insert(ns, n3, &inserted);
 	UA_Node* n4 = createNode(0,2200);
 	UA_Node* n4 = createNode(0,2200);
     UA_NodeStore_insert(ns, n4, NULL);
     UA_NodeStore_insert(ns, n4, NULL);
@@ -132,8 +129,6 @@ START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
 	// then
 	// then
 	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)inserted);
 	ck_assert_int_eq((uintptr_t)nr, (uintptr_t)inserted);
 	// finally
 	// finally
-	UA_NodeStore_release(inserted);
-	UA_NodeStore_release(nr);
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -194,7 +189,6 @@ START_TEST(findNodeInExpandedNamespace) {
 	ck_assert_int_eq(nr->nodeId.identifier.numeric,n2->nodeId.identifier.numeric);
 	ck_assert_int_eq(nr->nodeId.identifier.numeric,n2->nodeId.identifier.numeric);
 	// finally
 	// finally
 	UA_free((void*)n2);
 	UA_free((void*)n2);
-	UA_NodeStore_release(nr);
 	UA_NodeStore_delete(ns);
 	UA_NodeStore_delete(ns);
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -277,14 +271,12 @@ static void *profileGetThread(void *arg) {
 	struct UA_NodeStoreProfileTest *test = (struct UA_NodeStoreProfileTest*) arg;
 	struct UA_NodeStoreProfileTest *test = (struct UA_NodeStoreProfileTest*) arg;
 	UA_NodeId id;
 	UA_NodeId id;
     UA_NodeId_init(&id);
     UA_NodeId_init(&id);
-	const UA_Node *cn;
 	UA_Int32 max_val = test->max_val;
 	UA_Int32 max_val = test->max_val;
 	UA_NodeStore *ns = test->ns;
 	UA_NodeStore *ns = test->ns;
 	for(UA_Int32 x = 0; x<test->rounds; x++) {
 	for(UA_Int32 x = 0; x<test->rounds; x++) {
-		for (UA_Int32 i=test->min_val; i<max_val; i++) {
+		for(UA_Int32 i=test->min_val; i<max_val; i++) {
 			id.identifier.numeric = i;
 			id.identifier.numeric = i;
-			cn = UA_NodeStore_get(ns,&id);
-			UA_NodeStore_release(cn);
+			UA_NodeStore_get(ns,&id);
 		}
 		}
 	}
 	}
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -320,14 +312,12 @@ START_TEST(profileGetDelete) {
 	end = clock();
 	end = clock();
 	printf("Time for %d create/get/delete on %d threads in a namespace: %fs.\n", N, THREADS, (double)(end - begin) / CLOCKS_PER_SEC);
 	printf("Time for %d create/get/delete on %d threads in a namespace: %fs.\n", N, THREADS, (double)(end - begin) / CLOCKS_PER_SEC);
 #else
 #else
-	const UA_Node *cn;
 	UA_NodeId id;
 	UA_NodeId id;
     UA_NodeId_init(&id);
     UA_NodeId_init(&id);
 	for(UA_Int32 x = 0; x<50; x++) {
 	for(UA_Int32 x = 0; x<50; x++) {
 	    for(int i=0; i<N; i++) {
 	    for(int i=0; i<N; i++) {
 	        id.identifier.numeric = i;
 	        id.identifier.numeric = i;
-			cn = UA_NodeStore_get(ns,&id);
-			UA_NodeStore_release(cn);
+            UA_NodeStore_get(ns,&id);
         }
         }
     }
     }
 	end = clock();
 	end = clock();

+ 69 - 72
tests/check_services_attributes.c

@@ -40,7 +40,7 @@ static UA_Server* makeTestSequence(void) {
     UA_VariableAttributes_init(&vattr);
     UA_VariableAttributes_init(&vattr);
     UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
     UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
     UA_Variant_setArray(&vattr.value, &myIntegerArray, 9, &UA_TYPES[UA_TYPES_INT32]);
     UA_Variant_setArray(&vattr.value, &myIntegerArray, 9, &UA_TYPES[UA_TYPES_INT32]);
-    UA_Int32 myIntegerDimensions[2] = {3,3};
+    UA_UInt32 myIntegerDimensions[2] = {3,3};
     vattr.value.arrayDimensions = myIntegerDimensions;
     vattr.value.arrayDimensions = myIntegerDimensions;
     vattr.value.arrayDimensionsSize = 2;
     vattr.value.arrayDimensionsSize = 2;
     vattr.displayName = UA_LOCALIZEDTEXT("locale","myarray");
     vattr.displayName = UA_LOCALIZEDTEXT("locale","myarray");
@@ -72,7 +72,7 @@ static UA_Server* makeTestSequence(void) {
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
     UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                          UA_QUALIFIEDNAME_ALLOC(0, "Viewtest"), view_attr, NULL);
+                          UA_QUALIFIEDNAME(0, "Viewtest"), view_attr, NULL);
 
 
 #ifdef ENABLE_METHODCALLS
 #ifdef ENABLE_METHODCALLS
 	/* MethodNode */
 	/* MethodNode */
@@ -84,7 +84,7 @@ static UA_Server* makeTestSequence(void) {
                             UA_NODEID_NUMERIC(0, 3),
                             UA_NODEID_NUMERIC(0, 3),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                             UA_QUALIFIEDNAME_ALLOC(0, "Methodtest"), ma,
                             UA_QUALIFIEDNAME_ALLOC(0, "Methodtest"), ma,
-                            NULL, NULL, -1, NULL, -1, NULL, NULL);
+                            NULL, NULL, 0, NULL, 0, NULL, NULL);
 #endif
 #endif
 
 
 	return server;
 	return server;
@@ -92,22 +92,20 @@ static UA_Server* makeTestSequence(void) {
 
 
 static UA_VariableNode* makeCompareSequence(void) {
 static UA_VariableNode* makeCompareSequence(void) {
 	UA_VariableNode *node = UA_VariableNode_new();
 	UA_VariableNode *node = UA_VariableNode_new();
-	UA_Variant *myIntegerVariant = UA_Variant_new();
+
 	UA_Int32 myInteger = 42;
 	UA_Int32 myInteger = 42;
-	UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+	UA_Variant_setScalarCopy(&node->value.variant.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+
 	const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
 	const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-	const UA_LocalizedText myIntegerDisplName = UA_LOCALIZEDTEXT("locale", "the answer");
-    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);
-	node->value.variant.value = *myIntegerVariant;
-	UA_NodeId_copy(&myIntegerNodeId,&node->nodeId);
 	UA_QualifiedName_copy(&myIntegerName,&node->browseName);
 	UA_QualifiedName_copy(&myIntegerName,&node->browseName);
+
+	const UA_LocalizedText myIntegerDisplName = UA_LOCALIZEDTEXT("locale", "the answer");
     UA_LocalizedText_copy(&myIntegerDisplName, &node->displayName);
     UA_LocalizedText_copy(&myIntegerDisplName, &node->displayName);
     UA_LocalizedText_copy(&myIntegerDisplName, &node->description);
     UA_LocalizedText_copy(&myIntegerDisplName, &node->description);
-    UA_ExpandedNodeId parentId;
-	UA_ExpandedNodeId_init(&parentId);
-	UA_NodeId_copy(&parentNodeId,&parentId.nodeId);
+
+    const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+	UA_NodeId_copy(&myIntegerNodeId,&node->nodeId);
+
 	return node;
 	return node;
 }
 }
 
 
@@ -122,7 +120,7 @@ START_TEST(ReadSingleAttributeValueWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_int_eq(42, *(UA_Int32* )resp.value.data);
     ck_assert_int_eq(42, *(UA_Int32* )resp.value.data);
     UA_Server_delete(server);
     UA_Server_delete(server);
@@ -140,7 +138,7 @@ START_TEST(ReadSingleAttributeValueRangeWithoutTimestamp) {
     rReq.nodesToReadSize = 1;
     rReq.nodesToReadSize = 1;
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "myarray");
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "myarray");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
-    rReq.nodesToRead[0].indexRange = UA_STRING_ALLOC("2:3,1:2");
+    rReq.nodesToRead[0].indexRange = UA_STRING_ALLOC("1:2,0:1");
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     ck_assert_int_eq(4, resp.value.arrayLength);
     ck_assert_int_eq(4, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
@@ -161,7 +159,7 @@ START_TEST(ReadSingleAttributeNodeIdWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_NODEID;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_NODEID;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_NODEID], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_NODEID], resp.value.type);
     UA_NodeId* respval = (UA_NodeId*) resp.value.data;
     UA_NodeId* respval = (UA_NodeId*) resp.value.data;
     ck_assert_int_eq(1, respval->namespaceIndex);
     ck_assert_int_eq(1, respval->namespaceIndex);
@@ -182,7 +180,7 @@ START_TEST(ReadSingleAttributeNodeClassWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_NODECLASS;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_NODECLASS;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32],resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32],resp.value.type);
     ck_assert_int_eq(*(UA_Int32*)resp.value.data,UA_NODECLASS_VARIABLE);
     ck_assert_int_eq(*(UA_Int32*)resp.value.data,UA_NODECLASS_VARIABLE);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -203,7 +201,7 @@ START_TEST(ReadSingleAttributeBrowseNameWithoutTimestamp) {
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_QualifiedName* respval = (UA_QualifiedName*) resp.value.data;
     UA_QualifiedName* respval = (UA_QualifiedName*) resp.value.data;
     const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_QUALIFIEDNAME], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_QUALIFIEDNAME], resp.value.type);
     ck_assert_int_eq(1, respval->namespaceIndex);
     ck_assert_int_eq(1, respval->namespaceIndex);
     ck_assert(UA_String_equal(&myIntegerName.name, &respval->name));
     ck_assert(UA_String_equal(&myIntegerName.name, &respval->name));
@@ -226,7 +224,7 @@ START_TEST(ReadSingleAttributeDisplayNameWithoutTimestamp) {
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     const UA_LocalizedText comp = UA_LOCALIZEDTEXT("locale", "the answer");
     const UA_LocalizedText comp = UA_LOCALIZEDTEXT("locale", "the answer");
     UA_VariableNode* compNode = makeCompareSequence();
     UA_VariableNode* compNode = makeCompareSequence();
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], resp.value.type);
     ck_assert(UA_String_equal(&comp.text, &respval->text));
     ck_assert(UA_String_equal(&comp.text, &respval->text));
     ck_assert(UA_String_equal(&compNode->displayName.locale, &respval->locale));
     ck_assert(UA_String_equal(&compNode->displayName.locale, &respval->locale));
@@ -249,7 +247,7 @@ START_TEST(ReadSingleAttributeDescriptionWithoutTimestamp) {
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     UA_VariableNode* compNode = makeCompareSequence();
     UA_VariableNode* compNode = makeCompareSequence();
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT], resp.value.type);
     ck_assert(UA_String_equal(&compNode->description.locale, &respval->locale));
     ck_assert(UA_String_equal(&compNode->description.locale, &respval->locale));
     ck_assert(UA_String_equal(&compNode->description.text, &respval->text));
     ck_assert(UA_String_equal(&compNode->description.text, &respval->text));
@@ -271,7 +269,7 @@ START_TEST(ReadSingleAttributeWriteMaskWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_WRITEMASK;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_WRITEMASK;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_UInt32* respval = (UA_UInt32*) resp.value.data;
     UA_UInt32* respval = (UA_UInt32*) resp.value.data;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_UINT32], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_UINT32], resp.value.type);
     ck_assert_int_eq(0,*respval);
     ck_assert_int_eq(0,*respval);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -291,7 +289,7 @@ START_TEST(ReadSingleAttributeUserWriteMaskWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USERWRITEMASK;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USERWRITEMASK;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_UInt32* respval = (UA_UInt32*) resp.value.data;
     UA_UInt32* respval = (UA_UInt32*) resp.value.data;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_UINT32], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_UINT32], resp.value.type);
     ck_assert_int_eq(0,*respval);
     ck_assert_int_eq(0,*respval);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -310,7 +308,7 @@ START_TEST(ReadSingleAttributeIsAbstractWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ISABSTRACT;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ISABSTRACT;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -329,7 +327,7 @@ START_TEST(ReadSingleAttributeSymmetricWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_SYMMETRIC;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_SYMMETRIC;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -350,7 +348,7 @@ START_TEST(ReadSingleAttributeInverseNameWithoutTimestamp) {
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     UA_LocalizedText* respval = (UA_LocalizedText*) resp.value.data;
     const UA_LocalizedText comp = UA_LOCALIZEDTEXT("en_US", "OrganizedBy");
     const UA_LocalizedText comp = UA_LOCALIZEDTEXT("en_US", "OrganizedBy");
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT],resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_LOCALIZEDTEXT],resp.value.type);
     ck_assert(UA_String_equal(&comp.text, &respval->text));
     ck_assert(UA_String_equal(&comp.text, &respval->text));
     ck_assert(UA_String_equal(&comp.locale, &respval->locale));
     ck_assert(UA_String_equal(&comp.locale, &respval->locale));
@@ -370,7 +368,7 @@ START_TEST(ReadSingleAttributeContainsNoLoopsWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_VIEWNODE;
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_VIEWNODE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_CONTAINSNOLOOPS;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_CONTAINSNOLOOPS;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     ck_assert(*(UA_Boolean* )resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -390,7 +388,7 @@ START_TEST(ReadSingleAttributeEventNotifierWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, resp.status);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, resp.status);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE],resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE],resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, 0);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, 0);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -410,7 +408,7 @@ START_TEST(ReadSingleAttributeDataTypeWithoutTimestamp) {
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_DATATYPE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_DATATYPE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     UA_NodeId* respval = (UA_NodeId*) resp.value.data;
     UA_NodeId* respval = (UA_NodeId*) resp.value.data;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_NODEID], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_NODEID], resp.value.type);
     ck_assert_int_eq(respval->namespaceIndex,0);
     ck_assert_int_eq(respval->namespaceIndex,0);
     ck_assert_int_eq(respval->identifier.numeric,UA_NS0ID_INT32);
     ck_assert_int_eq(respval->identifier.numeric,UA_NS0ID_INT32);
@@ -430,7 +428,7 @@ START_TEST(ReadSingleAttributeValueRankWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUERANK;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUERANK;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_int_eq(-2, *(UA_Int32* )resp.value.data);
     ck_assert_int_eq(-2, *(UA_Int32* )resp.value.data);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -449,7 +447,7 @@ START_TEST(ReadSingleAttributeArrayDimensionsWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
     Service_Read_single(server, &adminSession,  UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession,  UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
     ck_assert_ptr_eq((UA_Int32*)resp.value.data,0);
     ck_assert_ptr_eq((UA_Int32*)resp.value.data,0);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
@@ -468,7 +466,7 @@ START_TEST(ReadSingleAttributeAccessLevelWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ACCESSLEVEL;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_ACCESSLEVEL;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE], resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, 0);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, 0);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
@@ -489,10 +487,9 @@ START_TEST(ReadSingleAttributeUserAccessLevelWithoutTimestamp) {
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     const UA_VariableNode* compNode =
     const UA_VariableNode* compNode =
         (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, &rReq.nodesToRead[0].nodeId);
         (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, &rReq.nodesToRead[0].nodeId);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE], resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, compNode->userAccessLevel);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, compNode->userAccessLevel);
-    UA_NodeStore_release((const UA_Node*)compNode);
     UA_Server_delete(server);
     UA_Server_delete(server);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -512,7 +509,7 @@ START_TEST(ReadSingleAttributeMinimumSamplingIntervalWithoutTimestamp) {
     UA_Double* respval = (UA_Double*) resp.value.data;
     UA_Double* respval = (UA_Double*) resp.value.data;
     UA_VariableNode *compNode = makeCompareSequence();
     UA_VariableNode *compNode = makeCompareSequence();
     UA_Double comp = (UA_Double) compNode->minimumSamplingInterval;
     UA_Double comp = (UA_Double) compNode->minimumSamplingInterval;
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_DOUBLE], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_DOUBLE], resp.value.type);
     ck_assert(*respval == comp);
     ck_assert(*respval == comp);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
@@ -532,7 +529,7 @@ START_TEST(ReadSingleAttributeHistorizingWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_HISTORIZING;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_HISTORIZING;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     UA_ReadRequest_deleteMembers(&rReq);
     UA_ReadRequest_deleteMembers(&rReq);
@@ -552,7 +549,7 @@ START_TEST(ReadSingleAttributeExecutableWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_METHODNODE;
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_METHODNODE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_EXECUTABLE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_EXECUTABLE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
@@ -573,7 +570,7 @@ START_TEST(ReadSingleAttributeUserExecutableWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_METHODNODE;
     rReq.nodesToRead[0].nodeId.identifier.numeric = UA_NS0ID_METHODNODE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USEREXECUTABLE;
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USEREXECUTABLE;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    ck_assert_int_eq(-1, resp.value.arrayLength);
+    ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     ck_assert(*(UA_Boolean*)resp.value.data==UA_FALSE);
     UA_DataValue_deleteMembers(&resp);
     UA_DataValue_deleteMembers(&resp);
@@ -588,11 +585,12 @@ START_TEST(WriteSingleAttributeNodeId) {
     UA_Server *server = makeTestSequence();
     UA_Server *server = makeTestSequence();
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
-    UA_NodeId *id = UA_NodeId_new();
+    UA_NodeId id;
+    UA_NodeId_init(&id);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_NODEID;
     wValue.attributeId = UA_ATTRIBUTEID_NODEID;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
-    UA_Variant_setScalar(&wValue.value.value, id, &UA_TYPES[UA_TYPES_NODEID]);
+    UA_Variant_setScalar(&wValue.value.value, &id, &UA_TYPES[UA_TYPES_NODEID]);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     UA_Server_delete(server);
     UA_Server_delete(server);
@@ -603,10 +601,11 @@ START_TEST(WriteSingleAttributeNodeclass) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
-    UA_NodeClass *class = UA_NodeClass_new();
+    UA_NodeClass class;
+    UA_NodeClass_init(&class);
     wValue.attributeId = UA_ATTRIBUTEID_NODECLASS;
     wValue.attributeId = UA_ATTRIBUTEID_NODECLASS;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
-    UA_Variant_setScalar(&wValue.value.value, class, &UA_TYPES[UA_TYPES_NODECLASS]);
+    UA_Variant_setScalar(&wValue.value.value, &class, &UA_TYPES[UA_TYPES_NODECLASS]);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     UA_Server_delete(server);
     UA_Server_delete(server);
@@ -617,7 +616,7 @@ START_TEST(WriteSingleAttributeBrowseName) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_QualifiedName testValue = UA_QUALIFIEDNAME(1, "the.answer");
     UA_QualifiedName testValue = UA_QUALIFIEDNAME(1, "the.answer");
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_BROWSENAME;
     wValue.attributeId = UA_ATTRIBUTEID_BROWSENAME;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -631,7 +630,7 @@ START_TEST(WriteSingleAttributeDisplayName) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_LocalizedText testValue = UA_LOCALIZEDTEXT("en_EN", "the.answer");
     UA_LocalizedText testValue = UA_LOCALIZEDTEXT("en_EN", "the.answer");
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_DISPLAYNAME;
     wValue.attributeId = UA_ATTRIBUTEID_DISPLAYNAME;
@@ -645,7 +644,7 @@ START_TEST(WriteSingleAttributeDescription) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_LocalizedText testValue = UA_LOCALIZEDTEXT("en_EN", "the.answer");
     UA_LocalizedText testValue = UA_LOCALIZEDTEXT("en_EN", "the.answer");
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
@@ -661,7 +660,7 @@ START_TEST(WriteSingleAttributeWriteMask) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue = 0;
     UA_Int32 testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_WRITEMASK;
     wValue.attributeId = UA_ATTRIBUTEID_WRITEMASK;
@@ -676,7 +675,7 @@ START_TEST(WriteSingleAttributeUserWriteMask) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue = 0;
     UA_Int32 testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_UINT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_USERWRITEMASK;
     wValue.attributeId = UA_ATTRIBUTEID_USERWRITEMASK;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -690,7 +689,7 @@ START_TEST(WriteSingleAttributeIsAbstract) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_ISABSTRACT;
     wValue.attributeId = UA_ATTRIBUTEID_ISABSTRACT;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -704,7 +703,7 @@ START_TEST(WriteSingleAttributeSymmetric) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_SYMMETRIC;
     wValue.attributeId = UA_ATTRIBUTEID_SYMMETRIC;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -732,7 +731,7 @@ START_TEST(WriteSingleAttributeContainsNoLoops) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_CONTAINSNOLOOPS;
     wValue.attributeId = UA_ATTRIBUTEID_CONTAINSNOLOOPS;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -746,7 +745,7 @@ START_TEST(WriteSingleAttributeEventNotifier) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Byte testValue = 0;
     UA_Byte testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
     wValue.attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -759,24 +758,20 @@ START_TEST(WriteSingleAttributeValue) {
     UA_Server *server = makeTestSequence();
     UA_Server *server = makeTestSequence();
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
-    UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Int32 myInteger = 20;
     UA_Int32 myInteger = 20;
-    UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Variant_setScalar(&wValue.value.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    wValue.value.hasValue = UA_TRUE;
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_VALUE;
     wValue.attributeId = UA_ATTRIBUTEID_VALUE;
-    wValue.value.hasValue = UA_TRUE;
-    wValue.value.value = *myIntegerVariant;
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
 
 
     UA_DataValue resp;
     UA_DataValue resp;
     UA_DataValue_init(&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(1, "the.answer");
-    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
-    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    UA_ReadValueId id;
+    UA_ReadValueId_init(&id);
+    id.nodeId = UA_NODEID_STRING(1, "the.answer");
+    id.attributeId = UA_ATTRIBUTEID_VALUE;
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &id, &resp);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     ck_assert(wValue.value.hasValue);
     ck_assert(wValue.value.hasValue);
     ck_assert_int_eq(20, *(UA_Int32*)resp.value.data);
     ck_assert_int_eq(20, *(UA_Int32*)resp.value.data);
@@ -788,11 +783,12 @@ START_TEST(WriteSingleAttributeDataType) {
     UA_Server *server = makeTestSequence();
     UA_Server *server = makeTestSequence();
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
-    UA_NodeId *typeId = UA_NodeId_new();
+    UA_NodeId typeId;
+    UA_NodeId_init(&typeId);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_DATATYPE;
     wValue.attributeId = UA_ATTRIBUTEID_DATATYPE;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
-    UA_Variant_setScalar(&wValue.value.value, typeId, &UA_TYPES[UA_TYPES_NODEID]);
+    UA_Variant_setScalar(&wValue.value.value, &typeId, &UA_TYPES[UA_TYPES_NODEID]);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wValue);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     ck_assert_int_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
     UA_Server_delete(server);
     UA_Server_delete(server);
@@ -803,7 +799,7 @@ START_TEST(WriteSingleAttributeValueRank) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue = -1;
     UA_Int32 testValue = -1;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_INT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_VALUERANK;
     wValue.attributeId = UA_ATTRIBUTEID_VALUERANK;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -818,7 +814,7 @@ START_TEST(WriteSingleAttributeArrayDimensions) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Int32 testValue[] = {-1,-1,-1};
     UA_Int32 testValue[] = {-1,-1,-1};
-    UA_Variant_setArrayCopy(&wValue.value.value, &testValue, 3, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Variant_setArray(&wValue.value.value, &testValue, 3, &UA_TYPES[UA_TYPES_INT32]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
     wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -833,7 +829,7 @@ START_TEST(WriteSingleAttributeAccessLevel) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Byte testValue = 0;
     UA_Byte testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_ACCESSLEVEL;
     wValue.attributeId = UA_ATTRIBUTEID_ACCESSLEVEL;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -847,7 +843,7 @@ START_TEST(WriteSingleAttributeUserAccessLevel) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Byte testValue = 0;
     UA_Byte testValue = 0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BYTE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_USERACCESSLEVEL;
     wValue.attributeId = UA_ATTRIBUTEID_USERACCESSLEVEL;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -861,7 +857,7 @@ START_TEST(WriteSingleAttributeMinimumSamplingInterval) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Double testValue = 0.0;
     UA_Double testValue = 0.0;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_DOUBLE]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_DOUBLE]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL;
     wValue.attributeId = UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -875,7 +871,7 @@ START_TEST(WriteSingleAttributeHistorizing) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_HISTORIZING;
     wValue.attributeId = UA_ATTRIBUTEID_HISTORIZING;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -889,7 +885,7 @@ START_TEST(WriteSingleAttributeExecutable) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_EXECUTABLE;
     wValue.attributeId = UA_ATTRIBUTEID_EXECUTABLE;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -903,7 +899,7 @@ START_TEST(WriteSingleAttributeUserExecutable) {
     UA_WriteValue wValue;
     UA_WriteValue wValue;
     UA_WriteValue_init(&wValue);
     UA_WriteValue_init(&wValue);
     UA_Boolean testValue = UA_TRUE;
     UA_Boolean testValue = UA_TRUE;
-    UA_Variant_setScalarCopy(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
+    UA_Variant_setScalar(&wValue.value.value, &testValue, &UA_TYPES[UA_TYPES_BOOLEAN]);
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.nodeId = UA_NODEID_STRING(1, "the.answer");
     wValue.attributeId = UA_ATTRIBUTEID_USEREXECUTABLE;
     wValue.attributeId = UA_ATTRIBUTEID_USEREXECUTABLE;
     wValue.value.hasValue = UA_TRUE;
     wValue.value.hasValue = UA_TRUE;
@@ -924,6 +920,7 @@ START_TEST(numericRange) {
     ck_assert_int_eq(range.dimensions[1].max,3);
     ck_assert_int_eq(range.dimensions[1].max,3);
     ck_assert_int_eq(range.dimensions[2].min,5);
     ck_assert_int_eq(range.dimensions[2].min,5);
     ck_assert_int_eq(range.dimensions[2].max,5);
     ck_assert_int_eq(range.dimensions[2].max,5);
+    UA_free(range.dimensions);
 } END_TEST
 } END_TEST
 
 
 static Suite * testSuite_services_attributes(void) {
 static Suite * testSuite_services_attributes(void) {

+ 55 - 85
tools/generate_datatypes.py

@@ -97,8 +97,7 @@ def parseTypeDescriptions(filename, namespaceid):
             definitions["UA_" + row[0]] = TypeDescription(row[0], row[1], namespaceid)
             definitions["UA_" + row[0]] = TypeDescription(row[0], row[1], namespaceid)
     return definitions
     return definitions
 
 
-class BuiltinType(object):
-    "Generic type without members. Used for builtin types."
+class Type(object):
     def __init__(self, name, description = ""):
     def __init__(self, name, description = ""):
         self.name = name
         self.name = name
         self.description = description
         self.description = description
@@ -114,7 +113,27 @@ class BuiltinType(object):
 
 
     def typedef_c(self):
     def typedef_c(self):
         pass
         pass
+    
+    def functions_c(self, typeTableName):
+        return ('''static UA_INLINE void %s_init(%s *p) { memset(p, 0, sizeof(%s)); }
+static UA_INLINE void %s_delete(%s *p) { UA_delete(p, %s); }
+static UA_INLINE void %s_deleteMembers(%s *p) { ''' + ("UA_deleteMembers(p, &"+typeTableName+"["+typeTableName+"_"+self.name[3:].upper()+"]);" if not self.fixed_size() else "") + ''' }
+static UA_INLINE %s * %s_new(void) { return (%s*) UA_new(%s); }
+static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { ''' + \
+                ("*dst = *src; return UA_STATUSCODE_GOOD;" if self.fixed_size() else "return UA_copy(src, dst, &" + typeTableName+"["+typeTableName+"_"+self.name[3:].upper() + "]);") +" }") % \
+    tuple([self.name, self.name, self.name] +
+          [self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"] +
+          [self.name, self.name] + 
+          [self.name, self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"] +
+          [self.name, self.name, self.name]) 
 
 
+    def encoding_h(self, typeTableName):
+        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_encodeBinary(src, %s, dst, offset); }
+static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_decodeBinary(src, offset, dst, %s); }''' % \
+    tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 2))))
+
+class BuiltinType(Type):
+    "Generic type without members. Used for builtin types."
     def typelayout_c(self, namespace_0, description, outname):
     def typelayout_c(self, namespace_0, description, outname):
         if description == None:
         if description == None:
             typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
             typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}, "
@@ -124,16 +143,16 @@ class BuiltinType(object):
         if self.name in ["UA_String", "UA_ByteString", "UA_XmlElement"]:
         if self.name in ["UA_String", "UA_ByteString", "UA_XmlElement"]:
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(" + self.name + "), " + \
                 ".memSize = sizeof(" + self.name + "), " + \
-                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
                 ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE, .namespaceZero = UA_TRUE, " + \
-                (".memberName = (char*)0, " if typeintrospection else "") + \
-                ".padding = offsetof(UA_String, data) - sizeof(UA_Int32), .isArray = UA_TRUE }}, " + \
+                (".memberName = \"\", " if typeintrospection else "") + \
+                ".padding = 0, .isArray = UA_TRUE }}, " + \
                 ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
                 ".typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
 
 
         if self.name == "UA_ExpandedNodeId":
         if self.name == "UA_ExpandedNodeId":
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(UA_ExpandedNodeId), " + \
                 ".memSize = sizeof(UA_ExpandedNodeId), " + \
-                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".membersSize = 3, .members = {" + \
                 ".membersSize = 3, .members = {" + \
                 "\n\t{.memberTypeIndex = UA_TYPES_NODEID, .namespaceZero = UA_TRUE, " + \
                 "\n\t{.memberTypeIndex = UA_TYPES_NODEID, .namespaceZero = UA_TRUE, " + \
                 (".memberName = \"nodeId\", " if typeintrospection else "") + \
                 (".memberName = \"nodeId\", " if typeintrospection else "") + \
@@ -149,7 +168,7 @@ class BuiltinType(object):
         if self.name == "UA_QualifiedName":
         if self.name == "UA_QualifiedName":
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(UA_QualifiedName), " + \
                 ".memSize = sizeof(UA_QualifiedName), " + \
-                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".membersSize = 2, .members = {" + \
                 ".membersSize = 2, .members = {" + \
                 "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
                 "\n\t{.memberTypeIndex = UA_TYPES_UINT16, .namespaceZero = UA_TRUE, " + \
                 (".memberName = \"namespaceIndex\", " if typeintrospection else "") + \
                 (".memberName = \"namespaceIndex\", " if typeintrospection else "") + \
@@ -162,7 +181,7 @@ class BuiltinType(object):
         if self.name == "UA_LocalizedText":
         if self.name == "UA_LocalizedText":
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                 ".memSize = sizeof(UA_LocalizedText), " + \
                 ".memSize = sizeof(UA_LocalizedText), " + \
-                ".namespaceZero = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
+                ".builtin = UA_TRUE, .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
                 ".membersSize = 2, .members = {" + \
                 ".membersSize = 2, .members = {" + \
                 "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
                 "\n\t{.memberTypeIndex = UA_TYPES_STRING, .namespaceZero = UA_TRUE, " + \
                 (".memberName = \"locale\", " if typeintrospection else "") + \
                 (".memberName = \"locale\", " if typeintrospection else "") + \
@@ -174,12 +193,15 @@ class BuiltinType(object):
 
 
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), " + \
             ".memSize = sizeof(" + self.name + "), " + \
-            ".namespaceZero = UA_TRUE, " + \
-            ".fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
+            ".builtin = UA_TRUE, .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
             ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
             ", .zeroCopyable = " + ("UA_TRUE" if self.zero_copy() else "UA_FALSE") + \
-            ", .membersSize = 0, .typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
+            ", .membersSize = 1, .members = {" + \
+            "\n\t{.memberTypeIndex = UA_TYPES_" + self.name[3:].upper() + " , .namespaceZero = UA_TRUE, " + \
+            (".memberName = \"\", " if typeintrospection else "") + \
+            ".padding = 0, .isArray = UA_FALSE }},\n" + \
+            ".typeIndex = UA_TYPES_" + self.name[3:].upper() + " }"
 
 
-class EnumerationType(object):
+class EnumerationType(Type):
     def __init__(self, name, description = "", elements = OrderedDict()):
     def __init__(self, name, description = "", elements = OrderedDict()):
         self.name = name
         self.name = name
         self.description = description
         self.description = description
@@ -212,29 +234,13 @@ class EnumerationType(object):
         else:
         else:
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-            ".memSize = sizeof(" + self.name + "), " +\
-            ".namespaceZero = UA_TRUE, " + \
+            ".memSize = sizeof(" + self.name + "), .builtin = UA_TRUE, " + \
             ".fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
             ".fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
-            ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32," + \
-            (".memberName = (char*)0, " if typeintrospection else "") + \
+            ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32, " + \
+            (".memberName = \"\", " if typeintrospection else "") + \
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
             ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
 
 
-    def functions_c(self, typeTableName):
-        return '''static UA_INLINE %s * %s_new(void) { %s *v = (%s*)UA_Int32_new(); return v; }
-static UA_INLINE void %s_init(%s *p) { UA_Int32_init((UA_Int32*)p); }
-static UA_INLINE void %s_delete(%s *p) { UA_Int32_delete((UA_Int32*)p); }
-static UA_INLINE void %s_deleteMembers(%s *p) { }
-static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { return UA_Int32_copy((const UA_Int32*)src, (UA_Int32*)dst); }''' % tuple(itertools.repeat(self.name, 13))
-
-    def encoding_h(self, typeTableName):
-        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_Int32_encodeBinary((const UA_Int32*)src, dst, offset); }
-static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_Int32_decodeBinary(src, offset, (UA_Int32*)dst); }''' % tuple(itertools.repeat(self.name, 4))
-
-class OpaqueType(object):
-    def __init__(self, name, description = ""):
-        self.name = name
-        self.description = description
-
+class OpaqueType(Type):
     def fixed_size(self):
     def fixed_size(self):
         return False
         return False
 
 
@@ -251,20 +257,9 @@ class OpaqueType(object):
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
             ".memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
             ".memSize = sizeof(" + self.name + "), .fixedSize = UA_FALSE, .zeroCopyable = UA_FALSE, " + \
-            ".namespaceZero = UA_TRUE, .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTESTRING," + \
-            (".memberName = (char*)0, " if typeintrospection else "") + \
-            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_BYTESTRING }"
-
-    def functions_c(self, typeTableName):
-        return '''static UA_INLINE %s * %s_new(void) { %s *v = (%s*)UA_ByteString_new(); return v; }
-static UA_INLINE void %s_init(%s *p) { UA_ByteString_init((UA_ByteString*)p); }
-static UA_INLINE void %s_delete(%s *p) { UA_ByteString_delete((UA_ByteString*)p); }
-static UA_INLINE void %s_deleteMembers(%s *p) { }
-static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { return UA_ByteString_copy((const UA_ByteString*)src, (UA_ByteString*)dst); }''' % tuple(itertools.repeat(self.name, 13))
-
-    def encoding_h(self, typeTableName):
-        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_ByteString_encodeBinary((UA_ByteString*)src, dst, offset); }
-static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_ByteString_decodeBinary(src, offset, (UA_ByteString*)dst); }''' % tuple(itertools.repeat(self.name, 4))
+            ".builtin = UA_FALSE, .membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_BYTE," + \
+            (".memberName = \"\", " if typeintrospection else "") + \
+            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_TRUE }}, .typeIndex = %s}" % (outname.upper() + "_" + self.name[3:].upper())
 
 
 class StructMember(object):
 class StructMember(object):
     def __init__(self, name, memberType, isArray):
     def __init__(self, name, memberType, isArray):
@@ -272,7 +267,7 @@ class StructMember(object):
         self.memberType = memberType
         self.memberType = memberType
         self.isArray = isArray
         self.isArray = isArray
 
 
-class StructType(object):
+class StructType(Type):
     def __init__(self, name, description, members = OrderedDict()):
     def __init__(self, name, description, members = OrderedDict()):
         self.name = name
         self.name = name
         self.description = description
         self.description = description
@@ -309,7 +304,7 @@ class StructType(object):
             values = self.members.items()
             values = self.members.items()
         for name, member in values:
         for name, member in values:
             if member.isArray:
             if member.isArray:
-                returnstr += "    UA_Int32 " + name + "Size;\n"
+                returnstr += "    size_t " + name + "Size;\n"
                 returnstr += "    " + member.memberType.name + " *" +name + ";\n"
                 returnstr += "    " + member.memberType.name + " *" +name + ";\n"
             else:
             else:
                 returnstr += "    " + member.memberType.name + " " +name + ";\n"
                 returnstr += "    " + member.memberType.name + " " +name + ";\n"
@@ -322,7 +317,7 @@ class StructType(object):
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
         layout = (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
         layout = (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
                  ".memSize = sizeof(" + self.name + "), "+ \
                  ".memSize = sizeof(" + self.name + "), "+ \
-                 ".namespaceZero = " + ("UA_TRUE" if namespace_0 else "UA_FALSE") + \
+                 ".builtin = UA_FALSE" + \
                  ", .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
                  ", .fixedSize = " + ("UA_TRUE" if self.fixed_size() else "UA_FALSE") + \
                  ", .zeroCopyable = " + ("sizeof(" + self.name + ") == " + str(self.mem_size()) if self.zero_copy() \
                  ", .zeroCopyable = " + ("sizeof(" + self.name + ") == " + str(self.mem_size()) if self.zero_copy() \
                                          else "UA_FALSE") + \
                                          else "UA_FALSE") + \
@@ -339,8 +334,11 @@ class StructType(object):
                           ("UA_TRUE, " if args.namespace_id == 0 or member.memberType.name in existing_types else "UA_FALSE, ") + \
                           ("UA_TRUE, " if args.namespace_id == 0 or member.memberType.name in existing_types else "UA_FALSE, ") + \
                           ".padding = "
                           ".padding = "
 
 
+                if not member.isArray:
+                    thispos = "offsetof(%s, %s)" % (self.name, member.name)
+                else:
+                    thispos = "offsetof(%s, %sSize)" % (self.name, member.name)
                 before_endpos = "0"
                 before_endpos = "0"
-                thispos = "offsetof(%s, %s)" % (self.name, member.name)
                 if index > 0:
                 if index > 0:
                     if sys.version_info[0] < 3:
                     if sys.version_info[0] < 3:
                         before = self.members.values()[index-1]
                         before = self.members.values()[index-1]
@@ -351,33 +349,12 @@ class StructType(object):
                         before_endpos += " + sizeof(void*))"
                         before_endpos += " + sizeof(void*))"
                     else:
                     else:
                         before_endpos += " + sizeof(%s))" % before.memberType.name
                         before_endpos += " + sizeof(%s))" % before.memberType.name
-            
-                if member.isArray:
-                    # the first two bytes are padding for the length index, the last three for the pointer
-                    length_pos = "offsetof(%s, %sSize)" % (self.name, member.name)
-                    if index != 0:
-                        layout += "((%s - %s) << 3) + " % (length_pos, before_endpos)
-                    layout += "(%s - sizeof(UA_Int32) - %s)" % (thispos, length_pos)
-                else:
-                    layout += "%s - %s" % (thispos, before_endpos)
+                layout += "%s - %s" % (thispos, before_endpos)
+
                 layout += ", .isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
                 layout += ", .isArray = " + ("UA_TRUE" if member.isArray else "UA_FALSE") + " }, "
             layout += "}"
             layout += "}"
         return layout + "}"
         return layout + "}"
 
 
-    def functions_c(self, typeTableName):
-        return '''static UA_INLINE void %s_init(%s *p) { UA_init(p, %s); }
-static UA_INLINE void %s_delete(%s *p) { UA_delete(p, %s); }
-static UA_INLINE void %s_deleteMembers(%s *p) { UA_deleteMembers(p, %s); }
-static UA_INLINE %s * %s_new(void) { return (%s *) UA_new(%s); }
-static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { return UA_copy(src, dst, %s); }''' % \
-    tuple(  list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 3)))
-          + list(itertools.chain(*itertools.repeat([self.name, self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 2))) )
-
-    def encoding_h(self, typeTableName):
-        return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_encodeBinary(src, %s, dst, offset); }
-static UA_INLINE UA_StatusCode %s_decodeBinary(const UA_ByteString *src, size_t *offset, %s *dst) { return UA_decodeBinary(src, offset, dst, %s); }''' % \
-    tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 2))))
-
 def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
 def parseTypeDefinitions(xmlDescription, existing_types = OrderedDict()):
     '''Returns an ordered dict that maps names to types. The order is such that
     '''Returns an ordered dict that maps names to types. The order is such that
        every type depends only on known types. '''
        every type depends only on known types. '''
@@ -572,14 +549,13 @@ else:
     values = types.values()
     values = types.values()
 
 
 for t in values:
 for t in values:
+    printh("")
     if type(t) != BuiltinType:
     if type(t) != BuiltinType:
-        printh("")
         if t.description != "":
         if t.description != "":
             printh("/** @brief " + t.description + " */")
             printh("/** @brief " + t.description + " */")
         printh(t.typedef_c())
         printh(t.typedef_c())
     printh("#define " + outname.upper() + "_" + t.name[3:].upper() + " " + str(i))
     printh("#define " + outname.upper() + "_" + t.name[3:].upper() + " " + str(i))
-    if type(t) != BuiltinType:
-        printh(t.functions_c(outname.upper()))
+    printh(t.functions_c(outname.upper()))
     i += 1
     i += 1
 
 
 printh('''
 printh('''
@@ -624,16 +600,10 @@ for t in values:
     else:
     else:
         td = None
         td = None
     printc(t.typelayout_c(args.namespace_id == 0, td, outname) + ",")
     printc(t.typelayout_c(args.namespace_id == 0, td, outname) + ",")
-    if not type(t) == BuiltinType:
-        printe("")
-        printe("/* " + t.name + " */")
-        printe(t.encoding_h(outname.upper()))
+    printe("")
+    printe("/* " + t.name + " */")
+    printe(t.encoding_h(outname.upper()))
 printc("};\n")
 printc("};\n")
-# if args.typedescriptions:
-#     printc('const UA_UInt32 *' + outname.upper() + '_IDS = (UA_UInt32[]){')
-#     for t in types.itervalues():
-#         print(str(typedescriptions[t.name].nodeid) + ", ", end='', file=fc)
-#     printc("};")
 
 
 fh.close()
 fh.close()
 fe.close()
 fe.close()