Browse Source

Merge branch 'master' into external_datasource

his merge is necessary,
Julius Pfrommer 10 years ago
parent
commit
dfbf009d3a

+ 31 - 29
examples/networklayer_tcp.c

@@ -62,6 +62,37 @@ NetworklayerTCP *NetworklayerTCP_new(UA_ConnectionConfig localConf, UA_UInt32 po
 	return newlayer;
 	return newlayer;
 }
 }
 
 
+void NetworklayerTCP_delete(NetworklayerTCP *layer) {
+	for(UA_UInt32 index = 0;index < layer->connectionsSize;index++) {
+		shutdown(layer->connections[index].sockfd, 2);
+        if(layer->connections[index].connection.channel)
+            layer->connections[index].connection.channel->connection = NULL;
+        UA_Connection_deleteMembers(&layer->connections[index].connection);
+		CLOSESOCKET(layer->connections[index].sockfd);
+	}
+	free(layer->connections);
+	free(layer);
+}
+
+void closeCallback(TCPConnectionHandle *handle);
+void writeCallback(TCPConnectionHandle *handle, UA_ByteStringArray gather_buf);
+
+static UA_StatusCode NetworklayerTCP_add(NetworklayerTCP *layer, UA_Int32 newsockfd) {
+    layer->connectionsSize++;
+	layer->connections = realloc(layer->connections, sizeof(TCPConnection) * layer->connectionsSize);
+	TCPConnection *newconnection = &layer->connections[layer->connectionsSize-1];
+	newconnection->sockfd = newsockfd;
+
+	struct TCPConnectionHandle *callbackhandle;
+    if(!(callbackhandle = malloc(sizeof(struct TCPConnectionHandle))))
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    callbackhandle->layer = layer;
+	callbackhandle->sockfd = newsockfd;
+	UA_Connection_init(&newconnection->connection, layer->localConf, callbackhandle,
+					   (UA_Connection_closeCallback)closeCallback, (UA_Connection_writeCallback)writeCallback);
+	return UA_STATUSCODE_GOOD;
+}
+
 // copy the array of connections, but _loose_ one. This does not close the
 // copy the array of connections, but _loose_ one. This does not close the
 // actual socket.
 // actual socket.
 static UA_StatusCode NetworklayerTCP_remove(NetworklayerTCP *layer, UA_Int32 sockfd) {
 static UA_StatusCode NetworklayerTCP_remove(NetworklayerTCP *layer, UA_Int32 sockfd) {
@@ -90,18 +121,6 @@ static UA_StatusCode NetworklayerTCP_remove(NetworklayerTCP *layer, UA_Int32 soc
 	return UA_STATUSCODE_GOOD;
 	return UA_STATUSCODE_GOOD;
 }
 }
 
 
-void NetworklayerTCP_delete(NetworklayerTCP *layer) {
-	for(UA_UInt32 index = 0;index < layer->connectionsSize;index++) {
-		shutdown(layer->connections[index].sockfd, 2);
-        if(layer->connections[index].connection.channel)
-            layer->connections[index].connection.channel->connection = NULL;
-        UA_Connection_deleteMembers(&layer->connections[index].connection);
-		CLOSESOCKET(layer->connections[index].sockfd);
-	}
-	free(layer->connections);
-	free(layer);
-}
-
 /** Callback function */
 /** Callback function */
 void closeCallback(TCPConnectionHandle *handle) {
 void closeCallback(TCPConnectionHandle *handle) {
 	shutdown(handle->sockfd,2);
 	shutdown(handle->sockfd,2);
@@ -161,23 +180,6 @@ void writeCallback(TCPConnectionHandle *handle, UA_ByteStringArray gather_buf) {
         free(gather_buf.strings[i].data);
         free(gather_buf.strings[i].data);
 }
 }
 
 
-static UA_StatusCode NetworklayerTCP_add(NetworklayerTCP *layer, UA_Int32 newsockfd) {
-    layer->connectionsSize++;
-	layer->connections = realloc(layer->connections, sizeof(TCPConnection) * layer->connectionsSize);
-	TCPConnection *newconnection = &layer->connections[layer->connectionsSize-1];
-	newconnection->sockfd = newsockfd;
-
-	struct TCPConnectionHandle *callbackhandle;
-    callbackhandle = malloc(sizeof(struct TCPConnectionHandle));
-    if(!callbackhandle)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    callbackhandle->layer = layer;
-	callbackhandle->sockfd = newsockfd;
-	UA_Connection_init(&newconnection->connection, layer->localConf, callbackhandle,
-					   (UA_Connection_closeCallback)closeCallback, (UA_Connection_writeCallback)writeCallback);
-	return UA_STATUSCODE_GOOD;
-}
-
 static UA_StatusCode setNonBlocking(int sockid) {
 static UA_StatusCode setNonBlocking(int sockid) {
 #ifdef WIN32
 #ifdef WIN32
 	u_long iMode = 1;
 	u_long iMode = 1;

+ 18 - 16
examples/networklayer_tcp_concurrent.c

@@ -8,8 +8,9 @@
 #include <uv.h>
 #include <uv.h>
 #include <assert.h>
 #include <assert.h>
 #include <malloc.h>
 #include <malloc.h>
-#include "networklayer_tcp.h"
 #include "ua_transport.h"
 #include "ua_transport.h"
+#include "ua_statuscodes.h"
+#include "networklayer_tcp.h"
 
 
 struct NetworklayerTCP {
 struct NetworklayerTCP {
     UA_Server *server;
     UA_Server *server;
@@ -21,13 +22,13 @@ struct NetworklayerTCP {
 	UA_UInt32 connectionsSize;
 	UA_UInt32 connectionsSize;
 };
 };
 
 
-UA_Int32 NetworklayerTCP_new(NetworklayerTCP **newlayer, UA_ConnectionConfig localConf, UA_UInt32 port) {
-    *newlayer = malloc(sizeof(NetworklayerTCP));
-    if(newlayer == UA_NULL)
-        return UA_ERROR;
-	(*newlayer)->localConf = localConf;
-	(*newlayer)->port = port;
-	return UA_SUCCESS;
+NetworklayerTCP * NetworklayerTCP_new(UA_ConnectionConfig localConf, UA_UInt32 port) {
+    NetworklayerTCP *newlayer = malloc(sizeof(NetworklayerTCP));
+    if(newlayer) {
+        newlayer->localConf = localConf;
+        newlayer->port = port;
+    }
+	return newlayer;
 }
 }
 
 
 void NetworklayerTCP_delete(NetworklayerTCP *layer) {
 void NetworklayerTCP_delete(NetworklayerTCP *layer) {
@@ -49,7 +50,7 @@ static void on_close(uv_handle_t * handle) {
     free(handle);
     free(handle);
 }
 }
 
 
-void close(void *handle) {
+static void closeHandle(void *handle) {
     uv_close((uv_handle_t *)handle, on_close);
     uv_close((uv_handle_t *)handle, on_close);
 }
 }
 
 
@@ -73,7 +74,7 @@ static void after_write(uv_write_t * req, int status) {
     free(wr);
     free(wr);
 }
 }
 
 
-static void write(void *handle, const UA_ByteStringArray buf) {
+static void writeHandle(void *handle, const UA_ByteStringArray buf) {
     uv_buf_t *uv_bufs = malloc(buf.stringsSize * sizeof(uv_buf_t));
     uv_buf_t *uv_bufs = malloc(buf.stringsSize * sizeof(uv_buf_t));
     for(UA_UInt32 i=0; i<buf.stringsSize; i++) {
     for(UA_UInt32 i=0; i<buf.stringsSize; i++) {
         uv_bufs[i].len = buf.strings[i].length;
         uv_bufs[i].len = buf.strings[i].length;
@@ -134,7 +135,7 @@ static void on_connection(uv_stream_t *server, int status) {
         return;
         return;
 
 
     UA_Connection *connection = malloc(sizeof(UA_Connection));
     UA_Connection *connection = malloc(sizeof(UA_Connection));
-    UA_Connection_init(connection, layer->localConf, stream, close, write);
+    UA_Connection_init(connection, layer->localConf, stream, closeHandle, writeHandle);
     stream->data = connection;
     stream->data = connection;
 
 
     assert(uv_accept(server, (uv_stream_t*)stream) == 0);
     assert(uv_accept(server, (uv_stream_t*)stream) == 0);
@@ -147,24 +148,25 @@ void check_running(uv_timer_t* handle, int status) {
         uv_stop(layer->uvloop);
         uv_stop(layer->uvloop);
 }
 }
 
 
-UA_Int32 NetworkLayerTCP_run(NetworklayerTCP *layer, UA_Server *server, struct timeval tv, void(*worker)(UA_Server*), UA_Boolean *running) {
+UA_StatusCode NetworkLayerTCP_run(NetworklayerTCP *layer, UA_Server *server, struct timeval tv,
+                                  void(*worker)(UA_Server*), UA_Boolean *running) {
     layer->uvloop = uv_default_loop();
     layer->uvloop = uv_default_loop();
     layer->server = server;
     layer->server = server;
     struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", layer->port);
     struct sockaddr_in addr = uv_ip4_addr("0.0.0.0", layer->port);
     if(uv_tcp_init(layer->uvloop, &layer->uvserver)) {
     if(uv_tcp_init(layer->uvloop, &layer->uvserver)) {
 		printf("Socket creation error\n");
 		printf("Socket creation error\n");
-        return UA_ERROR;
+        return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
     
     
     if(uv_tcp_bind(&layer->uvserver, addr)) {
     if(uv_tcp_bind(&layer->uvserver, addr)) {
         printf("Bind error\n");
         printf("Bind error\n");
-        return UA_ERROR;
+        return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
 
 
 #define MAXBACKLOG 10
 #define MAXBACKLOG 10
     if(uv_listen((uv_stream_t*)&layer->uvserver, MAXBACKLOG, on_connection)) {
     if(uv_listen((uv_stream_t*)&layer->uvserver, MAXBACKLOG, on_connection)) {
         printf("Listen error");
         printf("Listen error");
-        return UA_ERROR;
+        return UA_STATUSCODE_BADINTERNALERROR;
     }
     }
     layer->uvloop->data = (void*)layer; // so we can get the pointer to the server
     layer->uvloop->data = (void*)layer; // so we can get the pointer to the server
     layer->running = running;
     layer->running = running;
@@ -174,5 +176,5 @@ UA_Int32 NetworkLayerTCP_run(NetworklayerTCP *layer, UA_Server *server, struct t
     uv_timer_start(&timer_check_running, check_running, 0, 500);
     uv_timer_start(&timer_check_running, check_running, 0, 500);
     
     
     uv_run(layer->uvloop, UV_RUN_DEFAULT);
     uv_run(layer->uvloop, UV_RUN_DEFAULT);
-    return UA_SUCCESS;
+    return UA_STATUSCODE_GOOD;
 }
 }

+ 4 - 0
include/ua_server.h

@@ -35,6 +35,10 @@ void UA_EXPORT UA_Server_delete(UA_Server *server);
 void UA_EXPORT UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg);
 void UA_EXPORT UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg);
 
 
 /* Services for local use */
 /* Services for local use */
+UA_AddNodesResult UA_EXPORT UA_Server_addNode(UA_Server *server, const UA_Node **node,
+                                              const UA_ExpandedNodeId *parentNodeId,
+                                              const UA_NodeId *referenceTypeId);
+UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item);
 void UA_EXPORT UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
 void UA_EXPORT UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
                                                const UA_VTable_Entry *vt, const UA_ExpandedNodeId *parentNodeId,
                                                const UA_VTable_Entry *vt, const UA_ExpandedNodeId *parentNodeId,
                                                const UA_NodeId *referenceTypeId );
                                                const UA_NodeId *referenceTypeId );

+ 5 - 89
include/ua_types.h

@@ -59,8 +59,6 @@ extern "C" {
  *   the stack, whereas the dynamically sized members is heap-allocated. To
  *   the stack, whereas the dynamically sized members is heap-allocated. To
  *   reuse the variable, the remaining members (not dynamically allocated) need
  *   reuse the variable, the remaining members (not dynamically allocated) need
  *   to be cleaned up with an _init.
  *   to be cleaned up with an _init.
- *
- * @{
  */
  */
 
 
 /** @brief A two-state logical value (true or false). */
 /** @brief A two-state logical value (true or false). */
@@ -344,6 +342,10 @@ UA_TYPE_PROTOTYPES(UA_Variant)
 UA_TYPE_PROTOTYPES(UA_DiagnosticInfo)
 UA_TYPE_PROTOTYPES(UA_DiagnosticInfo)
 UA_TYPE_PROTOTYPES(UA_InvalidType)
 UA_TYPE_PROTOTYPES(UA_InvalidType)
 
 
+/**********************************************/
+/* Custom functions for the builtin datatypes */
+/**********************************************/
+
 /* String */
 /* String */
 #define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
 #define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
 #define UA_STRING_STATIC(VARIABLE, STRING) do { \
 #define UA_STRING_STATIC(VARIABLE, STRING) do { \
@@ -390,20 +392,10 @@ void UA_EXPORT UA_ByteString_printx_hex(char *label, const UA_ByteString *string
 /* NodeId */
 /* NodeId */
 UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
 UA_Boolean UA_EXPORT UA_NodeId_isNull(const UA_NodeId *p);
 UA_Boolean UA_EXPORT UA_NodeId_isNull(const UA_NodeId *p);
-UA_Boolean UA_EXPORT UA_NodeId_isBasicType(UA_NodeId const *id);
-
-#define NS0NODEID(NUMERIC_ID)                                                                        \
-    (UA_NodeId) {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = \
-                     NUMERIC_ID }
 
 
 /* ExpandedNodeId */
 /* ExpandedNodeId */
 UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
 UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
 
 
-#define NS0EXPANDEDNODEID(VARIABLE, NUMERIC_ID) do {   \
-        VARIABLE.nodeId       = NS0NODEID(NUMERIC_ID); \
-        VARIABLE.namespaceUri = UA_STRING_NULL;        \
-        VARIABLE.serverIndex  = 0; } while(0)
-
 /* QualifiedName */
 /* QualifiedName */
 #define UA_QUALIFIEDNAME_STATIC(VARIABLE, STRING) do { \
 #define UA_QUALIFIEDNAME_STATIC(VARIABLE, STRING) do { \
         VARIABLE.namespaceIndex = 0;                   \
         VARIABLE.namespaceIndex = 0;                   \
@@ -429,7 +421,7 @@ UA_StatusCode UA_EXPORT UA_Array_new(void **p, UA_Int32 noElements, const UA_VTa
 void UA_EXPORT UA_Array_init(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt);
 void UA_EXPORT UA_Array_init(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt);
 void UA_EXPORT UA_Array_delete(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt);
 void UA_EXPORT UA_Array_delete(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt);
 
 
-/* @brief The destination array is allocated according to noElements. */
+/* @brief The destination array is allocated with size noElements. */
 UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, UA_Int32 noElements, const UA_VTable_Entry *vt, void **dst);
 UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, UA_Int32 noElements, const UA_VTable_Entry *vt, void **dst);
 #ifdef DEBUG
 #ifdef DEBUG
 void UA_EXPORT UA_Array_print(const void *p, UA_Int32 noElements, const UA_VTable_Entry *vt, FILE *stream);
 void UA_EXPORT UA_Array_print(const void *p, UA_Int32 noElements, const UA_VTable_Entry *vt, FILE *stream);
@@ -468,82 +460,6 @@ struct UA_VTable_Entry {
     UA_Encoding encodings[UA_ENCODING_AMOUNT]; // binary, xml, ... UA_ENCODING_AMOUNT is set by the build script
     UA_Encoding encodings[UA_ENCODING_AMOUNT]; // binary, xml, ... UA_ENCODING_AMOUNT is set by the build script
 };
 };
 
 
-/***********************************/
-/* Macros for type implementations */
-/***********************************/
-
-#define UA_TYPE_DEFAULT(TYPE)            \
-    UA_TYPE_DELETE_DEFAULT(TYPE)         \
-    UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
-    UA_TYPE_INIT_DEFAULT(TYPE)           \
-    UA_TYPE_NEW_DEFAULT(TYPE)            \
-    UA_TYPE_COPY_DEFAULT(TYPE)           \
-    
-#define UA_TYPE_NEW_DEFAULT(TYPE)                             \
-    TYPE * TYPE##_new() {                                     \
-        TYPE *p = UA_alloc(sizeof(TYPE));                     \
-        if(p) TYPE##_init(p);                                 \
-        return p;                                             \
-    }
-
-#define UA_TYPE_INIT_DEFAULT(TYPE) \
-    void TYPE##_init(TYPE * p) {   \
-        *p = (TYPE)0;              \
-    }
-
-#define UA_TYPE_INIT_AS(TYPE, TYPE_AS) \
-    void TYPE##_init(TYPE * p) {       \
-        TYPE_AS##_init((TYPE_AS *)p);  \
-    }
-
-#define UA_TYPE_DELETE_DEFAULT(TYPE) \
-    void TYPE##_delete(TYPE *p) {    \
-        TYPE##_deleteMembers(p);     \
-        UA_free(p);                  \
-    }
-
-#define UA_TYPE_DELETE_AS(TYPE, TYPE_AS) \
-    void TYPE##_delete(TYPE * p) {       \
-        TYPE_AS##_delete((TYPE_AS *)p);  \
-    }
-
-#define UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
-    void TYPE##_deleteMembers(TYPE * p) { return; }
-
-#define UA_TYPE_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
-    void TYPE##_deleteMembers(TYPE * p) { TYPE_AS##_deleteMembers((TYPE_AS *)p); }
-
-/* Use only when the type has no arrays. Otherwise, implement deep copy */
-#define UA_TYPE_COPY_DEFAULT(TYPE)                             \
-    UA_StatusCode TYPE##_copy(TYPE const *src, TYPE *dst) {    \
-        *dst = *src;                                           \
-        return UA_STATUSCODE_GOOD;                             \
-    }
-
-#define UA_TYPE_COPY_AS(TYPE, TYPE_AS)                         \
-    UA_StatusCode TYPE##_copy(TYPE const *src, TYPE *dst) {    \
-        return TYPE_AS##_copy((TYPE_AS *)src, (TYPE_AS *)dst); \
-    }
-
-#ifdef DEBUG //print functions only in debug mode
-#define UA_TYPE_PRINT_AS(TYPE, TYPE_AS)              \
-    void TYPE##_print(TYPE const *p, FILE *stream) { \
-        TYPE_AS##_print((TYPE_AS *)p, stream);       \
-    }
-#else
-#define UA_TYPE_PRINT_AS(TYPE, TYPE_AS)
-#endif
-
-#define UA_TYPE_AS(TYPE, TYPE_AS)           \
-    UA_TYPE_NEW_DEFAULT(TYPE)               \
-    UA_TYPE_INIT_AS(TYPE, TYPE_AS)          \
-    UA_TYPE_DELETE_AS(TYPE, TYPE_AS)        \
-    UA_TYPE_DELETEMEMBERS_AS(TYPE, TYPE_AS) \
-    UA_TYPE_COPY_AS(TYPE, TYPE_AS)          \
-    UA_TYPE_PRINT_AS(TYPE, TYPE_AS)
-
-/// @} /* end of group */
-
 #ifdef __cplusplus
 #ifdef __cplusplus
 } // extern "C"
 } // extern "C"
 #endif
 #endif

+ 228 - 158
src/server/ua_nodestore.c

@@ -2,16 +2,30 @@
 #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;
+    const UA_Node node;
+};
+
 struct UA_NodeStore {
 struct UA_NodeStore {
-    const UA_Node **entries;
-    UA_UInt32       size;
-    UA_UInt32       count;
-    UA_UInt32       sizePrimeIndex;
+    struct nodeEntry **entries;
+    UA_UInt32          size;
+    UA_UInt32          count;
+    UA_UInt32          sizePrimeIndex;
 };
 };
 
 
-typedef UA_UInt32 hash_t;
 /* The size of the hash-map is always a prime number. They are chosen to be
 /* The size of the hash-map is always a prime number. They are chosen to be
    close to the next power of 2. So the size ca. doubles with each prime. */
    close to the next power of 2. So the size ca. doubles with each prime. */
+typedef UA_UInt32 hash_t;
 static hash_t const primes[] = {
 static hash_t const primes[] = {
     7,         13,         31,         61,         127,         251,
     7,         13,         31,         61,         127,         251,
     509,       1021,       2039,       4093,       8191,        16381,
     509,       1021,       2039,       4093,       8191,        16381,
@@ -20,13 +34,8 @@ static hash_t const primes[] = {
     134217689, 268435399,  536870909,  1073741789, 2147483647,  4294967291
     134217689, 268435399,  536870909,  1073741789, 2147483647,  4294967291
 };
 };
 
 
-static INLINE hash_t mod(hash_t h, hash_t size) {
-    return h % size;
-}
-static INLINE hash_t mod2(hash_t h, hash_t size) {
-    return 1 + (h % (size - 2));
-}
-
+static INLINE hash_t mod(hash_t h, hash_t size) { return h % size; }
+static INLINE hash_t mod2(hash_t h, hash_t size) { return 1 + (h % (size - 2)); }
 static INLINE UA_Int16 higher_prime_index(hash_t n) {
 static INLINE UA_Int16 higher_prime_index(hash_t n) {
     UA_UInt16 low  = 0;
     UA_UInt16 low  = 0;
     UA_UInt16 high = sizeof(primes) / sizeof(hash_t);
     UA_UInt16 high = sizeof(primes) / sizeof(hash_t);
@@ -41,10 +50,12 @@ static INLINE UA_Int16 higher_prime_index(hash_t n) {
 }
 }
 
 
 /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
 /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
-static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
+static hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
+    if(data == UA_NULL)
+        return 0;
+
     const int32_t   nblocks = len / 4;
     const int32_t   nblocks = len / 4;
     const uint32_t *blocks;
     const uint32_t *blocks;
-
     static const uint32_t c1 = 0xcc9e2d51;
     static const uint32_t c1 = 0xcc9e2d51;
     static const uint32_t c2 = 0x1b873593;
     static const uint32_t c2 = 0x1b873593;
     static const uint32_t r1 = 15;
     static const uint32_t r1 = 15;
@@ -52,10 +63,6 @@ static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 se
     static const uint32_t m  = 5;
     static const uint32_t m  = 5;
     static const uint32_t n  = 0xe6546b64;
     static const uint32_t n  = 0xe6546b64;
     hash_t hash = seed;
     hash_t hash = seed;
-
-    if(data == UA_NULL)
-        return 0;
-
     blocks = (const uint32_t *)data;
     blocks = (const uint32_t *)data;
     for(int32_t i = 0;i < nblocks;i++) {
     for(int32_t i = 0;i < nblocks;i++) {
         uint32_t k = blocks[i];
         uint32_t k = blocks[i];
@@ -68,14 +75,11 @@ static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 se
 
 
     const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
     const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
     uint32_t       k1   = 0;
     uint32_t       k1   = 0;
-
     switch(len & 3) {
     switch(len & 3) {
     case 3:
     case 3:
         k1 ^= tail[2] << 16;
         k1 ^= tail[2] << 16;
-
     case 2:
     case 2:
         k1 ^= tail[1] << 8;
         k1 ^= tail[1] << 8;
-
     case 1:
     case 1:
         k1   ^= tail[0];
         k1   ^= tail[0];
         k1   *= c1;
         k1   *= c1;
@@ -90,95 +94,42 @@ static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 se
     hash ^= (hash >> 13);
     hash ^= (hash >> 13);
     hash *= 0xc2b2ae35;
     hash *= 0xc2b2ae35;
     hash ^= (hash >> 16);
     hash ^= (hash >> 16);
-
     return hash;
     return hash;
 }
 }
 
 
-static INLINE hash_t hash(const UA_NodeId *n) {
+static hash_t hash(const UA_NodeId *n) {
     switch(n->identifierType) {
     switch(n->identifierType) {
     case UA_NODEIDTYPE_NUMERIC:
     case UA_NODEIDTYPE_NUMERIC:
         /*  Knuth's multiplicative hashing */
         /*  Knuth's multiplicative hashing */
         return (n->identifier.numeric + n->namespaceIndex) * 2654435761;   // mod(2^32) is implicit
         return (n->identifier.numeric + n->namespaceIndex) * 2654435761;   // mod(2^32) is implicit
-
     case UA_NODEIDTYPE_STRING:
     case UA_NODEIDTYPE_STRING:
         return hash_array(n->identifier.string.data, n->identifier.string.length, n->namespaceIndex);
         return hash_array(n->identifier.string.data, n->identifier.string.length, n->namespaceIndex);
-
     case UA_NODEIDTYPE_GUID:
     case UA_NODEIDTYPE_GUID:
         return hash_array((UA_Byte *)&(n->identifier.guid), sizeof(UA_Guid), n->namespaceIndex);
         return hash_array((UA_Byte *)&(n->identifier.guid), sizeof(UA_Guid), n->namespaceIndex);
-
     case UA_NODEIDTYPE_BYTESTRING:
     case UA_NODEIDTYPE_BYTESTRING:
         return hash_array((UA_Byte *)n->identifier.byteString.data, n->identifier.byteString.length, n->namespaceIndex);
         return hash_array((UA_Byte *)n->identifier.byteString.data, n->identifier.byteString.length, n->namespaceIndex);
-
     default:
     default:
         UA_assert(UA_FALSE);
         UA_assert(UA_FALSE);
         return 0;
         return 0;
     }
     }
 }
 }
 
 
-static INLINE void clear_entry(UA_NodeStore *ns, const UA_Node **entry) {
-    const UA_Node *node;
-    if(entry == UA_NULL || *entry == UA_NULL)
-        return;
-
-    node = *entry;
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        UA_ObjectNode_delete((UA_ObjectNode *)node);
-        break;
-
-    case UA_NODECLASS_VARIABLE:
-        UA_VariableNode_delete((UA_VariableNode *)node);
-        break;
-
-    case UA_NODECLASS_METHOD:
-        UA_MethodNode_delete((UA_MethodNode *)node);
-        break;
-
-    case UA_NODECLASS_OBJECTTYPE:
-        UA_ObjectTypeNode_delete((UA_ObjectTypeNode *)node);
-        break;
-
-    case UA_NODECLASS_VARIABLETYPE:
-        UA_VariableTypeNode_delete((UA_VariableTypeNode *)node);
-        break;
-
-    case UA_NODECLASS_REFERENCETYPE:
-        UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode *)node);
-        break;
-
-    case UA_NODECLASS_DATATYPE:
-        UA_DataTypeNode_delete((UA_DataTypeNode *)node);
-        break;
-
-    case UA_NODECLASS_VIEW:
-        UA_ViewNode_delete((UA_ViewNode *)node);
-        break;
-
-    default:
-        UA_assert(UA_FALSE);
-        break;
-    }
-    entry = UA_NULL;
-    ns->count--;
-}
-
-/* Returns UA_STATUSCODE_GOOD if an entry was found. Otherwise, An error code is
-   returned and the "entry" argument points to the first free entry under the
-   NodeId. */
-static INLINE UA_StatusCode find_entry(const UA_NodeStore *ns, const UA_NodeId *nodeid, const UA_Node ***entry) {
-    hash_t          h     = hash(nodeid);
-    UA_UInt32       size  = ns->size;
-    hash_t          index = mod(h, size);
-    const UA_Node **e     = &ns->entries[index];
+/* Returns UA_TRUE if an entry was found under the nodeid. Otherwise, returns
+   false and sets slot to a pointer to the next free slot. */
+static UA_Boolean __containsNodeId(const UA_NodeStore *ns, const UA_NodeId *nodeid, struct nodeEntry ***entry) {
+    hash_t         h     = hash(nodeid);
+    UA_UInt32      size  = ns->size;
+    hash_t         index = mod(h, size);
+    struct nodeEntry **e = &ns->entries[index];
 
 
     if(*e == UA_NULL) {
     if(*e == UA_NULL) {
         *entry = e;
         *entry = e;
-        return UA_STATUSCODE_BADINTERNALERROR;
+        return UA_FALSE;
     }
     }
 
 
-    if(UA_NodeId_equal(&(*e)->nodeId, nodeid)) {
+    if(UA_NodeId_equal(&(*e)->node.nodeId, nodeid)) {
         *entry = e;
         *entry = e;
-        return UA_STATUSCODE_GOOD;
+        return UA_TRUE;
     }
     }
 
 
     hash_t hash2 = mod2(h, size);
     hash_t hash2 = mod2(h, size);
@@ -191,156 +142,275 @@ static INLINE UA_StatusCode find_entry(const UA_NodeStore *ns, const UA_NodeId *
 
 
         if(*e == UA_NULL) {
         if(*e == UA_NULL) {
             *entry = e;
             *entry = e;
-            return UA_STATUSCODE_BADINTERNALERROR;
+            return UA_FALSE;
         }
         }
 
 
-        if(UA_NodeId_equal(&(*e)->nodeId, nodeid)) {
+        if(UA_NodeId_equal(&(*e)->node.nodeId, nodeid)) {
             *entry = e;
             *entry = e;
-            return UA_STATUSCODE_GOOD;
+            return UA_TRUE;
         }
         }
     }
     }
 
 
     /* NOTREACHED */
     /* NOTREACHED */
-    return UA_STATUSCODE_GOOD;
+    return UA_TRUE;
 }
 }
 
 
 /* The following function changes size of memory allocated for the entries and
 /* The following function changes size of memory allocated for the entries and
    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) {
-    const UA_Node **nentries;
-    int32_t nsize;
-    UA_UInt32 nindex;
-
-    const UA_Node **oentries = ns->entries;
-    int32_t osize = ns->size;
-    const UA_Node **olimit   = &oentries[osize];
-    int32_t count = ns->count;
-
+static UA_StatusCode __expand(UA_NodeStore *ns) {
+    UA_Int32 osize = ns->size;
+    UA_Int32 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 <= 32))
         return UA_STATUSCODE_GOOD;
         return UA_STATUSCODE_GOOD;
 
 
-    nindex = higher_prime_index(count * 2);
-    nsize  = primes[nindex];
 
 
-    if(!(nentries = UA_alloc(sizeof(UA_Node *) * nsize)))
+    UA_UInt32 nindex = higher_prime_index(count * 2);
+    UA_Int32 nsize = primes[nindex];
+    struct nodeEntry **nentries;
+    if(!(nentries = UA_alloc(sizeof(struct nodeEntry *) * nsize)))
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
 
-    memset(nentries, 0, nsize * sizeof(UA_Node *));
+    memset(nentries, 0, nsize * sizeof(struct nodeEntry *));
+    struct nodeEntry **oentries = ns->entries;
     ns->entries = nentries;
     ns->entries = nentries;
     ns->size    = nsize;
     ns->size    = nsize;
     ns->sizePrimeIndex = nindex;
     ns->sizePrimeIndex = nindex;
 
 
-    const UA_Node **p = oentries;
-    do {
-        if(*p != UA_NULL) {
-            const UA_Node **e;
-            find_entry(ns, &(*p)->nodeId, &e);  /* We know this returns an empty entry here */
-            *e = *p;
-        }
-        p++;
-    } while(p < olimit);
+    // 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])
+            continue;
+        struct nodeEntry **e;
+        __containsNodeId(ns, &(*oentries[i]).node.nodeId, &e);  /* We know this returns an empty entry here */
+        *e = oentries[i];
+        j++;
+    }
 
 
     UA_free(oentries);
     UA_free(oentries);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
+/* Marks the entry dead and deletes if necessary. */
+static void __deleteEntry(struct nodeEntry *entry) {
+    if(entry->refcount > 0)
+        return;
+    const UA_Node *node = &entry->node;
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        UA_ObjectNode_deleteMembers((UA_ObjectNode *)node);
+        break;
+    case UA_NODECLASS_VARIABLE:
+        UA_VariableNode_deleteMembers((UA_VariableNode *)node);
+        break;
+    case UA_NODECLASS_METHOD:
+        UA_MethodNode_deleteMembers((UA_MethodNode *)node);
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        UA_ObjectTypeNode_deleteMembers((UA_ObjectTypeNode *)node);
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        UA_VariableTypeNode_deleteMembers((UA_VariableTypeNode *)node);
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        UA_ReferenceTypeNode_deleteMembers((UA_ReferenceTypeNode *)node);
+        break;
+    case UA_NODECLASS_DATATYPE:
+        UA_DataTypeNode_deleteMembers((UA_DataTypeNode *)node);
+        break;
+    case UA_NODECLASS_VIEW:
+        UA_ViewNode_deleteMembers((UA_ViewNode *)node);
+        break;
+    default:
+        UA_assert(UA_FALSE);
+        break;
+    }
+    UA_free(entry);
+}
+
+static INLINE struct nodeEntry * __nodeEntryFromNode(const UA_Node *node) {
+    UA_UInt32 nodesize = 0;
+    /* Copy the node into the entry. Then reset the original node. It shall no longer be used. */
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        nodesize = sizeof(UA_ObjectNode);
+        break;
+    case UA_NODECLASS_VARIABLE:
+        nodesize = sizeof(UA_VariableNode);
+        break;
+    case UA_NODECLASS_METHOD:
+        nodesize = sizeof(UA_MethodNode);
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        nodesize = sizeof(UA_ObjectTypeNode);
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        nodesize = sizeof(UA_VariableTypeNode);
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        nodesize = sizeof(UA_ReferenceTypeNode);
+        break;
+    case UA_NODECLASS_DATATYPE:
+        nodesize = sizeof(UA_DataTypeNode);
+        break;
+    case UA_NODECLASS_VIEW:
+        nodesize = sizeof(UA_ViewNode);
+        break;
+    default:
+        UA_assert(UA_FALSE);
+    }
+
+    struct nodeEntry *entry;
+    if(!(entry = UA_alloc(sizeof(struct nodeEntry) - sizeof(UA_Node) + nodesize)))
+        return UA_NULL;
+    memcpy((void *)&entry->node, node, nodesize);
+    UA_free((void*)node);
+    return entry;
+}
+
 /**********************/
 /**********************/
 /* Exported functions */
 /* Exported functions */
 /**********************/
 /**********************/
 
 
-UA_StatusCode UA_NodeStore_new(UA_NodeStore **result) {
+UA_NodeStore * UA_NodeStore_new() {
     UA_NodeStore *ns;
     UA_NodeStore *ns;
-    UA_UInt32     sizePrimeIndex, size;
     if(!(ns = UA_alloc(sizeof(UA_NodeStore))))
     if(!(ns = UA_alloc(sizeof(UA_NodeStore))))
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+        return UA_NULL;
 
 
-    sizePrimeIndex = higher_prime_index(32);
-    size = primes[sizePrimeIndex];
-    if(!(ns->entries = UA_alloc(sizeof(UA_Node *) * size))) {
+    ns->sizePrimeIndex = higher_prime_index(32);
+    ns->size = primes[ns->sizePrimeIndex];
+    ns->count = 0;
+    if(!(ns->entries = UA_alloc(sizeof(struct nodeEntry *) * ns->size))) {
         UA_free(ns);
         UA_free(ns);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+        return UA_NULL;
     }
     }
-
-    /* set entries to zero */
-    memset(ns->entries, 0, size * sizeof(UA_Node *));
-
-    *ns     = (UA_NodeStore) {ns->entries, size, 0, sizePrimeIndex };
-    *result = ns;
-    return UA_STATUSCODE_GOOD;
+    memset(ns->entries, 0, ns->size * sizeof(struct nodeEntry *));
+    return ns;
 }
 }
 
 
 void UA_NodeStore_delete(UA_NodeStore *ns) {
 void UA_NodeStore_delete(UA_NodeStore *ns) {
-    UA_UInt32       size    = ns->size;
-    const UA_Node **entries = ns->entries;
-
-    for(UA_UInt32 i = 0;i < size;i++)
-        clear_entry(ns, &entries[i]);
+    UA_UInt32 size = ns->size;
+    struct nodeEntry **entries = ns->entries;
+    for(UA_UInt32 i = 0;i < size;i++) {
+        if(entries[i] != UA_NULL) {
+            entries[i]->refcount &= ~ALIVE_BIT; // mark dead
+            __deleteEntry(entries[i]);
+            entries[i] = UA_NULL;
+            ns->count--;
+        }
+    }
 
 
     UA_free(ns->entries);
     UA_free(ns->entries);
     UA_free(ns);
     UA_free(ns);
 }
 }
 
 
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node **node, UA_Byte flags) {
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged) {
     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;
     }
     }
 
 
-    const UA_Node **entry;
-    UA_Int32 found = find_entry(ns, &(*node)->nodeId, &entry);
-
-    if(flags & UA_NODESTORE_INSERT_UNIQUE) {
-        if(found == UA_STATUSCODE_GOOD)
-            return UA_STATUSCODE_BADNODEIDEXISTS;
-        else
-            *entry = *node;
+    // get a free slot
+    struct nodeEntry **slot;
+    UA_NodeId *nodeId = (UA_NodeId *)&(*node)->nodeId;
+    if(UA_NodeId_isNull(nodeId)) {
+        // find a unique nodeid that is not taken
+        nodeId->identifierType = UA_NODEIDTYPE_NUMERIC;
+        nodeId->namespaceIndex = 1; // namespace 1 is always in the local nodestore
+        UA_Int32 identifier = ns->count+1; // start value
+        UA_Int32 size = ns->size;
+        hash_t increase = mod2(identifier, size);
+        while(UA_TRUE) {
+            nodeId->identifier.numeric = identifier;
+            if(!__containsNodeId(ns, nodeId, &slot))
+                break;
+            identifier += increase;
+            if(identifier >= size)
+                identifier -= size;
+        }
     } else {
     } else {
-        if(found == UA_STATUSCODE_GOOD)
-            clear_entry(ns, entry);
-        *entry = *node;
+        if(__containsNodeId(ns, nodeId, &slot))
+            return UA_STATUSCODE_BADNODEIDEXISTS;
     }
     }
+    
+    struct nodeEntry *entry = __nodeEntryFromNode(*node);
+    if(!entry)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    *slot = entry;
+    ns->count++;
 
 
-    if(!(flags & UA_NODESTORE_INSERT_GETMANAGED))
+    if(getManaged) {
+        entry->refcount = ALIVE_BIT + 1;
+        *node = &entry->node;
+    } else {
+        entry->refcount = ALIVE_BIT;
         *node = UA_NULL;
         *node = UA_NULL;
+    }
 
 
-    ns->count++;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_StatusCode UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid, const UA_Node **managedNode) {
-    const UA_Node **entry;
-    if(find_entry(ns, nodeid, &entry) != UA_STATUSCODE_GOOD)
+UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged) {
+    struct nodeEntry **slot;
+    const UA_NodeId *nodeId = &(*node)->nodeId;
+    if(!__containsNodeId(ns, nodeId, &slot))
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
 
-    *managedNode = *entry;
+    struct nodeEntry *entry = __nodeEntryFromNode(*node);
+    if(!entry)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    (*slot)->refcount &= ~ALIVE_BIT; // mark dead
+    __deleteEntry(*slot);
+    *slot = entry;
+
+    if(getManaged) {
+        entry->refcount = ALIVE_BIT + 1;
+        *node = &entry->node;
+    } else {
+        entry->refcount = ALIVE_BIT;
+        *node = UA_NULL;
+    }
     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;
+    if(!__containsNodeId(ns, nodeid, &slot))
+        return UA_NULL;
+    (*slot)->refcount++;
+    return &(*slot)->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) {
-    const UA_Node **entry;
-    if(find_entry(ns, nodeid, &entry) != UA_STATUSCODE_GOOD)
+    struct nodeEntry **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.
     // Check before if deleting the node makes the UA_NodeStore inconsistent.
-    clear_entry(ns, entry);
+    (*slot)->refcount &= ~ALIVE_BIT; // mark dead
+    __deleteEntry(*slot);
+    *slot = UA_NULL;
+    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++) {
-        const UA_Node *node = ns->entries[i];
-        if(node != UA_NULL)
-            visitor(node);
+        if(ns->entries[i] != UA_NULL)
+            visitor(&ns->entries[i]->node);
     }
     }
 }
 }
 
 
 void UA_NodeStore_release(const UA_Node *managed) {
 void UA_NodeStore_release(const UA_Node *managed) {
-    ;
+    struct nodeEntry *entry = (struct nodeEntry *) ((char*)managed - offsetof(struct nodeEntry, node));
+    entry->refcount--;
+    __deleteEntry(entry);    
 }
 }

+ 26 - 18
src/server/ua_nodestore.h

@@ -9,34 +9,43 @@
 
 
    @defgroup nodestore NodeStore
    @defgroup nodestore NodeStore
 
 
-   @brief The nodestore is the central storage for nodes in the UA address
-   space. Internally, the nodestore is realised as hash-map where nodes are
-   stored and retrieved with their nodeid.
-
-   The nodes in the nodestore are immutable. To change the content of a node, it
-   needs to be replaced as a whole. When a node is inserted into the namespace,
-   it gets replaced with a pointer to a managed node. Managed nodes shall never
-   be freed by the user. This is done by the namespace when the node is removed
-   and no readers (in other threads) access the node.
+   @brief The nodestore contains the nodes in the UA address space. Internally,
+   it is based on a hash-map that maps nodes to their nodeid.
+
+   ATTENTION! You need to allocate single nodes on the heap (with _new) before
+   adding them to the nodestore with _insert or _replace. The node is then
+   copied to a new (managed) location in the nodestore and the original memory
+   is freed. The nodes in the nodestore are immutable. To change the content of
+   a node, it needs to be replaced as a whole.
+
+   ATTENTION! Every node you _get from the nodestore needs to be _released when
+   it is no longer needed. Otherwise, we can't know if somebody still uses it
+   (especially in multi-threaded environments).
  */
  */
 
 
 struct UA_NodeStore;
 struct UA_NodeStore;
 typedef struct UA_NodeStore UA_NodeStore;
 typedef struct UA_NodeStore UA_NodeStore;
 
 
 /** @brief Create a new namespace */
 /** @brief Create a new namespace */
-UA_StatusCode UA_NodeStore_new(UA_NodeStore **result);
+UA_NodeStore * UA_NodeStore_new();
 
 
 /** @brief Delete the namespace and all nodes in it */
 /** @brief Delete the namespace and all nodes in it */
 void UA_NodeStore_delete(UA_NodeStore *ns);
 void UA_NodeStore_delete(UA_NodeStore *ns);
 
 
-#define UA_NODESTORE_INSERT_UNIQUE 1
-#define UA_NODESTORE_INSERT_GETMANAGED 2
 /** @brief Insert a new node into the namespace
 /** @brief Insert a new node into the namespace
 
 
-    With the UNIQUE flag, the node is only inserted if the nodeid does not
-    already exist. With the GETMANAGED flag, the node pointer is replaced with
-    the managed pointer. Otherwise, it is set to UA_NULL. */
-UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node **node, UA_Byte flags);
+    With the getManaged flag, the node pointer is replaced with the managed
+    pointer. Otherwise, it is set to UA_NULL.
+
+    If the nodeid is zero, then a fresh numeric nodeid from namespace 1 is
+    assigned. */
+UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged);
+
+/** @brief Replace an existing node in the nodestore
+
+    With the getManaged flag, the node pointer is replaced with the managed
+    pointer. Otherwise, it is set to UA_NULL. */
+UA_StatusCode UA_NodeStore_replace(UA_NodeStore *ns, const UA_Node **node, UA_Boolean getManaged);
 
 
 /** @brief Remove a node from the namespace. Always succeeds, even if the node
 /** @brief Remove a node from the namespace. Always succeeds, even if the node
     was not found. */
     was not found. */
@@ -45,8 +54,7 @@ UA_StatusCode UA_NodeStore_remove(UA_NodeStore *ns, const UA_NodeId *nodeid);
 /** @brief Retrieve a node (read-only) from the namespace. Nodes are immutable.
 /** @brief Retrieve a node (read-only) from the namespace. Nodes are immutable.
     They can only be replaced. After the Node is no longer used, the locked
     They can only be replaced. After the Node is no longer used, the locked
     entry needs to be released. */
     entry needs to be released. */
-UA_StatusCode UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid,
-                               const UA_Node **managedNode);
+const UA_Node * UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid);
 
 
 /** @brief Release a managed node. Do never insert a node that isn't stored in a
 /** @brief Release a managed node. Do never insert a node that isn't stored in a
     namespace. */
     namespace. */

+ 12 - 12
src/server/ua_nodestore_concurrent.c

@@ -6,13 +6,13 @@
 #include <urcu/uatomic.h>
 #include <urcu/uatomic.h>
 #include <urcu/rculfhash.h>
 #include <urcu/rculfhash.h>
 
 
-#define ALIVE_BIT (1 << 15) /* Alive bit in the readcount */
+#define ALIVE_BIT (1 << 15) /* Alive bit in the refcount */
 
 
 typedef struct UA_NodeStore_Entry {
 typedef struct UA_NodeStore_Entry {
     struct cds_lfht_node htn;      /* contains next-ptr for urcu-hashmap */
     struct cds_lfht_node htn;      /* contains next-ptr for urcu-hashmap */
     struct rcu_head      rcu_head; /* For call-rcu */
     struct rcu_head      rcu_head; /* For call-rcu */
-    UA_UInt16 readcount;           /* 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! */
+    UA_UInt16 refcount;            /* Counts the amount of readers on it [alive-bit, 15 counter-bits] */
+    const UA_Node node;            /* Might be cast from any _bigger_ UA_Node* type. Allocate enough memory! */
 } UA_NodeStore_Entry;
 } UA_NodeStore_Entry;
 
 
 struct UA_NodeStore {
 struct UA_NodeStore {
@@ -26,7 +26,7 @@ struct UA_NodeStore {
 typedef UA_UInt32 hash_t;
 typedef UA_UInt32 hash_t;
 
 
 /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
 /* Based on Murmur-Hash 3 by Austin Appleby (public domain, freely usable) */
-static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
+static hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 seed) {
     static const uint32_t c1 = 0xcc9e2d51;
     static const uint32_t c1 = 0xcc9e2d51;
     static const uint32_t c2 = 0x1b873593;
     static const uint32_t c2 = 0x1b873593;
     static const uint32_t r1 = 15;
     static const uint32_t r1 = 15;
@@ -76,7 +76,7 @@ static INLINE hash_t hash_array(const UA_Byte *data, UA_UInt32 len, UA_UInt32 se
     return hash;
     return hash;
 }
 }
 
 
-static INLINE hash_t hash(const UA_NodeId *n) {
+static hash_t hash(const UA_NodeId *n) {
     switch(n->identifierType) {
     switch(n->identifierType) {
     case UA_NODEIDTYPE_NUMERIC:
     case UA_NODEIDTYPE_NUMERIC:
         /*  Knuth's multiplicative hashing */
         /*  Knuth's multiplicative hashing */
@@ -151,11 +151,11 @@ static int compare(struct cds_lfht_node *htn, const void *orig) {
 
 
 /* The entry was removed from the hashtable. No more readers can get it. Since
 /* 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
    all readers using the node for a longer time (outside the rcu critical
-   section) increased the readcount, we only need to wait for the readcount
+   section) increased the refcount, we only need to wait for the refcount
    to reach zero. */
    to reach zero. */
 static void markDead(struct rcu_head *head) {
 static void markDead(struct rcu_head *head) {
     UA_NodeStore_Entry *entry = caa_container_of(head, UA_NodeStore_Entry, rcu_head);
     UA_NodeStore_Entry *entry = caa_container_of(head, UA_NodeStore_Entry, rcu_head);
-    if(uatomic_sub_return(&entry->readcount, ALIVE_BIT) > 0)
+    if(uatomic_and(&entry->refcount, ~ALIVE_BIT) > 0)
         return;
         return;
 
 
     node_deleteMembers(&entry->node);
     node_deleteMembers(&entry->node);
@@ -166,7 +166,7 @@ static void markDead(struct rcu_head *head) {
 /* Free the entry if it is dead and nobody uses it anymore */
 /* Free the entry if it is dead and nobody uses it anymore */
 void UA_NodeStore_release(const UA_Node *managed) {
 void UA_NodeStore_release(const UA_Node *managed) {
     UA_NodeStore_Entry *entry = caa_container_of(managed, UA_NodeStore_Entry, node); // pointer to the first entry
     UA_NodeStore_Entry *entry = caa_container_of(managed, UA_NodeStore_Entry, node); // pointer to the first entry
-    if(uatomic_sub_return(&entry->readcount, 1) > 0)
+    if(uatomic_sub_return(&entry->refcount, 1) > 0)
         return;
         return;
 
 
     node_deleteMembers(managed);
     node_deleteMembers(managed);
@@ -257,9 +257,9 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node **node, UA_Byte flag
     memcpy(&entry->node, *node, nodesize);
     memcpy(&entry->node, *node, nodesize);
 
 
     cds_lfht_node_init(&entry->htn);
     cds_lfht_node_init(&entry->htn);
-    entry->readcount = ALIVE_BIT;
+    entry->refcount = ALIVE_BIT;
     if(flags & UA_NODESTORE_INSERT_GETMANAGED)
     if(flags & UA_NODESTORE_INSERT_GETMANAGED)
-        entry->readcount++;
+        entry->refcount++;
 
 
     hash_t nhash = hash(&(*node)->nodeId);
     hash_t nhash = hash(&(*node)->nodeId);
     struct cds_lfht_node *result;
     struct cds_lfht_node *result;
@@ -328,7 +328,7 @@ UA_StatusCode UA_NodeStore_get(const UA_NodeStore *ns, const UA_NodeId *nodeid,
     }
     }
 
 
     /* This is done within a read-lock. The node will not be marked dead within a read-lock. */
     /* This is done within a read-lock. The node will not be marked dead within a read-lock. */
-    uatomic_inc(&found_entry->readcount);
+    uatomic_inc(&found_entry->refcount);
     rcu_read_unlock();
     rcu_read_unlock();
 
 
     *managedNode = &found_entry->node;
     *managedNode = &found_entry->node;
@@ -343,7 +343,7 @@ void UA_NodeStore_iterate(const UA_NodeStore *ns, UA_NodeStore_nodeVisitor visit
     cds_lfht_first(ht, &iter);
     cds_lfht_first(ht, &iter);
     while(iter.node != UA_NULL) {
     while(iter.node != UA_NULL) {
         UA_NodeStore_Entry *found_entry = (UA_NodeStore_Entry *)cds_lfht_iter_get_node(&iter);
         UA_NodeStore_Entry *found_entry = (UA_NodeStore_Entry *)cds_lfht_iter_get_node(&iter);
-        uatomic_inc(&found_entry->readcount);
+        uatomic_inc(&found_entry->refcount);
         const UA_Node      *node = &found_entry->node;
         const UA_Node      *node = &found_entry->node;
         rcu_read_unlock();
         rcu_read_unlock();
         visitor(node);
         visitor(node);

+ 1 - 0
src/server/ua_securechannel_manager.c

@@ -45,6 +45,7 @@ UA_StatusCode UA_SecureChannelManager_open(UA_SecureChannelManager           *cm
     UA_SecureChannel_init(&entry->channel);
     UA_SecureChannel_init(&entry->channel);
 
 
     entry->channel.connection = conn;
     entry->channel.connection = conn;
+    conn->channel = &entry->channel;
     entry->channel.securityToken.channelId       = cm->lastChannelId++;
     entry->channel.securityToken.channelId       = cm->lastChannelId++;
     entry->channel.securityToken.tokenId         = cm->lastTokenId++;
     entry->channel.securityToken.tokenId         = cm->lastTokenId++;
     entry->channel.securityToken.createdAt       = UA_DateTime_now();
     entry->channel.securityToken.createdAt       = UA_DateTime_now();

+ 173 - 167
src/server/ua_server.c

@@ -38,7 +38,7 @@ void UA_Server_delete(UA_Server *server) {
 UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertificate) {
 UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertificate) {
     UA_Server *server = UA_alloc(sizeof(UA_Server));
     UA_Server *server = UA_alloc(sizeof(UA_Server));
     if(!server)
     if(!server)
-        return server;
+        return UA_NULL;
     
     
     // mockup application description
     // mockup application description
     UA_ApplicationDescription_init(&server->description);
     UA_ApplicationDescription_init(&server->description);
@@ -46,6 +46,8 @@ UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertifica
     UA_String_copycstring("http://open62541.info/applications/4711", &server->description.applicationUri);
     UA_String_copycstring("http://open62541.info/applications/4711", &server->description.applicationUri);
     UA_LocalizedText_copycstring("The open62541 application", &server->description.applicationName);
     UA_LocalizedText_copycstring("The open62541 application", &server->description.applicationName);
     server->description.applicationType = UA_APPLICATIONTYPE_SERVER;
     server->description.applicationType = UA_APPLICATIONTYPE_SERVER;
+    server->externalNamespacesSize = 0;
+    server->externalNamespaces = UA_NULL;
 
 
     UA_ByteString_init(&server->serverCertificate);
     UA_ByteString_init(&server->serverCertificate);
     if(serverCertificate)
     if(serverCertificate)
@@ -85,15 +87,16 @@ UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertifica
 #define STARTSESSIONID 1
 #define STARTSESSIONID 1
     UA_SessionManager_init(&server->sessionManager, MAXSESSIONCOUNT, SESSIONLIFETIME, STARTSESSIONID);
     UA_SessionManager_init(&server->sessionManager, MAXSESSIONCOUNT, SESSIONLIFETIME, STARTSESSIONID);
 
 
-    UA_NodeStore_new(&server->nodestore);
+    server->nodestore = UA_NodeStore_new();
 
 
-#define ADDREFERENCE(NODE, REFTYPE_NODEID, INVERSE, TARGET_EXPNODEID) do { \
-        struct UA_ReferenceNode refnode;                                \
-        UA_ReferenceNode_init(&refnode);                                \
-        refnode.referenceTypeId = REFTYPE_NODEID;                       \
-        refnode.isInverse       = INVERSE;                              \
-        refnode.targetId = TARGET_EXPNODEID;                            \
-        AddReference(server->nodestore, (UA_Node *)NODE, &refnode);     \
+#define ADDREFERENCE(NODEID, REFTYPE_NODEID, TARGET_EXPNODEID) do { \
+        UA_AddReferencesItem item;                                      \
+        UA_AddReferencesItem_init(&item);                               \
+        item.sourceNodeId = NODEID;                                     \
+        item.referenceTypeId = REFTYPE_NODEID;                          \
+        item.isForward = UA_TRUE;                                       \
+        item.targetNodeId = TARGET_EXPNODEID;                           \
+        UA_Server_addReference(server, &item);                          \
     } while(0)
     } while(0)
 
 
 #define COPYNAMES(TARGET, NAME) do {                                \
 #define COPYNAMES(TARGET, NAME) do {                                \
@@ -106,229 +109,236 @@ UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertifica
     /* References */
     /* References */
     /**************/
     /**************/
     
     
+    /* bootstrap by manually inserting "references" and "hassubtype" */
     UA_ReferenceTypeNode *references = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *references = UA_ReferenceTypeNode_new();
-    references->nodeId    = UA_NODEIDS[UA_REFERENCES];
-    references->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(references, "References");
     COPYNAMES(references, "References");
+    references->nodeId     = UA_NODEIDS[UA_REFERENCES];
+    references->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     references->isAbstract = UA_TRUE;
     references->isAbstract = UA_TRUE;
     references->symmetric  = UA_TRUE;
     references->symmetric  = UA_TRUE;
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&references, UA_NODESTORE_INSERT_UNIQUE);
+    // this node has no parent??
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&references, UA_FALSE);
 
 
+    UA_ReferenceTypeNode *hassubtype = UA_ReferenceTypeNode_new();
+    COPYNAMES(hassubtype, "HasSubtype");
+    UA_LocalizedText_copycstring("SubtypeOf", &hassubtype->inverseName);
+    hassubtype->nodeId     = UA_NODEIDS[UA_HASSUBTYPE];
+    hassubtype->nodeClass  = UA_NODECLASS_REFERENCETYPE;
+    hassubtype->isAbstract = UA_FALSE;
+    hassubtype->symmetric  = UA_FALSE;
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&hassubtype, UA_FALSE);
+
+    /* continue adding reference types with normal "addnode" */
     UA_ReferenceTypeNode *hierarchicalreferences = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hierarchicalreferences = UA_ReferenceTypeNode_new();
-    hierarchicalreferences->nodeId    = UA_NODEIDS[UA_HIERARCHICALREFERENCES];
-    hierarchicalreferences->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hierarchicalreferences, "Hierarchicalreferences");
     COPYNAMES(hierarchicalreferences, "Hierarchicalreferences");
+    hierarchicalreferences->nodeId     = UA_NODEIDS[UA_HIERARCHICALREFERENCES];
+    hierarchicalreferences->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->symmetric  = UA_FALSE;
     hierarchicalreferences->symmetric  = UA_FALSE;
-    ADDREFERENCE(hierarchicalreferences, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_REFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hierarchicalreferences, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node**)&hierarchicalreferences,
+                      &UA_EXPANDEDNODEIDS[UA_REFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
-    nonhierarchicalreferences->nodeId    = UA_NODEIDS[UA_NONHIERARCHICALREFERENCES];
-    nonhierarchicalreferences->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(nonhierarchicalreferences, "NonHierarchicalReferences");
     COPYNAMES(nonhierarchicalreferences, "NonHierarchicalReferences");
+    nonhierarchicalreferences->nodeId     = UA_NODEIDS[UA_NONHIERARCHICALREFERENCES];
+    nonhierarchicalreferences->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
-    ADDREFERENCE(nonhierarchicalreferences, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_REFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&nonhierarchicalreferences, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&nonhierarchicalreferences,
+                      &UA_EXPANDEDNODEIDS[UA_REFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
-    haschild->nodeId    = UA_NODEIDS[UA_HASCHILD];
-    haschild->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(haschild, "HasChild");
     COPYNAMES(haschild, "HasChild");
+    haschild->nodeId     = UA_NODEIDS[UA_HASCHILD];
+    haschild->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     haschild->isAbstract = UA_TRUE;
     haschild->isAbstract = UA_TRUE;
     haschild->symmetric  = UA_FALSE;
     haschild->symmetric  = UA_FALSE;
-    ADDREFERENCE(haschild, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&haschild, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&haschild,
+                      &UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
-    organizes->nodeId    = UA_NODEIDS[UA_ORGANIZES];
-    organizes->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(organizes, "Organizes");
     COPYNAMES(organizes, "Organizes");
     UA_LocalizedText_copycstring("OrganizedBy", &organizes->inverseName);
     UA_LocalizedText_copycstring("OrganizedBy", &organizes->inverseName);
+    organizes->nodeId     = UA_NODEIDS[UA_ORGANIZES];
+    organizes->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     organizes->isAbstract = UA_FALSE;
     organizes->isAbstract = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
-    ADDREFERENCE(organizes, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&organizes, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&organizes,
+                      &UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
-    haseventsource->nodeId    = UA_NODEIDS[UA_HASEVENTSOURCE];
-    haseventsource->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(haseventsource, "HasEventSource");
     COPYNAMES(haseventsource, "HasEventSource");
     UA_LocalizedText_copycstring("EventSourceOf", &haseventsource->inverseName);
     UA_LocalizedText_copycstring("EventSourceOf", &haseventsource->inverseName);
+    haseventsource->nodeId     = UA_NODEIDS[UA_HASEVENTSOURCE];
+    haseventsource->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     haseventsource->isAbstract = UA_FALSE;
     haseventsource->isAbstract = UA_FALSE;
     haseventsource->symmetric  = UA_FALSE;
     haseventsource->symmetric  = UA_FALSE;
-    ADDREFERENCE(haseventsource, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&haseventsource, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&haseventsource,
+                      &UA_EXPANDEDNODEIDS[UA_HIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
-    hasmodellingrule->nodeId    = UA_NODEIDS[UA_HASMODELLINGRULE];
-    hasmodellingrule->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hasmodellingrule, "HasModellingRule");
     COPYNAMES(hasmodellingrule, "HasModellingRule");
     UA_LocalizedText_copycstring("ModellingRuleOf", &hasmodellingrule->inverseName);
     UA_LocalizedText_copycstring("ModellingRuleOf", &hasmodellingrule->inverseName);
+    hasmodellingrule->nodeId     = UA_NODEIDS[UA_HASMODELLINGRULE];
+    hasmodellingrule->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasmodellingrule->isAbstract = UA_FALSE;
     hasmodellingrule->isAbstract = UA_FALSE;
     hasmodellingrule->symmetric  = UA_FALSE;
     hasmodellingrule->symmetric  = UA_FALSE;
-    ADDREFERENCE(hasmodellingrule, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hasmodellingrule, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hasmodellingrule,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
-    hasencoding->nodeId    = UA_NODEIDS[UA_HASENCODING];
-    hasencoding->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hasencoding, "HasEncoding");
     COPYNAMES(hasencoding, "HasEncoding");
     UA_LocalizedText_copycstring("EncodingOf", &hasencoding->inverseName);
     UA_LocalizedText_copycstring("EncodingOf", &hasencoding->inverseName);
+    hasencoding->nodeId     = UA_NODEIDS[UA_HASENCODING];
+    hasencoding->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasencoding->isAbstract = UA_FALSE;
     hasencoding->isAbstract = UA_FALSE;
     hasencoding->symmetric  = UA_FALSE;
     hasencoding->symmetric  = UA_FALSE;
-    ADDREFERENCE(hasencoding, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hasencoding, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hasencoding,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
-    hasdescription->nodeId    = UA_NODEIDS[UA_HASDESCRIPTION];
-    hasdescription->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hasdescription, "HasDescription");
     COPYNAMES(hasdescription, "HasDescription");
     UA_LocalizedText_copycstring("DescriptionOf", &hasdescription->inverseName);
     UA_LocalizedText_copycstring("DescriptionOf", &hasdescription->inverseName);
+    hasdescription->nodeId     = UA_NODEIDS[UA_HASDESCRIPTION];
+    hasdescription->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasdescription->isAbstract = UA_FALSE;
     hasdescription->isAbstract = UA_FALSE;
     hasdescription->symmetric  = UA_FALSE;
     hasdescription->symmetric  = UA_FALSE;
-    ADDREFERENCE(hasdescription, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hasdescription, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hasdescription,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
-    hastypedefinition->nodeId    = UA_NODEIDS[UA_HASTYPEDEFINITION];
-    hastypedefinition->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hastypedefinition, "HasTypeDefinition");
     COPYNAMES(hastypedefinition, "HasTypeDefinition");
     UA_LocalizedText_copycstring("TypeDefinitionOf", &hastypedefinition->inverseName);
     UA_LocalizedText_copycstring("TypeDefinitionOf", &hastypedefinition->inverseName);
+    hastypedefinition->nodeId     = UA_NODEIDS[UA_HASTYPEDEFINITION];
+    hastypedefinition->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hastypedefinition->isAbstract = UA_FALSE;
     hastypedefinition->isAbstract = UA_FALSE;
     hastypedefinition->symmetric  = UA_FALSE;
     hastypedefinition->symmetric  = UA_FALSE;
-    ADDREFERENCE(hastypedefinition, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hastypedefinition, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hastypedefinition,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
-    generatesevent->nodeId    = UA_NODEIDS[UA_GENERATESEVENT];
-    generatesevent->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(generatesevent, "GeneratesEvent");
     COPYNAMES(generatesevent, "GeneratesEvent");
     UA_LocalizedText_copycstring("GeneratedBy", &generatesevent->inverseName);
     UA_LocalizedText_copycstring("GeneratedBy", &generatesevent->inverseName);
+    generatesevent->nodeId     = UA_NODEIDS[UA_GENERATESEVENT];
+    generatesevent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     generatesevent->isAbstract = UA_FALSE;
     generatesevent->isAbstract = UA_FALSE;
     generatesevent->symmetric  = UA_FALSE;
     generatesevent->symmetric  = UA_FALSE;
-    ADDREFERENCE(generatesevent, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&generatesevent, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&generatesevent,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
-    aggregates->nodeId    = UA_NODEIDS[UA_AGGREGATES];
-    aggregates->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(aggregates, "Aggregates");
     COPYNAMES(aggregates, "Aggregates");
+    // Todo: Is there an inverse name?
+    aggregates->nodeId     = UA_NODEIDS[UA_AGGREGATES];
+    aggregates->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     aggregates->isAbstract = UA_TRUE;
     aggregates->isAbstract = UA_TRUE;
     aggregates->symmetric  = UA_FALSE;
     aggregates->symmetric  = UA_FALSE;
-    ADDREFERENCE(aggregates, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_HASCHILD]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&aggregates, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&aggregates,
+                      &UA_EXPANDEDNODEIDS[UA_HASCHILD], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
-    UA_ReferenceTypeNode *hassubtype = UA_ReferenceTypeNode_new();
-    hassubtype->nodeId    = UA_NODEIDS[UA_HASSUBTYPE];
-    hassubtype->nodeClass = UA_NODECLASS_REFERENCETYPE;
-    COPYNAMES(hassubtype, "HasSubtype");
-    UA_LocalizedText_copycstring("SubtypeOf", &hassubtype->inverseName);
-    hassubtype->isAbstract = UA_FALSE;
-    hassubtype->symmetric  = UA_FALSE;
-    ADDREFERENCE(hassubtype, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_HASCHILD]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hassubtype, UA_NODESTORE_INSERT_UNIQUE);
+    // complete bootstrap of hassubtype
+    ADDREFERENCE(UA_NODEIDS[UA_HASCHILD], UA_NODEIDS[UA_HASSUBTYPE],
+                 UA_EXPANDEDNODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
-    hasproperty->nodeId    = UA_NODEIDS[UA_HASPROPERTY];
-    hasproperty->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hasproperty, "HasProperty");
     COPYNAMES(hasproperty, "HasProperty");
     UA_LocalizedText_copycstring("PropertyOf", &hasproperty->inverseName);
     UA_LocalizedText_copycstring("PropertyOf", &hasproperty->inverseName);
+    hasproperty->nodeId     = UA_NODEIDS[UA_HASPROPERTY];
+    hasproperty->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasproperty->isAbstract = UA_FALSE;
     hasproperty->isAbstract = UA_FALSE;
     hasproperty->symmetric  = UA_FALSE;
     hasproperty->symmetric  = UA_FALSE;
-    ADDREFERENCE(hasproperty, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_AGGREGATES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hasproperty, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hasproperty,
+                      &UA_EXPANDEDNODEIDS[UA_AGGREGATES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
-    hascomponent->nodeId    = UA_NODEIDS[UA_HASCOMPONENT];
-    hascomponent->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hascomponent, "HasComponent");
     COPYNAMES(hascomponent, "HasComponent");
     UA_LocalizedText_copycstring("ComponentOf", &hascomponent->inverseName);
     UA_LocalizedText_copycstring("ComponentOf", &hascomponent->inverseName);
+    hascomponent->nodeId     = UA_NODEIDS[UA_HASCOMPONENT];
+    hascomponent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hascomponent->isAbstract = UA_FALSE;
     hascomponent->isAbstract = UA_FALSE;
     hascomponent->symmetric  = UA_FALSE;
     hascomponent->symmetric  = UA_FALSE;
-    ADDREFERENCE(hascomponent, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_AGGREGATES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hascomponent, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hascomponent,
+                      &UA_EXPANDEDNODEIDS[UA_AGGREGATES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
-    hasnotifier->nodeId    = UA_NODEIDS[UA_HASNOTIFIER];
-    hasnotifier->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hasnotifier, "HasNotifier");
     COPYNAMES(hasnotifier, "HasNotifier");
     UA_LocalizedText_copycstring("NotifierOf", &hasnotifier->inverseName);
     UA_LocalizedText_copycstring("NotifierOf", &hasnotifier->inverseName);
+    hasnotifier->nodeId     = UA_NODEIDS[UA_HASNOTIFIER];
+    hasnotifier->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasnotifier->isAbstract = UA_FALSE;
     hasnotifier->isAbstract = UA_FALSE;
     hasnotifier->symmetric  = UA_FALSE;
     hasnotifier->symmetric  = UA_FALSE;
-    ADDREFERENCE(hasnotifier, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_HASEVENTSOURCE]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hasnotifier, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hasnotifier,
+                      &UA_EXPANDEDNODEIDS[UA_HASEVENTSOURCE], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
-    hasorderedcomponent->nodeId    = UA_NODEIDS[UA_HASORDEREDCOMPONENT];
-    hasorderedcomponent->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hasorderedcomponent, "HasOrderedComponent");
     COPYNAMES(hasorderedcomponent, "HasOrderedComponent");
     UA_LocalizedText_copycstring("OrderedComponentOf", &hasorderedcomponent->inverseName);
     UA_LocalizedText_copycstring("OrderedComponentOf", &hasorderedcomponent->inverseName);
+    hasorderedcomponent->nodeId     = UA_NODEIDS[UA_HASORDEREDCOMPONENT];
+    hasorderedcomponent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasorderedcomponent->isAbstract = UA_FALSE;
     hasorderedcomponent->isAbstract = UA_FALSE;
     hasorderedcomponent->symmetric  = UA_FALSE;
     hasorderedcomponent->symmetric  = UA_FALSE;
-    ADDREFERENCE(hasorderedcomponent, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_HASCOMPONENT]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hasorderedcomponent, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hasorderedcomponent,
+                      &UA_EXPANDEDNODEIDS[UA_HASCOMPONENT], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
-    hasmodelparent->nodeId    = UA_NODEIDS[UA_HASMODELPARENT];
-    hasmodelparent->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hasmodelparent, "HasModelParent");
     COPYNAMES(hasmodelparent, "HasModelParent");
     UA_LocalizedText_copycstring("ModelParentOf", &hasmodelparent->inverseName);
     UA_LocalizedText_copycstring("ModelParentOf", &hasmodelparent->inverseName);
+    hasmodelparent->nodeId     = UA_NODEIDS[UA_HASMODELPARENT];
+    hasmodelparent->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hasmodelparent->isAbstract = UA_FALSE;
     hasmodelparent->isAbstract = UA_FALSE;
     hasmodelparent->symmetric  = UA_FALSE;
     hasmodelparent->symmetric  = UA_FALSE;
-    ADDREFERENCE(hasmodelparent, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hasmodelparent, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hasmodelparent,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
-    fromstate->nodeId    = UA_NODEIDS[UA_FROMSTATE];
-    fromstate->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(fromstate, "FromState");
     COPYNAMES(fromstate, "FromState");
     UA_LocalizedText_copycstring("ToTransition", &fromstate->inverseName);
     UA_LocalizedText_copycstring("ToTransition", &fromstate->inverseName);
+    fromstate->nodeId     = UA_NODEIDS[UA_FROMSTATE];
+    fromstate->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     fromstate->isAbstract = UA_FALSE;
     fromstate->isAbstract = UA_FALSE;
     fromstate->symmetric  = UA_FALSE;
     fromstate->symmetric  = UA_FALSE;
-    ADDREFERENCE(fromstate, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&fromstate, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&fromstate,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
-    tostate->nodeId    = UA_NODEIDS[UA_TOSTATE];
-    tostate->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(tostate, "ToState");
     COPYNAMES(tostate, "ToState");
     UA_LocalizedText_copycstring("FromTransition", &tostate->inverseName);
     UA_LocalizedText_copycstring("FromTransition", &tostate->inverseName);
+    tostate->nodeId     = UA_NODEIDS[UA_TOSTATE];
+    tostate->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     tostate->isAbstract = UA_FALSE;
     tostate->isAbstract = UA_FALSE;
     tostate->symmetric  = UA_FALSE;
     tostate->symmetric  = UA_FALSE;
-    ADDREFERENCE(tostate, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&tostate, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&tostate,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
-    hascause->nodeId    = UA_NODEIDS[UA_HASCAUSE];
-    hascause->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hascause, "HasCause");
     COPYNAMES(hascause, "HasCause");
     UA_LocalizedText_copycstring("MayBeCausedBy", &hascause->inverseName);
     UA_LocalizedText_copycstring("MayBeCausedBy", &hascause->inverseName);
+    hascause->nodeId     = UA_NODEIDS[UA_HASCAUSE];
+    hascause->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hascause->isAbstract = UA_FALSE;
     hascause->isAbstract = UA_FALSE;
     hascause->symmetric  = UA_FALSE;
     hascause->symmetric  = UA_FALSE;
-    ADDREFERENCE(hascause, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hascause, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hascause,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
-    haseffect->nodeId    = UA_NODEIDS[UA_HASEFFECT];
-    haseffect->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(haseffect, "HasEffect");
     COPYNAMES(haseffect, "HasEffect");
     UA_LocalizedText_copycstring("MayBeEffectedBy", &haseffect->inverseName);
     UA_LocalizedText_copycstring("MayBeEffectedBy", &haseffect->inverseName);
+    haseffect->nodeId     = UA_NODEIDS[UA_HASEFFECT];
+    haseffect->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     haseffect->isAbstract = UA_FALSE;
     haseffect->isAbstract = UA_FALSE;
     haseffect->symmetric  = UA_FALSE;
     haseffect->symmetric  = UA_FALSE;
-    ADDREFERENCE(haseffect, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&haseffect, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&haseffect,
+                      &UA_EXPANDEDNODEIDS[UA_NONHIERARCHICALREFERENCES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
-    hashistoricalconfiguration->nodeId    = UA_NODEIDS[UA_HASHISTORICALCONFIGURATION];
-    hashistoricalconfiguration->nodeClass = UA_NODECLASS_REFERENCETYPE;
     COPYNAMES(hashistoricalconfiguration, "HasHistoricalConfiguration");
     COPYNAMES(hashistoricalconfiguration, "HasHistoricalConfiguration");
     UA_LocalizedText_copycstring("HistoricalConfigurationOf", &hashistoricalconfiguration->inverseName);
     UA_LocalizedText_copycstring("HistoricalConfigurationOf", &hashistoricalconfiguration->inverseName);
+    hashistoricalconfiguration->nodeId     = UA_NODEIDS[UA_HASHISTORICALCONFIGURATION];
+    hashistoricalconfiguration->nodeClass  = UA_NODECLASS_REFERENCETYPE;
     hashistoricalconfiguration->isAbstract = UA_FALSE;
     hashistoricalconfiguration->isAbstract = UA_FALSE;
     hashistoricalconfiguration->symmetric  = UA_FALSE;
     hashistoricalconfiguration->symmetric  = UA_FALSE;
-    ADDREFERENCE(hashistoricalconfiguration, UA_NODEIDS[UA_HASSUBTYPE], UA_TRUE, UA_EXPANDEDNODEIDS[UA_AGGREGATES]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&hashistoricalconfiguration, UA_NODESTORE_INSERT_UNIQUE);
+    UA_Server_addNode(server, (const UA_Node **)&hashistoricalconfiguration,
+                      &UA_EXPANDEDNODEIDS[UA_AGGREGATES], &UA_NODEIDS[UA_HASSUBTYPE]);
 
 
     /***********/
     /***********/
     /* Objects */
     /* Objects */
@@ -338,77 +348,81 @@ UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertifica
     folderType->nodeId    = UA_NODEIDS[UA_FOLDERTYPE];
     folderType->nodeId    = UA_NODEIDS[UA_FOLDERTYPE];
     folderType->nodeClass = UA_NODECLASS_OBJECTTYPE;
     folderType->nodeClass = UA_NODECLASS_OBJECTTYPE;
     COPYNAMES(folderType, "FolderType");
     COPYNAMES(folderType, "FolderType");
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&folderType, UA_NODESTORE_INSERT_UNIQUE);
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&folderType, UA_FALSE);
 
 
     UA_ObjectNode *root = UA_ObjectNode_new();
     UA_ObjectNode *root = UA_ObjectNode_new();
+    COPYNAMES(root, "Root");
     root->nodeId    = UA_NODEIDS[UA_ROOTFOLDER];
     root->nodeId    = UA_NODEIDS[UA_ROOTFOLDER];
     root->nodeClass = UA_NODECLASS_OBJECT;
     root->nodeClass = UA_NODECLASS_OBJECT;
-    COPYNAMES(root, "Root");
-    ADDREFERENCE(root, UA_NODEIDS[UA_HASTYPEDEFINITION], UA_FALSE, UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
-    ADDREFERENCE(root, UA_NODEIDS[UA_ORGANIZES], UA_FALSE, UA_EXPANDEDNODEIDS[UA_OBJECTSFOLDER]);
-    ADDREFERENCE(root, UA_NODEIDS[UA_ORGANIZES], UA_FALSE, UA_EXPANDEDNODEIDS[UA_TYPESFOLDER]);
-    ADDREFERENCE(root, UA_NODEIDS[UA_ORGANIZES], UA_FALSE, UA_EXPANDEDNODEIDS[UA_VIEWSFOLDER]);
-    /* Root is replaced with a managed node that we need to release at the end.*/
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&root, UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED);
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&root, UA_FALSE);
+    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
+                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
+    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_ORGANIZES],
+                 UA_EXPANDEDNODEIDS[UA_OBJECTSFOLDER]);
+    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_ORGANIZES],
+                 UA_EXPANDEDNODEIDS[UA_TYPESFOLDER]);
+    ADDREFERENCE(UA_NODEIDS[UA_ROOTFOLDER], UA_NODEIDS[UA_ORGANIZES],
+                 UA_EXPANDEDNODEIDS[UA_VIEWSFOLDER]);
 
 
     UA_ObjectNode *objects = UA_ObjectNode_new();
     UA_ObjectNode *objects = UA_ObjectNode_new();
+    COPYNAMES(objects, "Objects");
     objects->nodeId    = UA_NODEIDS[UA_OBJECTSFOLDER];
     objects->nodeId    = UA_NODEIDS[UA_OBJECTSFOLDER];
     objects->nodeClass = UA_NODECLASS_OBJECT;
     objects->nodeClass = UA_NODECLASS_OBJECT;
-    COPYNAMES(objects, "Objects");
-    ADDREFERENCE(objects, UA_NODEIDS[UA_HASTYPEDEFINITION], UA_FALSE, UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
-    ADDREFERENCE(objects, UA_NODEIDS[UA_ORGANIZES], UA_FALSE, UA_EXPANDEDNODEIDS[UA_SERVER]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&objects, UA_NODESTORE_INSERT_UNIQUE);
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&objects, UA_FALSE);
+    ADDREFERENCE(UA_NODEIDS[UA_OBJECTSFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
+                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
+    ADDREFERENCE(UA_NODEIDS[UA_OBJECTSFOLDER], UA_NODEIDS[UA_ORGANIZES], UA_EXPANDEDNODEIDS[UA_SERVER]);
 
 
     UA_ObjectNode *types = UA_ObjectNode_new();
     UA_ObjectNode *types = UA_ObjectNode_new();
+    COPYNAMES(types, "Types");
     types->nodeId    = UA_NODEIDS[UA_TYPESFOLDER];
     types->nodeId    = UA_NODEIDS[UA_TYPESFOLDER];
     types->nodeClass = UA_NODECLASS_OBJECT;
     types->nodeClass = UA_NODECLASS_OBJECT;
-    COPYNAMES(types, "Types");
-    ADDREFERENCE(types, UA_NODEIDS[UA_HASTYPEDEFINITION], UA_FALSE, UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&types, UA_NODESTORE_INSERT_UNIQUE);
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&types, UA_FALSE);
+    ADDREFERENCE(UA_NODEIDS[UA_TYPESFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
+                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
 
 
     UA_ObjectNode *views = UA_ObjectNode_new();
     UA_ObjectNode *views = UA_ObjectNode_new();
+    COPYNAMES(views, "Views");
     views->nodeId    = UA_NODEIDS[UA_VIEWSFOLDER];
     views->nodeId    = UA_NODEIDS[UA_VIEWSFOLDER];
     views->nodeClass = UA_NODECLASS_OBJECT;
     views->nodeClass = UA_NODECLASS_OBJECT;
-    COPYNAMES(views, "Views");
-    ADDREFERENCE(views, UA_NODEIDS[UA_HASTYPEDEFINITION], UA_FALSE, UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&views, UA_NODESTORE_INSERT_UNIQUE);
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&views, UA_FALSE);
+    ADDREFERENCE(UA_NODEIDS[UA_VIEWSFOLDER], UA_NODEIDS[UA_HASTYPEDEFINITION],
+                 UA_EXPANDEDNODEIDS[UA_FOLDERTYPE]);
 
 
     UA_ObjectNode *servernode = UA_ObjectNode_new();
     UA_ObjectNode *servernode = UA_ObjectNode_new();
+    COPYNAMES(servernode, "Server");
     servernode->nodeId    = UA_NODEIDS[UA_SERVER];
     servernode->nodeId    = UA_NODEIDS[UA_SERVER];
     servernode->nodeClass = UA_NODECLASS_OBJECT;
     servernode->nodeClass = UA_NODECLASS_OBJECT;
-    COPYNAMES(servernode, "Server");
-    ADDREFERENCE(servernode, UA_NODEIDS[UA_HASCOMPONENT], UA_FALSE, UA_EXPANDEDNODEIDS[UA_SERVER_SERVERCAPABILITIES]);
-    ADDREFERENCE(servernode, UA_NODEIDS[UA_HASCOMPONENT], UA_FALSE, UA_EXPANDEDNODEIDS[UA_SERVER_NAMESPACEARRAY]);
-    ADDREFERENCE(servernode, UA_NODEIDS[UA_HASPROPERTY], UA_FALSE, UA_EXPANDEDNODEIDS[UA_SERVER_SERVERSTATUS]);
-    ADDREFERENCE(servernode, UA_NODEIDS[UA_HASPROPERTY], UA_FALSE, UA_EXPANDEDNODEIDS[UA_SERVER_SERVERARRAY]);
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&servernode, UA_NODESTORE_INSERT_UNIQUE);
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&servernode, UA_FALSE);
+    ADDREFERENCE(UA_NODEIDS[UA_SERVER], UA_NODEIDS[UA_HASCOMPONENT],
+                 UA_EXPANDEDNODEIDS[UA_SERVER_SERVERCAPABILITIES]);
+    ADDREFERENCE(UA_NODEIDS[UA_SERVER], UA_NODEIDS[UA_HASPROPERTY], UA_EXPANDEDNODEIDS[UA_SERVER_SERVERARRAY]);
 
 
     UA_VariableNode *namespaceArray = UA_VariableNode_new();
     UA_VariableNode *namespaceArray = UA_VariableNode_new();
+    COPYNAMES(namespaceArray, "NamespaceArray");
     namespaceArray->nodeId    = UA_NODEIDS[UA_SERVER_NAMESPACEARRAY];
     namespaceArray->nodeId    = UA_NODEIDS[UA_SERVER_NAMESPACEARRAY];
     namespaceArray->nodeClass = UA_NODECLASS_VARIABLE;
     namespaceArray->nodeClass = UA_NODECLASS_VARIABLE;
-    COPYNAMES(namespaceArray, "NamespaceArray");
     UA_Array_new(&namespaceArray->value.storage.data.dataPtr, 2, &UA_TYPES[UA_STRING]);
     UA_Array_new(&namespaceArray->value.storage.data.dataPtr, 2, &UA_TYPES[UA_STRING]);
     namespaceArray->value.vt = &UA_TYPES[UA_STRING];
     namespaceArray->value.vt = &UA_TYPES[UA_STRING];
     namespaceArray->value.storage.data.arrayLength = 2;
     namespaceArray->value.storage.data.arrayLength = 2;
     // Fixme: Insert the external namespaces
     // Fixme: Insert the external namespaces
-    UA_String_copycstring("http://opcfoundation.org/UA/", &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[0]);
-    UA_String_copycstring("http://localhost:16664/open62541/", &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[1]);
+    UA_String_copycstring("http://opcfoundation.org/UA/",
+                          &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[0]);
+    UA_String_copycstring("urn:myServer:myApplication",
+                          &((UA_String *)(namespaceArray->value.storage.data.dataPtr))[1]);
     UA_UInt32 *dimensions = UA_alloc(sizeof(UA_UInt32));
     UA_UInt32 *dimensions = UA_alloc(sizeof(UA_UInt32));
     if(dimensions) {
     if(dimensions) {
         *dimensions = 2;
         *dimensions = 2;
         namespaceArray->arrayDimensions = dimensions;
         namespaceArray->arrayDimensions = dimensions;
         namespaceArray->arrayDimensionsSize = 1;
         namespaceArray->arrayDimensionsSize = 1;
     }
     }
-    namespaceArray->dataType = NS0NODEID(UA_STRING_NS0);
-    namespaceArray->valueRank       = 1;
+    namespaceArray->dataType = UA_NODEIDS[UA_STRING];
+    namespaceArray->valueRank = 1;
     namespaceArray->minimumSamplingInterval = 1.0;
     namespaceArray->minimumSamplingInterval = 1.0;
-    namespaceArray->historizing     = UA_FALSE;
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&namespaceArray, UA_NODESTORE_INSERT_UNIQUE);
+    namespaceArray->historizing = UA_FALSE;
+    UA_Server_addNode(server, (const UA_Node **)&namespaceArray,
+                      &UA_EXPANDEDNODEIDS[UA_SERVER], &UA_NODEIDS[UA_HASCOMPONENT]);
 
 
-    UA_VariableNode *serverstatus = UA_VariableNode_new();
-    serverstatus->nodeId    = UA_NODEIDS[UA_SERVER_SERVERSTATUS];
-    serverstatus->nodeClass = UA_NODECLASS_VARIABLE;
-    COPYNAMES(serverstatus, "ServerStatus");
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     status->startTime   = UA_DateTime_now();
     status->startTime   = UA_DateTime_now();
     status->currentTime = UA_DateTime_now();
     status->currentTime = UA_DateTime_now();
@@ -418,47 +432,39 @@ UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertifica
     UA_String_copycstring("open62541", &status->buildInfo.productName);
     UA_String_copycstring("open62541", &status->buildInfo.productName);
     UA_String_copycstring("0.0", &status->buildInfo.softwareVersion);
     UA_String_copycstring("0.0", &status->buildInfo.softwareVersion);
     UA_String_copycstring("0.0", &status->buildInfo.buildNumber);
     UA_String_copycstring("0.0", &status->buildInfo.buildNumber);
-    status->buildInfo.buildDate     = UA_DateTime_now();
-    status->secondsTillShutdown     = 99999999;
+    status->buildInfo.buildDate = UA_DateTime_now();
+    status->secondsTillShutdown = 99999999;
     UA_LocalizedText_copycstring("because", &status->shutdownReason);
     UA_LocalizedText_copycstring("because", &status->shutdownReason);
-    serverstatus->value.vt          = &UA_TYPES[UA_SERVERSTATUSDATATYPE]; // gets encoded as an extensionobject
+    UA_VariableNode *serverstatus = UA_VariableNode_new();
+    COPYNAMES(serverstatus, "ServerStatus");
+    serverstatus->nodeId    = UA_NODEIDS[UA_SERVER_SERVERSTATUS];
+    serverstatus->nodeClass = UA_NODECLASS_VARIABLE;
+    serverstatus->value.vt = &UA_TYPES[UA_SERVERSTATUSDATATYPE]; // gets encoded as an extensionobject
     serverstatus->value.storage.data.arrayLength = 1;
     serverstatus->value.storage.data.arrayLength = 1;
-    serverstatus->value.storage.data.dataPtr        = status;
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&serverstatus, UA_NODESTORE_INSERT_UNIQUE);
+    serverstatus->value.storage.data.dataPtr = status;
+    UA_Server_addNode(server, (const UA_Node **)&serverstatus,
+                      &UA_EXPANDEDNODEIDS[UA_SERVER], &UA_NODEIDS[UA_HASPROPERTY]);
 
 
+    // todo: make this variable point to a member of the serverstatus
     UA_VariableNode *state = UA_VariableNode_new();
     UA_VariableNode *state = UA_VariableNode_new();
+    UA_ServerState stateEnum = UA_SERVERSTATE_RUNNING;
+    COPYNAMES(state, "State");
     state->nodeId    = UA_NODEIDS[UA_SERVER_SERVERSTATUS_STATE];
     state->nodeId    = UA_NODEIDS[UA_SERVER_SERVERSTATUS_STATE];
     state->nodeClass = UA_NODECLASS_VARIABLE;
     state->nodeClass = UA_NODECLASS_VARIABLE;
-    COPYNAMES(state, "State");
     state->value.vt = &UA_TYPES[UA_SERVERSTATE];
     state->value.vt = &UA_TYPES[UA_SERVERSTATE];
     state->value.storage.data.arrayDimensionsLength = 1; // added to ensure encoding in readreponse
     state->value.storage.data.arrayDimensionsLength = 1; // added to ensure encoding in readreponse
     state->value.storage.data.arrayLength = 1;
     state->value.storage.data.arrayLength = 1;
-    state->value.storage.data.dataPtr = &status->state; // points into the other object.
+    state->value.storage.data.dataPtr = &stateEnum; // points into the other object.
     state->value.storageType = UA_VARIANT_DATA_NODELETE;
     state->value.storageType = UA_VARIANT_DATA_NODELETE;
-    UA_NodeStore_insert(server->nodestore, (UA_Node**)&state, UA_NODESTORE_INSERT_UNIQUE);
-
-    UA_NodeStore_release((const UA_Node *)root);
+    UA_NodeStore_insert(server->nodestore, (const UA_Node**)&state, UA_FALSE);
 
 
     return server;
     return server;
 }
 }
 
 
-UA_AddNodesResult
-UA_Server_addNode(UA_Server *server, UA_Node **node, const UA_NodeId *parentNodeId,
-                                    const UA_NodeId *referenceTypeId) {
-    UA_ExpandedNodeId expParentNodeId;
-    UA_ExpandedNodeId_init(&expParentNodeId);
-    UA_NodeId_copy(parentNodeId, &expParentNodeId.nodeId);
-    return AddNode(server, &adminSession, node, &expParentNodeId, referenceTypeId);
-}
-
-void UA_Server_addReference(UA_Server *server, const UA_AddReferencesRequest *request,
-                            UA_AddReferencesResponse *response) {
-    Service_AddReferences(server, &adminSession, request, response);
-}
-
 void UA_EXPORT
 void UA_EXPORT
-UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value, const UA_VTable_Entry *vt,
-                                const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
+UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
+                                const UA_VTable_Entry *vt, const UA_ExpandedNodeId *parentNodeId,
+                                const UA_NodeId *referenceTypeId) {
     UA_VariableNode *tmpNode = UA_VariableNode_new();
     UA_VariableNode *tmpNode = UA_VariableNode_new();
     UA_QualifiedName_copy(browseName, &tmpNode->browseName);
     UA_QualifiedName_copy(browseName, &tmpNode->browseName);
     UA_String_copy(&browseName->name, &tmpNode->displayName.text);
     UA_String_copy(&browseName->name, &tmpNode->displayName.text);
@@ -469,5 +475,5 @@ UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName,
     tmpNode->value.storage.data.dataPtr = value;
     tmpNode->value.storage.data.dataPtr = value;
     tmpNode->value.storageType = UA_VARIANT_DATA_NODELETE;
     tmpNode->value.storageType = UA_VARIANT_DATA_NODELETE;
     tmpNode->value.storage.data.arrayLength = 1;
     tmpNode->value.storage.data.arrayLength = 1;
-    AddNode(server, &adminSession, (UA_Node**)&tmpNode, parentNodeId, referenceTypeId);
+    UA_Server_addNode(server, (const UA_Node**)&tmpNode, parentNodeId, referenceTypeId);
 }
 }

+ 2 - 2
src/server/ua_server_binary.c

@@ -91,8 +91,8 @@ static void processOpen(UA_Connection *connection, UA_Server *server, const UA_B
     respHeader.isFinal     = 'F';
     respHeader.isFinal     = 'F';
     respHeader.messageSize = 8+4; //header + securechannelid
     respHeader.messageSize = 8+4; //header + securechannelid
 
 
-    UA_ExpandedNodeId responseType;
-    NS0EXPANDEDNODEID(responseType, 449);
+    UA_ExpandedNodeId responseType = UA_EXPANDEDNODEIDS[UA_OPENSECURECHANNELRESPONSE];
+    responseType.nodeId.identifier.numeric += UA_ENCODINGOFFSET_BINARY;
 
 
     respHeader.messageSize += UA_AsymmetricAlgorithmSecurityHeader_calcSizeBinary(&asymHeader);
     respHeader.messageSize += UA_AsymmetricAlgorithmSecurityHeader_calcSizeBinary(&asymHeader);
     respHeader.messageSize += UA_SequenceHeader_calcSizeBinary(&seqHeader);
     respHeader.messageSize += UA_SequenceHeader_calcSizeBinary(&seqHeader);

+ 34 - 12
src/server/ua_services_attribute.c

@@ -14,9 +14,8 @@
 
 
 /** Reads a single attribute from a node in the nodestore. */
 /** Reads a single attribute from a node in the nodestore. */
 static void __readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue *v) {
 static void __readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue *v) {
-    UA_Node const *node   = UA_NULL;
-    UA_Int32       result = UA_NodeStore_get(server->nodestore, &(id->nodeId), &node);
-    if(result != UA_STATUSCODE_GOOD || node == UA_NULL) {
+    UA_Node const *node = UA_NodeStore_get(server->nodestore, &(id->nodeId));
+    if(!node) {
         v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
         v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
         v->status       = UA_STATUSCODE_BADNODEIDUNKNOWN;
         v->status       = UA_STATUSCODE_BADNODEIDUNKNOWN;
         return;
         return;
@@ -194,7 +193,6 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
         response->responseHeader.serviceResult = retval;
         response->responseHeader.serviceResult = retval;
         return;
         return;
     }
     }
-    response->resultsSize = request->nodesToReadSize;
 
 
     /* ### Begin External Namespaces */
     /* ### Begin External Namespaces */
     UA_Boolean isExternal[request->nodesToReadSize];
     UA_Boolean isExternal[request->nodesToReadSize];
@@ -202,7 +200,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     UA_UInt32 indices[request->nodesToReadSize];
     UA_UInt32 indices[request->nodesToReadSize];
     for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
     for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
         UA_UInt32 indexSize = 0;
         UA_UInt32 indexSize = 0;
-        for(UA_Int32 i = 0;i < response->resultsSize;i++) {
+        for(UA_Int32 i = 0;i < request->nodesToReadSize;i++) {
             if(request->nodesToRead[i].nodeId.namespaceIndex !=
             if(request->nodesToRead[i].nodeId.namespaceIndex !=
                server->externalNamespaces[j].index)
                server->externalNamespaces[j].index)
                 continue;
                 continue;
@@ -218,6 +216,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     }
     }
     /* ### End External Namespaces */
     /* ### End External Namespaces */
 
 
+    response->resultsSize = request->nodesToReadSize;
     for(UA_Int32 i = 0;i < response->resultsSize;i++) {
     for(UA_Int32 i = 0;i < response->resultsSize;i++) {
         if(!isExternal[i])
         if(!isExternal[i])
             __readValue(server, &request->nodesToRead[i], &response->results[i]);
             __readValue(server, &request->nodesToRead[i], &response->results[i]);
@@ -225,12 +224,11 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
 }
 }
 
 
 static UA_StatusCode __writeValue(UA_Server *server, UA_WriteValue *writeValue) {
 static UA_StatusCode __writeValue(UA_Server *server, UA_WriteValue *writeValue) {
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    const UA_Node *node;
-    retval = UA_NodeStore_get(server->nodestore, &writeValue->nodeId, &node);
-    if(retval)
-        return retval;
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &writeValue->nodeId);
+    if(!node)
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
 
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     switch(writeValue->attributeId) {
     switch(writeValue->attributeId) {
     case UA_ATTRIBUTEID_NODEID:
     case UA_ATTRIBUTEID_NODEID:
         /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){ } */
         /* if(writeValue->value.encodingMask == UA_DATAVALUE_ENCODINGMASK_VARIANT){ } */
@@ -361,8 +359,32 @@ void Service_Write(UA_Server *server, UA_Session *session,
         response->responseHeader.serviceResult = retval;
         response->responseHeader.serviceResult = retval;
         return;
         return;
     }
     }
+
+    /* ### Begin External Namespaces */
+    UA_Boolean isExternal[request->nodesToWriteSize];
+    memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
+    UA_UInt32 indices[request->nodesToWriteSize];
+    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+        UA_UInt32 indexSize = 0;
+        for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++) {
+            if(request->nodesToWrite[i].nodeId.namespaceIndex !=
+               server->externalNamespaces[j].index)
+                continue;
+            isExternal[i] = UA_TRUE;
+            indices[indexSize] = i;
+            indexSize++;
+        }
+        if(indexSize == 0)
+            continue;
+        UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
+        ens->writeNodes(ens->ensHandle, &request->requestHeader, request->nodesToWrite,
+                        indices, indexSize, response->results, response->diagnosticInfos);
+    }
+    /* ### End External Namespaces */
     
     
     response->resultsSize = request->nodesToWriteSize;
     response->resultsSize = request->nodesToWriteSize;
-    for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++)
-        response->results[i] = __writeValue(server, &request->nodesToWrite[i]);
+    for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++) {
+        if(!isExternal[i])
+            response->results[i] = __writeValue(server, &request->nodesToWrite[i]);
+    }
 }
 }

+ 3 - 3
src/server/ua_services_internal.h

@@ -9,15 +9,15 @@
 #include "ua_session.h"
 #include "ua_session.h"
 #include "ua_nodestore.h"
 #include "ua_nodestore.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated.h"
-
+#include "ua_namespace_0.h"
 /* @brief Add a reference (and the inverse reference to the target node).
 /* @brief Add a reference (and the inverse reference to the target node).
  *
  *
  * @param The node to which the reference shall be added
  * @param The node to which the reference shall be added
  * @param The reference itself
  * @param The reference itself
  * @param The namespace where the target node is looked up for the reverse reference (this is omitted if targetns is UA_NULL)
  * @param The namespace where the target node is looked up for the reverse reference (this is omitted if targetns is UA_NULL)
  */
  */
-UA_Int32 AddReference(UA_NodeStore *nodestore, UA_Node *node, UA_ReferenceNode *reference);
-UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session, UA_Node **node,
+UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session, const UA_Node **node,
                           const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId);
                           const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId);
+UA_StatusCode AddReference(UA_Server *server, const UA_AddReferencesItem *item);
 
 
 #endif /* UA_SERVICES_INTERNAL_H_ */
 #endif /* UA_SERVICES_INTERNAL_H_ */

+ 186 - 82
src/server/ua_services_nodemanagement.c

@@ -7,6 +7,29 @@
 #include "ua_session.h"
 #include "ua_session.h"
 #include "ua_util.h"
 #include "ua_util.h"
 
 
+const UA_VTable_Entry * UA_Node_getVT(const UA_Node *node) {
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        return &UA_TYPES[UA_OBJECTNODE];
+    case UA_NODECLASS_VARIABLE:
+        return &UA_TYPES[UA_VARIABLENODE];
+    case UA_NODECLASS_METHOD:
+        return &UA_TYPES[UA_METHODNODE];
+    case UA_NODECLASS_OBJECTTYPE:
+        return &UA_TYPES[UA_OBJECTTYPENODE];
+    case UA_NODECLASS_VARIABLETYPE:
+        return &UA_TYPES[UA_VARIABLETYPENODE];
+    case UA_NODECLASS_REFERENCETYPE:
+        return &UA_TYPES[UA_REFERENCETYPENODE];
+    case UA_NODECLASS_DATATYPE:
+        return &UA_TYPES[UA_DATATYPENODE];
+    case UA_NODECLASS_VIEW:
+        return &UA_TYPES[UA_VIEWNODE];
+    default: break;
+    }
+    return &UA_TYPES[UA_INVALIDTYPE];
+}
+
 #define COPY_STANDARDATTRIBUTES do {                                    \
 #define COPY_STANDARDATTRIBUTES do {                                    \
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {  \
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {  \
         vnode->displayName = attr.displayName;                          \
         vnode->displayName = attr.displayName;                          \
@@ -82,68 +105,65 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
-UA_Int32 AddReference(UA_NodeStore *nodestore, UA_Node *node, UA_ReferenceNode *reference);
-
 /**
 /**
    If adding the node succeeds, the pointer will be set to zero. If the nodeid
    If adding the node succeeds, the pointer will be set to zero. If the nodeid
    of the node is null (ns=0,i=0), a unique new nodeid will be assigned and
    of the node is null (ns=0,i=0), a unique new nodeid will be assigned and
    returned in the AddNodesResult.
    returned in the AddNodesResult.
  */
  */
-UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session, UA_Node **node,
-                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
-    UA_AddNodesResult result;
-    UA_AddNodesResult_init(&result);
-    
-    const UA_Node *parent;
-    if(UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId, &parent) != UA_STATUSCODE_GOOD) {
-        result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
-        return result;
+static void __addNode(UA_Server *server, UA_Session *session, const UA_Node **node,
+                      const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                      UA_AddNodesResult *result) {
+    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId);
+    if(!parent) {
+        result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
+        return;
     }
     }
 
 
-    const UA_ReferenceTypeNode *referenceType;
-    if(UA_NodeStore_get(server->nodestore, referenceTypeId, (const UA_Node**)&referenceType) != UA_STATUSCODE_GOOD) {
-        result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+    const UA_ReferenceTypeNode *referenceType =
+        (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
+    if(!referenceType) {
+        result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         goto ret;
         goto ret;
     }
     }
 
 
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
-        result.statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+        result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         goto ret2;
         goto ret2;
     }
     }
 
 
     if(referenceType->isAbstract == UA_TRUE) {
     if(referenceType->isAbstract == UA_TRUE) {
-        result.statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
+        result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
         goto ret2;
         goto ret2;
     }
     }
 
 
-    // todo: test if the referenetype is hierarchical
-
+    // todo: test if the referencetype is hierarchical
     if(UA_NodeId_isNull(&(*node)->nodeId)) {
     if(UA_NodeId_isNull(&(*node)->nodeId)) {
-        if(UA_NodeStore_insert(server->nodestore, node,
-                               UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
-            result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
+            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
             goto ret2;
             goto ret2;
         }
         }
-        result.addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
+        result->addedNodeId = (*node)->nodeId; // cannot fail as unique nodeids are numeric
     } else {
     } else {
-        if(UA_NodeId_copy(&(*node)->nodeId, &result.addedNodeId) != UA_STATUSCODE_GOOD) {
-            result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        if(UA_NodeId_copy(&(*node)->nodeId, &result->addedNodeId) != UA_STATUSCODE_GOOD) {
+            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
             goto ret2;
             goto ret2;
         }
         }
 
 
-        if(UA_NodeStore_insert(server->nodestore, node, UA_NODESTORE_INSERT_GETMANAGED) != UA_STATUSCODE_GOOD) {
-            result.statusCode = UA_STATUSCODE_BADNODEIDEXISTS;  // todo: differentiate out of memory
-            UA_NodeId_deleteMembers(&result.addedNodeId);
+        if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
+            result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS;  // todo: differentiate out of memory
+            UA_NodeId_deleteMembers(&result->addedNodeId);
             goto ret2;
             goto ret2;
         }
         }
     }
     }
     
     
-    UA_ReferenceNode ref;
-    UA_ReferenceNode_init(&ref);
-    ref.referenceTypeId = referenceType->nodeId; // is numeric
-    ref.isInverse = UA_TRUE; // todo: check if they are all not inverse..
-    ref.targetId.nodeId = parent->nodeId;
-    AddReference(server->nodestore, *node, &ref);
+    // reference back to the parent
+    UA_AddReferencesItem item;
+    UA_AddReferencesItem_init(&item);
+    item.sourceNodeId = (*node)->nodeId;
+    item.referenceTypeId = referenceType->nodeId;
+    item.isForward = UA_FALSE;
+    item.targetNodeId.nodeId = parent->nodeId;
+    UA_Server_addReference(server, &item);
 
 
     // todo: error handling. remove new node from nodestore
     // todo: error handling. remove new node from nodestore
 
 
@@ -155,97 +175,181 @@ UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session, UA_Node **node
  ret:
  ret:
     UA_NodeStore_release(parent);
     UA_NodeStore_release(parent);
 
 
+    return;
+}
+
+/* Exposed to userland */
+UA_AddNodesResult UA_Server_addNode(UA_Server *server, const UA_Node **node,
+                                    const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
+    UA_AddNodesResult result;
+    UA_AddNodesResult_init(&result);
+    __addNode(server, &adminSession, node, parentNodeId, referenceTypeId, &result);
     return result;
     return result;
 }
 }
 
 
-static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
-                                  UA_AddNodesResult *result) {
+static void __addNodeFromAttributes(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) {
     if(item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
-        // adding nodes to ns0 is not allowed over the wire
         result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
         result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
         return;
         return;
     }
     }
 
 
-    UA_Node *newNode;
-    const UA_VTable_Entry *newNodeVT = UA_NULL;
+    // parse the node
+    UA_Node *node;
+    const UA_VTable_Entry *nodeVT = UA_NULL;
     if(item->nodeClass == UA_NODECLASS_VARIABLE)
     if(item->nodeClass == UA_NODECLASS_VARIABLE)
-        result->statusCode = parseVariableNode(&item->nodeAttributes, &newNode, &newNodeVT);
+        result->statusCode = parseVariableNode(&item->nodeAttributes, &node, &nodeVT);
     else // add more node types here..
     else // add more node types here..
         result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
         result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
 
 
     if(result->statusCode != UA_STATUSCODE_GOOD)
     if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
         return;
 
 
-    *result = AddNode(server, session, &newNode, &item->parentNodeId, &item->referenceTypeId);
+    // add the node
+    __addNode(server, session, (const UA_Node **)&node, &item->parentNodeId, &item->referenceTypeId, result);
     if(result->statusCode != UA_STATUSCODE_GOOD)
     if(result->statusCode != UA_STATUSCODE_GOOD)
-        newNodeVT->delete(newNode);
+        nodeVT->delete(node);
 }
 }
 
 
-void Service_AddNodes(UA_Server *server, UA_Session *session,
-                      const UA_AddNodesRequest *request, UA_AddNodesResponse *response) {
+void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
+                      UA_AddNodesResponse *response) {
     if(request->nodesToAddSize <= 0) {
     if(request->nodesToAddSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
         return;
     }
     }
 
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToAddSize, &UA_TYPES[UA_ADDNODESRESULT]);
+    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToAddSize,
+                                        &UA_TYPES[UA_ADDNODESRESULT]);
     if(retval) {
     if(retval) {
         response->responseHeader.serviceResult = retval;
         response->responseHeader.serviceResult = retval;
         return;
         return;
     }
     }
+
+    /* ### Begin External Namespaces */
+    UA_Boolean isExternal[request->nodesToAddSize];
+    memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToAddSize);
+    UA_UInt32 indices[request->nodesToAddSize];
+    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+        UA_UInt32 indexSize = 0;
+        for(UA_Int32 i = 0;i < request->nodesToAddSize;i++) {
+            if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex !=
+               server->externalNamespaces[j].index)
+                continue;
+            isExternal[i] = UA_TRUE;
+            indices[indexSize] = i;
+            indexSize++;
+        }
+        if(indexSize == 0)
+            continue;
+        UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
+        ens->addNodes(ens->ensHandle, &request->requestHeader, request->nodesToAdd,
+                      indices, indexSize, response->results, response->diagnosticInfos);
+    }
+    /* ### End External Namespaces */
     
     
     response->resultsSize = request->nodesToAddSize;
     response->resultsSize = request->nodesToAddSize;
-    for(int i = 0;i < request->nodesToAddSize;i++)
-        addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
+    for(int i = 0;i < request->nodesToAddSize;i++) {
+        if(!isExternal[i])
+            __addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
+    }
 }
 }
 
 
-static UA_Int32 AddSingleReference(UA_Node *node, UA_ReferenceNode *reference) {
-    // TODO: Check if reference already exists
-    UA_Int32 count = node->referencesSize;
-    UA_ReferenceNode *old_refs = node->references;
-    UA_ReferenceNode *new_refs;
+static UA_StatusCode __addSingleReference(UA_Server *server, const UA_AddReferencesItem *item) {
+    // todo: we don't support references to other servers (expandednodeid) for now
+    if(item->targetServerUri.length > 0)
+        return UA_STATUSCODE_BADNOTIMPLEMENTED;
+    
+    // Is this for an external nodestore?
+    UA_ExternalNodeStore *ens = UA_NULL;
+    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+        if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index) {
+            ens = &server->externalNamespaces[j].externalNodeStore;
+            break;
+        }
+    }
 
 
-    if(count < 0) count = 0;
+    if(ens) {
+        // todo: use external nodestore
 
 
-    if(!(new_refs = UA_alloc(sizeof(UA_ReferenceNode)*(count+1))))
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+    } else {
+        // use the servers nodestore
+        const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
+        // todo differentiate between error codes
+        if(!node)
+            return UA_STATUSCODE_BADINTERNALERROR;
+
+        const UA_VTable_Entry *nodeVT = UA_Node_getVT(node);
+        UA_Node *newNode = nodeVT->new();
+        nodeVT->copy(node, newNode);
+
+        UA_Int32 count = node->referencesSize;
+        if(count < 0)
+            count = 0;
+        UA_ReferenceNode *old_refs = newNode->references;
+        UA_ReferenceNode *new_refs = UA_alloc(sizeof(UA_ReferenceNode)*(count+1));
+        if(!new_refs) {
+            nodeVT->delete(newNode);
+            UA_NodeStore_release(node);
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        }
 
 
-    UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
-    if(UA_ReferenceNode_copy(reference, &new_refs[count]) != UA_STATUSCODE_GOOD) {
-        UA_free(new_refs);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+        // insert the new reference
+        UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
+        UA_ReferenceNode_init(&new_refs[count]);
+        UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
+        new_refs[count].isInverse = !item->isForward;
+        retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
+        if(retval != UA_STATUSCODE_GOOD) {
+            UA_Array_delete(new_refs, ++count, &UA_TYPES[UA_REFERENCENODE]);
+            newNode->references = UA_NULL;
+            newNode->referencesSize = 0;
+            nodeVT->delete(newNode);
+            UA_NodeStore_release(node);
+            return UA_STATUSCODE_BADOUTOFMEMORY;
+        }
+        UA_free(old_refs);
+        newNode->references = new_refs;
+        newNode->referencesSize = ++count;
+        UA_NodeStore_replace(server->nodestore, (const UA_Node **)&newNode, UA_FALSE);
+        UA_NodeStore_release(node);
     }
     }
-
-    node->references     = new_refs;
-    node->referencesSize = count+1;
-    UA_free(old_refs);
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
-}
+} 
 
 
-UA_Int32 AddReference(UA_NodeStore *nodestore, UA_Node *node, UA_ReferenceNode *reference) {
-    UA_Int32 retval = AddSingleReference(node, reference);
-    UA_Node *targetnode;
-    UA_ReferenceNode inversereference;
-    if(retval != UA_STATUSCODE_GOOD || nodestore == UA_NULL)
+UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item) {
+    // the first direction
+    UA_StatusCode retval = __addSingleReference(server, item);
+    if(retval != UA_STATUSCODE_GOOD)
         return retval;
         return retval;
 
 
-    // Do a copy every time?
-    if(UA_NodeStore_get(nodestore, &reference->targetId.nodeId, (const UA_Node **)&targetnode) != UA_STATUSCODE_GOOD)
-        return UA_STATUSCODE_BADINTERNALERROR;
-
-    inversereference.referenceTypeId       = reference->referenceTypeId;
-    inversereference.isInverse             = !reference->isInverse;
-    inversereference.targetId.nodeId       = node->nodeId;
-    inversereference.targetId.namespaceUri = UA_STRING_NULL;
-    inversereference.targetId.serverIndex  = 0;
-    retval = AddSingleReference(targetnode, &inversereference);
-    UA_NodeStore_release(targetnode);
+    // detect when the inverse reference shall be added as well
+    UA_AddReferencesItem item2;
+    UA_AddReferencesItem_init(&item2);
+    item2.sourceNodeId = item->targetNodeId.nodeId;
+    item2.referenceTypeId = item->referenceTypeId;
+    item2.isForward = !item->isForward;
+    item2.targetNodeId.nodeId = item->sourceNodeId;
+    retval = __addSingleReference(server, &item2);
+    // todo: if this fails, remove the first reference
 
 
     return retval;
     return retval;
 }
 }
 
 
-void Service_AddReferences(UA_Server *server, UA_Session *session,
-                           const UA_AddReferencesRequest *request,
+void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
                            UA_AddReferencesResponse *response) {
                            UA_AddReferencesResponse *response) {
-    response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
+    if(request->referencesToAddSize <= 0) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+        return;
+    }
+
+    response->results = UA_alloc(sizeof(UA_StatusCode)*request->referencesToAddSize);
+    if(!response->results) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
+    }
+
+    response->resultsSize = request->referencesToAddSize;
+    for(UA_Int32 i = 0;i < response->resultsSize;i++)
+            response->results[i] = UA_Server_addReference(server, &request->referencesToAdd[i]);
 }
 }

+ 29 - 16
src/server/ua_services_view.c

@@ -64,8 +64,8 @@ getRelevantTargetNode(UA_NodeStore *ns, const UA_BrowseDescription *browseDescri
             return UA_NULL;
             return UA_NULL;
     }
     }
 
 
-    const UA_Node *node;
-    if(UA_NodeStore_get(ns, &reference->targetId.nodeId, &node) != UA_STATUSCODE_GOOD)
+    const UA_Node *node = UA_NodeStore_get(ns, &reference->targetId.nodeId);
+    if(!node)
         return UA_NULL;
         return UA_NULL;
 
 
     if(browseDescription->nodeClassMask != 0 && (node->nodeClass & browseDescription->nodeClassMask) == 0) {
     if(browseDescription->nodeClassMask != 0 && (node->nodeClass & browseDescription->nodeClassMask) == 0) {
@@ -95,12 +95,13 @@ static UA_StatusCode findRelevantReferenceTypes(UA_NodeStore *ns, const UA_NodeI
         return UA_STATUSCODE_BADOUTOFMEMORY;
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
     }
         
         
-    const UA_ReferenceTypeNode *node;
     do {
     do {
-        retval |= UA_NodeStore_get(ns, &typeArray[currentIndex], (const UA_Node **)&node);
-        if(retval)
+        const UA_ReferenceTypeNode *node =
+            (const UA_ReferenceTypeNode *)UA_NodeStore_get(ns, &typeArray[currentIndex]);
+        if(!node)
             break;
             break;
-        if(node->nodeClass != UA_NODECLASS_REFERENCETYPE) // subtypes of referencestypes are always referencestypes?
+        // subtypes of referencestypes are always referencestypes?
+        if(node->nodeClass != UA_NODECLASS_REFERENCETYPE) 
             continue;
             continue;
 
 
         // Find subtypes of the current referencetype
         // Find subtypes of the current referencetype
@@ -152,7 +153,8 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
     if(!returnAll) {
     if(!returnAll) {
         if(browseDescription->includeSubtypes) {
         if(browseDescription->includeSubtypes) {
             browseResult->statusCode = findRelevantReferenceTypes(ns, &browseDescription->referenceTypeId,
             browseResult->statusCode = findRelevantReferenceTypes(ns, &browseDescription->referenceTypeId,
-                                                                  &relevantReferenceTypes, &relevantReferenceTypesSize);
+                                                                  &relevantReferenceTypes,
+                                                                  &relevantReferenceTypesSize);
             if(browseResult->statusCode != UA_STATUSCODE_GOOD)
             if(browseResult->statusCode != UA_STATUSCODE_GOOD)
                 return;
                 return;
         } else {
         } else {
@@ -161,17 +163,23 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
         }
         }
     }
     }
 
 
-    const UA_Node *parentNode;
-    if(UA_NodeStore_get(ns, &browseDescription->nodeId, &parentNode) != UA_STATUSCODE_GOOD) {
+    const UA_Node *parentNode = UA_NodeStore_get(ns, &browseDescription->nodeId);
+    if(!parentNode) {
         browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         browseResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
         if(!returnAll && browseDescription->includeSubtypes)
         if(!returnAll && browseDescription->includeSubtypes)
             UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_NODEID]);
             UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_NODEID]);
         return;
         return;
     }
     }
 
 
+    maxReferences = parentNode->referencesSize;
     // 0 => unlimited references
     // 0 => unlimited references
-    if(maxReferences == 0 || maxReferences > UA_INT32_MAX || (UA_Int32)maxReferences > parentNode->referencesSize)
-        maxReferences = parentNode->referencesSize;
+    if(maxReferences <= 0 || maxReferences > UA_INT32_MAX ||
+       (UA_Int32)maxReferences > parentNode->referencesSize) {
+        if(parentNode->referencesSize < 0)
+            maxReferences = 0;
+        else
+            maxReferences = parentNode->referencesSize;
+    }
 
 
     /* We allocate an array that is probably too big. But since most systems
     /* We allocate an array that is probably too big. But since most systems
        have more than enough memory, this has zero impact on speed and
        have more than enough memory, this has zero impact on speed and
@@ -183,13 +191,16 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
         UA_UInt32 currentRefs = 0;
         UA_UInt32 currentRefs = 0;
         for(UA_Int32 i = 0;i < parentNode->referencesSize && currentRefs < maxReferences;i++) {
         for(UA_Int32 i = 0;i < parentNode->referencesSize && currentRefs < maxReferences;i++) {
             // 1) Is the node relevant? If yes, the node is retrieved from the nodestore.
             // 1) Is the node relevant? If yes, the node is retrieved from the nodestore.
-            const UA_Node *currentNode = getRelevantTargetNode(ns, browseDescription, returnAll, &parentNode->references[i],
-                                                               relevantReferenceTypes, relevantReferenceTypesSize);
+            const UA_Node *currentNode = getRelevantTargetNode(ns, browseDescription, returnAll,
+                                                               &parentNode->references[i],
+                                                               relevantReferenceTypes,
+                                                               relevantReferenceTypesSize);
             if(!currentNode)
             if(!currentNode)
                 continue;
                 continue;
 
 
             // 2) Fill the reference description. This also releases the current node.
             // 2) Fill the reference description. This also releases the current node.
-            if(fillReferenceDescription(ns, currentNode, &parentNode->references[i], browseDescription->resultMask,
+            if(fillReferenceDescription(ns, currentNode, &parentNode->references[i],
+                                        browseDescription->resultMask,
                                         &browseResult->references[currentRefs]) != UA_STATUSCODE_GOOD) {
                                         &browseResult->references[currentRefs]) != UA_STATUSCODE_GOOD) {
                 UA_Array_delete(browseResult->references, currentRefs, &UA_TYPES[UA_REFERENCEDESCRIPTION]);
                 UA_Array_delete(browseResult->references, currentRefs, &UA_TYPES[UA_REFERENCEDESCRIPTION]);
                 currentRefs = 0;
                 currentRefs = 0;
@@ -212,13 +223,15 @@ static void getBrowseResult(UA_NodeStore *ns, const UA_BrowseDescription *browse
         UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_NODEID]);
         UA_Array_delete(relevantReferenceTypes, relevantReferenceTypesSize, &UA_TYPES[UA_NODEID]);
 }
 }
 
 
-void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request, UA_BrowseResponse *response) {
+void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseRequest *request,
+                    UA_BrowseResponse *response) {
     if(request->nodesToBrowseSize <= 0) {
     if(request->nodesToBrowseSize <= 0) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
         return;
         return;
     }
     }
 
 
-    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToBrowseSize, &UA_TYPES[UA_BROWSERESULT]);
+    UA_StatusCode retval = UA_Array_new((void**)&response->results, request->nodesToBrowseSize,
+                                        &UA_TYPES[UA_BROWSERESULT]);
     if(retval) {
     if(retval) {
         response->responseHeader.serviceResult = retval;
         response->responseHeader.serviceResult = retval;
         return;
         return;

+ 1 - 0
src/ua_transport.c

@@ -2,6 +2,7 @@
 #include <stdio.h>
 #include <stdio.h>
 #endif
 #endif
 #include "ua_transport.h"
 #include "ua_transport.h"
+#include "ua_types_internal.h"
 #include "ua_util.h"
 #include "ua_util.h"
 
 
 UA_TYPE_DEFAULT(UA_MessageType)
 UA_TYPE_DEFAULT(UA_MessageType)

+ 1 - 0
src/ua_types.c

@@ -13,6 +13,7 @@
 
 
 #include "ua_util.h"
 #include "ua_util.h"
 #include "ua_types.h"
 #include "ua_types.h"
+#include "ua_types_internal.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_namespace_0.h"
 #include "ua_namespace_0.h"
 #include "ua_statuscodes.h"
 #include "ua_statuscodes.h"

+ 89 - 89
tests/check_nodestore.c

@@ -3,7 +3,7 @@
 #include <time.h>
 #include <time.h>
 
 
 #include "ua_types.h"
 #include "ua_types.h"
-#include "server/nodestore/open62541_nodestore.h"
+#include "server/ua_nodestore.h"
 #include "ua_util.h"
 #include "ua_util.h"
 #include "check.h"
 #include "check.h"
 
 
@@ -23,10 +23,10 @@ void printVisitor(const UA_Node* node) {
 	printf("%d\n", node->nodeId.identifier.numeric);
 	printf("%d\n", node->nodeId.identifier.numeric);
 }
 }
 
 
-START_TEST(test_open62541NodeStore) {
-	open62541NodeStore *ns = UA_NULL;
-	open62541NodeStore_new(&ns);
-	open62541NodeStore_delete(ns);
+START_TEST(test_UA_NodeStore) {
+	UA_NodeStore *ns = UA_NULL;
+	UA_NodeStore_new(&ns);
+	UA_NodeStore_delete(ns);
 }
 }
 END_TEST
 END_TEST
 
 
@@ -39,113 +39,113 @@ UA_StatusCode createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 	return UA_STATUSCODE_GOOD;
 	return UA_STATUSCODE_GOOD;
 }
 }
 
 
-START_TEST(findNodeInopen62541NodeStoreWithSingleEntry) {
+START_TEST(findNodeInUA_NodeStoreWithSingleEntry) {
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
    	rcu_register_thread();
    	rcu_register_thread();
 #endif
 #endif
 	// given
 	// given
-	open62541NodeStore *ns;
-	open62541NodeStore_new(&ns);
+	UA_NodeStore *ns;
+	UA_NodeStore_new(&ns);
 	UA_Node* n1; createNode(&n1,0,2253);
 	UA_Node* n1; createNode(&n1,0,2253);
-	open62541NodeStore_insert(ns, &n1, UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED);
+	UA_NodeStore_insert(ns, &n1, UA_NODESTORE_INSERT_UNIQUE | UA_NODESTORE_INSERT_GETMANAGED);
 	const UA_Node* nr = UA_NULL;
 	const UA_Node* nr = UA_NULL;
 	UA_Int32 retval;
 	UA_Int32 retval;
 	// when
 	// when
-	retval = open62541NodeStore_get(ns,&n1->nodeId,&nr);
+	retval = UA_NodeStore_get(ns,&n1->nodeId,&nr);
 	// then
 	// then
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_ptr_eq((void*)nr, (void*)n1);
 	ck_assert_ptr_eq((void*)nr, (void*)n1);
 	// finally
 	// finally
-	open62541NodeStore_release(n1);
-	open62541NodeStore_release(nr);
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_release(n1);
+	UA_NodeStore_release(nr);
+	UA_NodeStore_delete(ns);
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
 #endif
 #endif
 }
 }
 END_TEST
 END_TEST
 
 
-START_TEST(failToFindNodeInOtheropen62541NodeStore) {
+START_TEST(failToFindNodeInOtherUA_NodeStore) {
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
    	rcu_register_thread();
    	rcu_register_thread();
 #endif
 #endif
 	// given
 	// given
-	open62541NodeStore *ns = UA_NULL;
-	open62541NodeStore_new(&ns);
+	UA_NodeStore *ns = UA_NULL;
+	UA_NodeStore_new(&ns);
 
 
-	UA_Node* n1; createNode(&n1,0,2253); open62541NodeStore_insert(ns, &n1, 0);
-	UA_Node* n2; createNode(&n2,0,2253); open62541NodeStore_insert(ns, &n2, 0);
+	UA_Node* n1; createNode(&n1,0,2253); UA_NodeStore_insert(ns, &n1, 0);
+	UA_Node* n2; createNode(&n2,0,2253); UA_NodeStore_insert(ns, &n2, 0);
 
 
 	const UA_Node* nr = UA_NULL;
 	const UA_Node* nr = UA_NULL;
 	// when
 	// when
 	UA_Node* n; createNode(&n,1,2255);
 	UA_Node* n; createNode(&n,1,2255);
-	UA_Int32 retval = open62541NodeStore_get(ns,&n->nodeId, &nr);
+	UA_Int32 retval = UA_NodeStore_get(ns,&n->nodeId, &nr);
 	// then
 	// then
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
 	// finally
 	// finally
 	UA_Node_delete(n);
 	UA_Node_delete(n);
-	open62541NodeStore_release(nr);
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_release(nr);
+	UA_NodeStore_delete(ns);
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
 #endif
 #endif
 }
 }
 END_TEST
 END_TEST
 
 
-START_TEST(findNodeInopen62541NodeStoreWithSeveralEntries) {
+START_TEST(findNodeInUA_NodeStoreWithSeveralEntries) {
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
    	rcu_register_thread();
    	rcu_register_thread();
 #endif
 #endif
 	// given
 	// given
-	open62541NodeStore *ns;
-	open62541NodeStore_new(&ns);
-	UA_Node* n1; createNode(&n1,0,2253); open62541NodeStore_insert(ns, &n1, 0);
-	UA_Node* n2; createNode(&n2,0,2255); open62541NodeStore_insert(ns, &n2, 0);
-	UA_Node* n3; createNode(&n3,0,2257); open62541NodeStore_insert(ns, &n3, UA_NODESTORE_INSERT_GETMANAGED);
-	UA_Node* n4; createNode(&n4,0,2200); open62541NodeStore_insert(ns, &n4, 0);
-	UA_Node* n5; createNode(&n5,0,1); open62541NodeStore_insert(ns, &n5, 0);
-	UA_Node* n6; createNode(&n6,0,12); open62541NodeStore_insert(ns, &n6, 0);
+	UA_NodeStore *ns;
+	UA_NodeStore_new(&ns);
+	UA_Node* n1; createNode(&n1,0,2253); UA_NodeStore_insert(ns, &n1, 0);
+	UA_Node* n2; createNode(&n2,0,2255); UA_NodeStore_insert(ns, &n2, 0);
+	UA_Node* n3; createNode(&n3,0,2257); UA_NodeStore_insert(ns, &n3, UA_NODESTORE_INSERT_GETMANAGED);
+	UA_Node* n4; createNode(&n4,0,2200); UA_NodeStore_insert(ns, &n4, 0);
+	UA_Node* n5; createNode(&n5,0,1); UA_NodeStore_insert(ns, &n5, 0);
+	UA_Node* n6; createNode(&n6,0,12); UA_NodeStore_insert(ns, &n6, 0);
 
 
 	const UA_Node* nr = UA_NULL;
 	const UA_Node* nr = UA_NULL;
 	UA_Int32 retval;
 	UA_Int32 retval;
 	// when
 	// when
-	retval = open62541NodeStore_get(ns,&(n3->nodeId),&nr);
+	retval = UA_NodeStore_get(ns,&(n3->nodeId),&nr);
 	// then
 	// then
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_ptr_eq((void*)nr, (void*)n3);
 	ck_assert_ptr_eq((void*)nr, (void*)n3);
 	// finally
 	// finally
-	open62541NodeStore_release(n3);
-	open62541NodeStore_release(nr);
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_release(n3);
+	UA_NodeStore_release(nr);
+	UA_NodeStore_delete(ns);
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
 #endif
 #endif
 }
 }
 END_TEST
 END_TEST
 
 
-START_TEST(iterateOveropen62541NodeStoreShallNotVisitEmptyNodes) {
+START_TEST(iterateOverUA_NodeStoreShallNotVisitEmptyNodes) {
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
    	rcu_register_thread();
    	rcu_register_thread();
 #endif
 #endif
 	// given
 	// given
-	open62541NodeStore *ns;
-	open62541NodeStore_new(&ns);
-	UA_Node* n1; createNode(&n1,0,2253); open62541NodeStore_insert(ns, &n1, 0);
-	UA_Node* n2; createNode(&n2,0,2255); open62541NodeStore_insert(ns, &n2, 0);
-	UA_Node* n3; createNode(&n3,0,2257); open62541NodeStore_insert(ns, &n3, 0);
-	UA_Node* n4; createNode(&n4,0,2200); open62541NodeStore_insert(ns, &n4, 0);
-	UA_Node* n5; createNode(&n5,0,1); open62541NodeStore_insert(ns, &n5, 0);
-	UA_Node* n6; createNode(&n6,0,12); open62541NodeStore_insert(ns, &n6, 0);
+	UA_NodeStore *ns;
+	UA_NodeStore_new(&ns);
+	UA_Node* n1; createNode(&n1,0,2253); UA_NodeStore_insert(ns, &n1, 0);
+	UA_Node* n2; createNode(&n2,0,2255); UA_NodeStore_insert(ns, &n2, 0);
+	UA_Node* n3; createNode(&n3,0,2257); UA_NodeStore_insert(ns, &n3, 0);
+	UA_Node* n4; createNode(&n4,0,2200); UA_NodeStore_insert(ns, &n4, 0);
+	UA_Node* n5; createNode(&n5,0,1); UA_NodeStore_insert(ns, &n5, 0);
+	UA_Node* n6; createNode(&n6,0,12); UA_NodeStore_insert(ns, &n6, 0);
 
 
 	// when
 	// when
 	zeroCnt = 0;
 	zeroCnt = 0;
 	visitCnt = 0;
 	visitCnt = 0;
-	open62541NodeStore_iterate(ns,checkZeroVisitor);
+	UA_NodeStore_iterate(ns,checkZeroVisitor);
 	// then
 	// then
 	ck_assert_int_eq(zeroCnt, 0);
 	ck_assert_int_eq(zeroCnt, 0);
 	ck_assert_int_eq(visitCnt, 6);
 	ck_assert_int_eq(visitCnt, 6);
 	// finally
 	// finally
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_delete(ns);
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
 #endif
 #endif
@@ -157,25 +157,25 @@ START_TEST(findNodeInExpandedNamespace) {
    	rcu_register_thread();
    	rcu_register_thread();
 #endif
 #endif
 	// given
 	// given
-	open62541NodeStore *ns;
-	open62541NodeStore_new(&ns);
+	UA_NodeStore *ns;
+	UA_NodeStore_new(&ns);
 	UA_Node* n;
 	UA_Node* n;
 	UA_Int32 i=0;
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 	for (; i<200; i++) {
-		createNode(&n,0,i); open62541NodeStore_insert(ns, &n, 0);
+		createNode(&n,0,i); UA_NodeStore_insert(ns, &n, 0);
 	}
 	}
 	const UA_Node* nr = UA_NULL;
 	const UA_Node* nr = UA_NULL;
 	UA_Int32 retval;
 	UA_Int32 retval;
 	// when
 	// when
 	createNode(&n,0,25);
 	createNode(&n,0,25);
-	retval = open62541NodeStore_get(ns,&(n->nodeId),&nr);
+	retval = UA_NodeStore_get(ns,&(n->nodeId),&nr);
 	// then
 	// then
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_eq(nr->nodeId.identifier.numeric,n->nodeId.identifier.numeric);
 	ck_assert_int_eq(nr->nodeId.identifier.numeric,n->nodeId.identifier.numeric);
 	// finally
 	// finally
 	UA_free((void*)n);
 	UA_free((void*)n);
-	open62541NodeStore_release(nr);
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_release(nr);
+	UA_NodeStore_delete(ns);
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
 #endif
 #endif
@@ -187,51 +187,51 @@ START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
    	rcu_register_thread();
    	rcu_register_thread();
 #endif
 #endif
 	// given
 	// given
-	open62541NodeStore *ns;
-	open62541NodeStore_new(&ns);
+	UA_NodeStore *ns;
+	UA_NodeStore_new(&ns);
 	UA_Node* n;
 	UA_Node* n;
 	UA_Int32 i=0;
 	UA_Int32 i=0;
 	for (; i<200; i++) {
 	for (; i<200; i++) {
-		createNode(&n,0,i); open62541NodeStore_insert(ns, &n, 0);
+		createNode(&n,0,i); UA_NodeStore_insert(ns, &n, 0);
 	}
 	}
 	// when
 	// when
 	zeroCnt = 0;
 	zeroCnt = 0;
 	visitCnt = 0;
 	visitCnt = 0;
-	open62541NodeStore_iterate(ns,checkZeroVisitor);
+	UA_NodeStore_iterate(ns,checkZeroVisitor);
 	// then
 	// then
 	ck_assert_int_eq(zeroCnt, 0);
 	ck_assert_int_eq(zeroCnt, 0);
 	ck_assert_int_eq(visitCnt, 200);
 	ck_assert_int_eq(visitCnt, 200);
 	// finally
 	// finally
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_delete(ns);
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
 #endif
 #endif
 }
 }
 END_TEST
 END_TEST
 
 
-START_TEST(failToFindNonExistantNodeInopen62541NodeStoreWithSeveralEntries) {
+START_TEST(failToFindNonExistantNodeInUA_NodeStoreWithSeveralEntries) {
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
    	rcu_register_thread();
    	rcu_register_thread();
 #endif
 #endif
 	// given
 	// given
-	open62541NodeStore *ns;
-	open62541NodeStore_new(&ns);
-	UA_Node* n1; createNode(&n1,0,2253); open62541NodeStore_insert(ns, &n1, 0);
-	UA_Node* n2; createNode(&n2,0,2255); open62541NodeStore_insert(ns, &n2, 0);
-	UA_Node* n3; createNode(&n3,0,2257); open62541NodeStore_insert(ns, &n3, 0);
-	UA_Node* n4; createNode(&n4,0,2200); open62541NodeStore_insert(ns, &n4, 0);
-	UA_Node* n5; createNode(&n5,0,1); open62541NodeStore_insert(ns, &n5, 0);
+	UA_NodeStore *ns;
+	UA_NodeStore_new(&ns);
+	UA_Node* n1; createNode(&n1,0,2253); UA_NodeStore_insert(ns, &n1, 0);
+	UA_Node* n2; createNode(&n2,0,2255); UA_NodeStore_insert(ns, &n2, 0);
+	UA_Node* n3; createNode(&n3,0,2257); UA_NodeStore_insert(ns, &n3, 0);
+	UA_Node* n4; createNode(&n4,0,2200); UA_NodeStore_insert(ns, &n4, 0);
+	UA_Node* n5; createNode(&n5,0,1); UA_NodeStore_insert(ns, &n5, 0);
 	UA_Node* n6; createNode(&n6,0,12); 
 	UA_Node* n6; createNode(&n6,0,12); 
 
 
 	const UA_Node* nr = UA_NULL;
 	const UA_Node* nr = UA_NULL;
 	UA_Int32 retval;
 	UA_Int32 retval;
 	// when
 	// when
-	retval = open62541NodeStore_get(ns, &(n6->nodeId), &nr);
+	retval = UA_NodeStore_get(ns, &(n6->nodeId), &nr);
 	// then
 	// then
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
 	ck_assert_int_ne(retval, UA_STATUSCODE_GOOD);
 	// finally
 	// finally
 	UA_free((void *)n6);
 	UA_free((void *)n6);
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_delete(ns);
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
 #endif
 #endif
@@ -243,8 +243,8 @@ END_TEST
 /************************************/
 /************************************/
 
 
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
-struct open62541NodeStoreProfileTest {
-	open62541NodeStore *ns;
+struct UA_NodeStoreProfileTest {
+	UA_NodeStore *ns;
 	UA_Int32 min_val;
 	UA_Int32 min_val;
 	UA_Int32 max_val;
 	UA_Int32 max_val;
 	UA_Int32 rounds;
 	UA_Int32 rounds;
@@ -252,16 +252,16 @@ struct open62541NodeStoreProfileTest {
 
 
 void *profileGetThread(void *arg) {
 void *profileGetThread(void *arg) {
    	rcu_register_thread();
    	rcu_register_thread();
-	struct open62541NodeStoreProfileTest *test = (struct open62541NodeStoreProfileTest*) arg;
+	struct UA_NodeStoreProfileTest *test = (struct UA_NodeStoreProfileTest*) arg;
 	UA_NodeId id = NS0NODEID(0);
 	UA_NodeId id = NS0NODEID(0);
 	const UA_Node *cn;
 	const UA_Node *cn;
 	UA_Int32 max_val = test->max_val;
 	UA_Int32 max_val = test->max_val;
-	open62541NodeStore *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;
-			open62541NodeStore_get(ns,&id, &cn);
-			open62541NodeStore_release(cn);
+			UA_NodeStore_get(ns,&id, &cn);
+			UA_NodeStore_release(cn);
 		}
 		}
 	}
 	}
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -276,25 +276,25 @@ START_TEST(profileGetDelete) {
 #endif
 #endif
 
 
 #define N 1000000
 #define N 1000000
-	open62541NodeStore *ns;
-	open62541NodeStore_new(&ns);
+	UA_NodeStore *ns;
+	UA_NodeStore_new(&ns);
 	UA_Int32 i=0;
 	UA_Int32 i=0;
 	UA_Node *n;
 	UA_Node *n;
 	for (; i<N; i++) {
 	for (; i<N; i++) {
-		createNode(&n,0,i); open62541NodeStore_insert(ns, &n, 0);
+		createNode(&n,0,i); UA_NodeStore_insert(ns, &n, 0);
 	}
 	}
 	clock_t begin, end;
 	clock_t begin, end;
 	begin = clock();
 	begin = clock();
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 #define THREADS 4
 #define THREADS 4
     pthread_t t[THREADS];
     pthread_t t[THREADS];
-	struct open62541NodeStoreProfileTest p[THREADS];
+	struct UA_NodeStoreProfileTest p[THREADS];
 	for (int i = 0; i < THREADS; i++) {
 	for (int i = 0; i < THREADS; i++) {
-		p[i] = (struct open62541NodeStoreProfileTest){ns, i*(N/THREADS), (i+1)*(N/THREADS), 50};
-		pthread_create(&t[i], UA_NULL, profileGetThread, &p[i]);
+		p[i] = (struct UA_NodeStoreProfileTest){ns, i*(N/THREADS), (i+1)*(N/THREADS), 50};
+		pthread_create(&t[i], NULL, profileGetThread, &p[i]);
 	}
 	}
 	for (int i = 0; i < THREADS; i++)
 	for (int i = 0; i < THREADS; i++)
-		pthread_join(t[i], UA_NULL);
+		pthread_join(t[i], NULL);
 	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
@@ -303,15 +303,15 @@ START_TEST(profileGetDelete) {
 	for(UA_Int32 x = 0; x<50; x++) {
 	for(UA_Int32 x = 0; x<50; x++) {
 	    for(i=0; i<N; i++) {
 	    for(i=0; i<N; i++) {
 	        id.identifier.numeric = i;
 	        id.identifier.numeric = i;
-			open62541NodeStore_get(ns,&id, &cn);
-			open62541NodeStore_release(cn);
+			UA_NodeStore_get(ns,&id, &cn);
+			UA_NodeStore_release(cn);
         }
         }
     }
     }
 	end = clock();
 	end = clock();
 	printf("Time for single-threaded %d create/get/delete in a namespace: %fs.\n", N, (double)(end - begin) / CLOCKS_PER_SEC);
 	printf("Time for single-threaded %d create/get/delete in a namespace: %fs.\n", N, (double)(end - begin) / CLOCKS_PER_SEC);
 #endif
 #endif
 
 
-	open62541NodeStore_delete(ns);
+	UA_NodeStore_delete(ns);
 
 
 #ifdef MULTITHREADING
 #ifdef MULTITHREADING
 	rcu_unregister_thread();
 	rcu_unregister_thread();
@@ -320,22 +320,22 @@ START_TEST(profileGetDelete) {
 END_TEST
 END_TEST
 
 
 Suite * namespace_suite (void) {
 Suite * namespace_suite (void) {
-	Suite *s = suite_create ("open62541NodeStore");
+	Suite *s = suite_create ("UA_NodeStore");
 
 
 	TCase *tc_cd = tcase_create ("Create/Delete");
 	TCase *tc_cd = tcase_create ("Create/Delete");
-	tcase_add_test (tc_cd, test_open62541NodeStore);
+	tcase_add_test (tc_cd, test_UA_NodeStore);
 	suite_add_tcase (s, tc_cd);
 	suite_add_tcase (s, tc_cd);
 
 
 	TCase* tc_find = tcase_create ("Find");
 	TCase* tc_find = tcase_create ("Find");
-	tcase_add_test (tc_find, findNodeInopen62541NodeStoreWithSingleEntry);
-	tcase_add_test (tc_find, findNodeInopen62541NodeStoreWithSeveralEntries);
+	tcase_add_test (tc_find, findNodeInUA_NodeStoreWithSingleEntry);
+	tcase_add_test (tc_find, findNodeInUA_NodeStoreWithSeveralEntries);
 	tcase_add_test (tc_find, findNodeInExpandedNamespace);
 	tcase_add_test (tc_find, findNodeInExpandedNamespace);
-	tcase_add_test (tc_find, failToFindNonExistantNodeInopen62541NodeStoreWithSeveralEntries);
-	tcase_add_test (tc_find, failToFindNodeInOtheropen62541NodeStore);
+	tcase_add_test (tc_find, failToFindNonExistantNodeInUA_NodeStoreWithSeveralEntries);
+	tcase_add_test (tc_find, failToFindNodeInOtherUA_NodeStore);
 	suite_add_tcase (s, tc_find);
 	suite_add_tcase (s, tc_find);
 
 
 	TCase* tc_iterate = tcase_create ("Iterate");
 	TCase* tc_iterate = tcase_create ("Iterate");
-	tcase_add_test (tc_iterate, iterateOveropen62541NodeStoreShallNotVisitEmptyNodes);
+	tcase_add_test (tc_iterate, iterateOverUA_NodeStoreShallNotVisitEmptyNodes);
 	tcase_add_test (tc_iterate, iterateOverExpandedNamespaceShallNotVisitEmptyNodes);
 	tcase_add_test (tc_iterate, iterateOverExpandedNamespaceShallNotVisitEmptyNodes);
 	suite_add_tcase (s, tc_iterate);
 	suite_add_tcase (s, tc_iterate);
 	
 	

+ 1 - 0
tools/generate_builtin.py

@@ -325,6 +325,7 @@ printc('''/**
  */
  */
  
  
 #include "''' + args.outfile.split("/")[-1] + '''.h"
 #include "''' + args.outfile.split("/")[-1] + '''.h"
+#include "ua_types_internal.h"
 #include "ua_namespace_0.h"
 #include "ua_namespace_0.h"
 #include "ua_util.h"\n''')
 #include "ua_util.h"\n''')