Przeglądaj źródła

refactor the addnodes functions to use services

Julius Pfrommer 9 lat temu
rodzic
commit
b887d06e42

+ 0 - 1
CMakeLists.txt

@@ -113,7 +113,6 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/ua_securechannel.c
                 ${PROJECT_SOURCE_DIR}/src/ua_session.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server.c
-                ${PROJECT_SOURCE_DIR}/src/server/ua_server_addressspace.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_binary.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_nodes.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_server_worker.c

+ 104 - 76
examples/server.c

@@ -225,11 +225,15 @@ int main(int argc, char** argv) {
   // add node with the datetime data source
   UA_NodeId nodeId_currentTime;
   UA_DataSource dateDataSource = (UA_DataSource) {.handle = NULL, .read = readTimeData, .write = NULL};
+  UA_VariableAttributes v_attr;
+  UA_VariableAttributes_init(&v_attr);
+  v_attr.description = UA_LOCALIZEDTEXT("en_US","current time");
+  v_attr.displayName = UA_LOCALIZEDTEXT("en_US","current time");
   const UA_QualifiedName dateName = UA_QUALIFIEDNAME(1, "current time");
-  const UA_LocalizedText dateNameBrowseName = UA_LOCALIZEDTEXT("en_US","current time");
-  UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, dateName, dateNameBrowseName, dateNameBrowseName, 0, 0,
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                  dateDataSource, &nodeId_currentTime);
+  UA_Server_addDataSourceVariableNode(server, &UA_EXPANDEDNODEID_NULL,
+                                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                      &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                      &dateName, NULL, &v_attr, &dateDataSource);
 
   // Get and reattach the datasource
   UA_DataSource dataSourceCopy;
@@ -239,18 +243,21 @@ int main(int argc, char** argv) {
   else
     UA_Server_setNodeAttribute_value_dataSource(server, nodeId_currentTime, dataSourceCopy);
 #ifndef _WIN32
-  //cpu temperature monitoring for linux machines
+  /* cpu temperature monitoring for linux machines */
   if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))) {
           // add node with the data source
           UA_DataSource temperatureDataSource = (UA_DataSource) {.handle = NULL, .read = readTemperature, .write = NULL};
           const UA_QualifiedName tempName = UA_QUALIFIEDNAME(1, "cpu temperature");
-          const UA_LocalizedText tempNameBrowseName = UA_LOCALIZEDTEXT("en_US","temperature");
-          UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, tempName, tempNameBrowseName, tempNameBrowseName, 0, 0,
-                                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                            temperatureDataSource, NULL);
+          UA_VariableAttributes_init(&v_attr);
+          v_attr.description = UA_LOCALIZEDTEXT("en_US","temperature");
+          v_attr.displayName = UA_LOCALIZEDTEXT("en_US","temperature");
+          UA_Server_addDataSourceVariableNode(server, &UA_EXPANDEDNODEID_NULL,
+                                              &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                              &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                              &tempName, NULL, &v_attr, &temperatureDataSource);
   }
 
-  //LED control for rpi
+  /* LED control for rpi */
   if(access("/sys/class/leds/led0/trigger", F_OK ) != -1 || access("/sys/class/leds/led0/brightness", F_OK ) != -1) {
     if((triggerFile = fopen("/sys/class/leds/led0/trigger", "w")) && (ledFile = fopen("/sys/class/leds/led0/brightness", "w"))) {
       //setting led mode to manual
@@ -263,88 +270,112 @@ int main(int argc, char** argv) {
 
       // add node with the LED status data source
       UA_DataSource ledStatusDataSource = (UA_DataSource) {.handle = NULL, .read = readLedStatus, .write = writeLedStatus};
+      UA_VariableAttributes_init(&v_attr);
+      v_attr.description = UA_LOCALIZEDTEXT("en_US","status LED");
+      v_attr.displayName = UA_LOCALIZEDTEXT("en_US","status LED");
       const UA_QualifiedName statusName = UA_QUALIFIEDNAME(0, "status LED");
-      const UA_LocalizedText statusNameBrowseName = UA_LOCALIZEDTEXT("en_US","status LED");
-      UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, statusName, statusNameBrowseName, statusNameBrowseName, 0, 0,
-
-                                        UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-
-                                        ledStatusDataSource,
-
-                                        NULL);
-    } else {
-      UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "[Raspberry Pi] LED file exist, but I have no access (try to run server with sudo)");
-    }
+      UA_Server_addDataSourceVariableNode(server, &UA_EXPANDEDNODEID_NULL,
+                                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                          &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                          &statusName, NULL, &v_attr, &ledStatusDataSource);
+    } else
+      UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND,
+                     "[Raspberry Pi] LED file exist, but is not accessible (try to run server with sudo)");
   }
 #endif
 
   // add a static variable node to the adresspace
-  UA_Variant *myIntegerVariant = UA_Variant_new();
+  UA_VariableAttributes myVar;
+  UA_VariableAttributes_init(&myVar);
+  myVar.description = UA_LOCALIZEDTEXT("en_US", "the answer");
+  myVar.displayName = UA_LOCALIZEDTEXT("en_US", "the answer");
   UA_Int32 myInteger = 42;
-  UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+  UA_Variant_setScalarCopy(&myVar.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
   const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-  const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
-  UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+  const UA_ExpandedNodeId myIntegerNodeId = UA_EXPANDEDNODEID_STRING(1, "the.answer");
+  UA_ExpandedNodeId parentNodeId = UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
   UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-  UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, UA_LOCALIZEDTEXT("en_US", "the answer"), UA_LOCALIZEDTEXT("en_US", "the answer"),  0, 0,
-                            parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
+  UA_Server_addVariableNode(server, &myIntegerNodeId, &parentNodeId, &parentReferenceNodeId,
+                            &myIntegerName, NULL, &myVar);
+  UA_Variant_deleteMembers(&myVar.value);
+
   /**************/
   /* Demo Nodes */
   /**************/
 
 #define DEMOID 50000
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, DEMOID), UA_QUALIFIEDNAME(1, "Demo"), UA_LOCALIZEDTEXT("en_US","Demo"),
-                          UA_LOCALIZEDTEXT("en_US","Demo"), 0, 0, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
+  UA_ObjectAttributes object_attr;
+  UA_ObjectAttributes_init(&object_attr);
+  object_attr.description = UA_LOCALIZEDTEXT("en_US","Demo");
+  object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Demo");
+  UA_Server_addObjectNode(server, &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID),
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                          &UA_QUALIFIEDNAME(1, "Demo"), NULL, &object_attr);
 
 #define SCALARID 50001
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, SCALARID), UA_QUALIFIEDNAME(1, "Scalar"), UA_LOCALIZEDTEXT("en_US","Scalar"),
-                          UA_LOCALIZEDTEXT("en_US","Scalar"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
+  object_attr.description = UA_LOCALIZEDTEXT("en_US","Scalar");
+  object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Scalar");
+  UA_Server_addObjectNode(server, &UA_EXPANDEDNODEID_NUMERIC(1, SCALARID),
+                          &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID), &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                          &UA_QUALIFIEDNAME(1, "Scalar"), NULL, &object_attr);
 
 #define ARRAYID 50002
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, ARRAYID), UA_QUALIFIEDNAME(1, "Array"), UA_LOCALIZEDTEXT("en_US","Array"),
-                          UA_LOCALIZEDTEXT("en_US","Array"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
+  object_attr.description = UA_LOCALIZEDTEXT("en_US","Array");
+  object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Array");
+  UA_Server_addObjectNode(server, &UA_EXPANDEDNODEID_NUMERIC(1, ARRAYID),
+                          &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID), &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                          &UA_QUALIFIEDNAME(1, "Array"), NULL, &object_attr);
 
 #define MATRIXID 50003
-  UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, MATRIXID), UA_QUALIFIEDNAME(1, "Matrix"), UA_LOCALIZEDTEXT("en_US","Matrix"),
-                          UA_LOCALIZEDTEXT("en_US","Matrix"), 0, 0, UA_NODEID_NUMERIC(1, DEMOID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), NULL);
+  object_attr.description = UA_LOCALIZEDTEXT("en_US","Matrix");
+  object_attr.displayName = UA_LOCALIZEDTEXT("en_US","Matrix");
+  UA_Server_addObjectNode(server, &UA_EXPANDEDNODEID_NUMERIC(1, MATRIXID),
+                          &UA_EXPANDEDNODEID_NUMERIC(1, DEMOID), &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                          &UA_QUALIFIEDNAME(1, "Matrix"), NULL, &object_attr);
 
-  UA_UInt32 id = 51000; //running id in namespace 0
+  UA_UInt32 id = 51000; // running id in namespace 0
   for(UA_UInt32 type = 0; UA_IS_BUILTIN(type); type++) {
     if(type == UA_TYPES_VARIANT || type == UA_TYPES_DIAGNOSTICINFO)
         continue;
-    //add a scalar node for every built-in type
-    void *value = UA_new(&UA_TYPES[type]);
-    UA_Variant *variant = UA_Variant_new();
-    UA_Variant_setScalar(variant, value, &UA_TYPES[type]);
+
+    UA_VariableAttributes attr;
+    UA_VariableAttributes_init(&attr);
     char name[15];
     sprintf(name, "%02d", type);
+    attr.displayName = UA_LOCALIZEDTEXT("en_US",name);
     UA_QualifiedName qualifiedName = UA_QUALIFIEDNAME(1, name);
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name), 0, 0,
-                              UA_NODEID_NUMERIC(1, SCALARID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), variant, NULL);
-
-    //add an array node for every built-in type
-    UA_Variant *arrayvar = UA_Variant_new();
-    UA_Variant_setArray(arrayvar, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name), 0, 0,
-                              UA_NODEID_NUMERIC(1, ARRAYID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), arrayvar, NULL);
 
-    //add an matrix node for every built-in type
-    arrayvar = UA_Variant_new();
+    /* add a scalar node for every built-in type */
+    void *value = UA_new(&UA_TYPES[type]);
+    UA_Variant_setScalar(&attr.value, value, &UA_TYPES[type]);
+    UA_Server_addVariableNode(server, &UA_EXPANDEDNODEID_NUMERIC(1, ++id),
+                              &UA_EXPANDEDNODEID_NUMERIC(1, SCALARID),
+                              &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                              &qualifiedName, NULL, &attr);
+    UA_Variant_deleteMembers(&attr.value);
+
+    /* add an array node for every built-in type */
+    UA_Variant_setArray(&attr.value, UA_Array_new(&UA_TYPES[type], 10), 10, &UA_TYPES[type]);
+    UA_Server_addVariableNode(server, &UA_EXPANDEDNODEID_NUMERIC(1, ++id),
+                              &UA_EXPANDEDNODEID_NUMERIC(1, ARRAYID),
+                              &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                              &qualifiedName, NULL, &attr);
+    UA_Variant_deleteMembers(&attr.value);
+
+    /* add an matrix node for every built-in type */
     void* myMultiArray = UA_Array_new(&UA_TYPES[type],9);
-    arrayvar->arrayDimensions = UA_Array_new(&UA_TYPES[UA_TYPES_INT32],2);
-    arrayvar->arrayDimensions[0] = 3;
-    arrayvar->arrayDimensions[1] = 3;
-    arrayvar->arrayDimensionsSize = 2;
-    arrayvar->arrayLength = 9;
-    arrayvar->data = myMultiArray;
-    arrayvar->type = &UA_TYPES[type];
-    UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, ++id), qualifiedName, UA_LOCALIZEDTEXT("en_US",name), UA_LOCALIZEDTEXT("en_US",name),
-                              0, 0, UA_NODEID_NUMERIC(1, MATRIXID), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), arrayvar, NULL);
+    attr.value.arrayDimensions = UA_Array_new(&UA_TYPES[UA_TYPES_INT32],2);
+    attr.value.arrayDimensions[0] = 3;
+    attr.value.arrayDimensions[1] = 3;
+    attr.value.arrayDimensionsSize = 2;
+    attr.value.arrayLength = 9;
+    attr.value.data = myMultiArray;
+    attr.value.type = &UA_TYPES[type];
+    UA_Server_addVariableNode(server, &UA_EXPANDEDNODEID_NUMERIC(1, ++id),
+                              &UA_EXPANDEDNODEID_NUMERIC(1, MATRIXID),
+                              &UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                              &qualifiedName, NULL, &attr);
+    UA_Variant_deleteMembers(&attr.value);
   }
 
 #ifdef ENABLE_METHODCALLS
@@ -366,20 +397,17 @@ int main(int argc, char** argv) {
   outputArguments.name = UA_STRING("Input an integer");
   outputArguments.valueRank = -1;
 
-  UA_NodeId methodId; // Retrieve the actual ID if this node if a random id as in UA_NODEID_NUMERIC(1,0) is used
-  UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541), UA_QUALIFIEDNAME(1,"ping"), UA_LOCALIZEDTEXT("en_US", "ping"),
-                          UA_LOCALIZEDTEXT("en_US", "Return a single argument as passed by the caller"),
-                          UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                          0, 0,
+  UA_NodeAttributes addmethodattributes;
+  UA_NodeAttributes_init(&addmethodattributes);
+  addmethodattributes.description = UA_LOCALIZEDTEXT("en_US", "Return a single argument as passed by the caller");
+  addmethodattributes.displayName = UA_LOCALIZEDTEXT("en_US", "ping");
+  UA_Server_addMethodNode(server, &UA_EXPANDEDNODEID_NUMERIC(1,62541),
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                          &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                          &UA_QUALIFIEDNAME(1,"ping"), &addmethodattributes,
                           &getMonitoredItems, // Call this method
                           (void *) server,    // Pass our server pointer as a handle to the method
-                          1, &inputArguments, 1, &outputArguments, &methodId);
-  
-  // Dettach the method from the methodNode
-  UA_Server_setNodeAttribute_method(server, UA_NODEID_NUMERIC(1,62541), NULL, NULL);
-  
-  // Reaettach the method from the methodNode
-  UA_Server_setNodeAttribute_method(server, UA_NODEID_NUMERIC(1,62541), &getMonitoredItems, (void *) server);
+                          1, &inputArguments, 1, &outputArguments);
 #endif
    
   // Example for iterating over all nodes referenced by "Objects":

+ 79 - 114
include/ua_server.h

@@ -130,8 +130,8 @@ typedef struct {
 UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
 
 /** Add a reference to the server's address space */
-UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
-                                               const UA_NodeId refTypeId, const UA_ExpandedNodeId targetId);
+UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_NodeId *sourceId,
+                                               const UA_NodeId *refTypeId, const UA_ExpandedNodeId *targetId);
 
 /** Deletes a node from the nodestore.
  *
@@ -142,82 +142,76 @@ UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_NodeI
  */
 UA_StatusCode UA_EXPORT UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId);
 
-/** A new variable Node with a value passed in variant.
- *
- * @param server The server object
- * @param nodeId        The requested nodeId of the new node. Use the numeric id with i=0 to get a new ID from the server.
- * @param browseName    The qualified name of this node
- * @param displayName   The localized text shown when displaying the node
- * @param description   The localized human readable description
- * @param userWriteMask Bitmask defining the user write permissions
- * @param writeMask     Bitmask defining the write permissions
- * @param parentNodeId  The node under which this node exists ("parent")
- * @param referenceTypeId Reference type used by the parent to reference this node
- * @param value         A variant containing the value to be assigned to this node.
- * @param createdNodeId Pointer to a NULL pointer that will hold the copy of the nodeId on a successfull return.
- * @return Return UA_STATUSCODE_GOOD if the node was created or an appropriate error code if not.
- */
-UA_StatusCode UA_EXPORT
-UA_Server_addVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                          const UA_LocalizedText displayName, const UA_LocalizedText description,
-						  const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                          UA_Variant *value, UA_NodeId *createdNodeId);
-
-// Missing: eventNotifier
-UA_StatusCode UA_EXPORT
-UA_Server_addObjectNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        const UA_LocalizedText displayName, const UA_LocalizedText description,
-						const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                        const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId);
-
-// Missing: isAbstract, symmetric
-UA_StatusCode UA_EXPORT 
-UA_Server_addReferenceTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                               const UA_LocalizedText displayName, const UA_LocalizedText description,
-							   const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                               const UA_ExpandedNodeId typeDefinition, const UA_LocalizedText inverseName,
-                               UA_NodeId *createdNodeId );
-
-UA_StatusCode UA_EXPORT
-UA_Server_addObjectTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                            const UA_LocalizedText displayName, const UA_LocalizedText description,
-							const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                            const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                            const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
-                            UA_NodeId *createdNodeId );
-
-UA_StatusCode UA_EXPORT 
-UA_Server_addVariableTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                              const UA_LocalizedText displayName, const UA_LocalizedText description,
-							  const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                              UA_Variant *value, const UA_Int32 valueRank, const UA_Boolean isAbstract,
-                              UA_NodeId *createdNodeId);
-
-UA_StatusCode UA_EXPORT
-UA_Server_addDataTypeNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                          const UA_LocalizedText displayName, const UA_LocalizedText description,
-						  const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                          const UA_ExpandedNodeId typeDefinition, const UA_Boolean isAbstract,
-                          UA_NodeId *createdNodeId);
-
-
-UA_StatusCode UA_EXPORT
-UA_Server_addViewNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                      const UA_LocalizedText displayName, const UA_LocalizedText description,
-					  const UA_UInt32 userWriteMask, const UA_UInt32 writeMask,
-                      const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                      const UA_ExpandedNodeId typeDefinition, UA_NodeId *createdNodeId);
-
-UA_StatusCode UA_EXPORT
-UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                                    const UA_LocalizedText displayName, const UA_LocalizedText description,
-									const UA_UInt32 userWriteMask, const UA_UInt32 writeMask, const UA_NodeId parentNodeId,
-                                    const UA_NodeId referenceTypeId, const UA_DataSource dataSource, UA_NodeId *createdNodeId);
+/* Don't use this function. There are typed versions as inline functions. */
+UA_AddNodesResult UA_EXPORT
+UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_ExpandedNodeId *requestedNewNodeId,
+                  const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                  const UA_QualifiedName *browseName, const UA_ExpandedNodeId *typeDefinition,
+                  const UA_NodeAttributes *attr, const UA_DataType *attributeType);
+
+static inline UA_AddNodesResult
+UA_Server_addVariableNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_QualifiedName *browseName, const UA_ExpandedNodeId *typeDefinition,
+                          const UA_VariableAttributes *attr) {
+    return UA_Server_addNode(server, UA_NODECLASS_VARIABLE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)attr,
+                             &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]); }
+
+static inline UA_AddNodesResult
+UA_Server_addVariableTypeNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_QualifiedName *browseName, const UA_VariableTypeAttributes *attr) {
+    return UA_Server_addNode(server, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, NULL, (const UA_NodeAttributes*)attr,
+                             &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]); }
+
+static inline UA_AddNodesResult
+UA_Server_addObjectNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_QualifiedName *browseName, const UA_ExpandedNodeId *typeDefinition,
+                          const UA_ObjectAttributes *attr) {
+    return UA_Server_addNode(server, UA_NODECLASS_OBJECT, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, typeDefinition, (const UA_NodeAttributes*)attr,
+                             &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES]); }
+
+static inline UA_AddNodesResult
+UA_Server_addObjectTypeNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_QualifiedName *browseName, const UA_ObjectTypeAttributes *attr) {
+    return UA_Server_addNode(server, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, NULL, (const UA_NodeAttributes*)attr,
+                             &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]); }
+
+static inline UA_AddNodesResult
+UA_Server_addViewNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_QualifiedName *browseName, const UA_ViewAttributes *attr) {
+    return UA_Server_addNode(server, UA_NODECLASS_VIEW, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, NULL, (const UA_NodeAttributes*)attr,
+                             &UA_TYPES[UA_TYPES_VIEWATTRIBUTES]); }
+
+static inline UA_AddNodesResult
+UA_Server_addReferenceTypeNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_QualifiedName *browseName, const UA_ReferenceTypeAttributes *attr) {
+    return UA_Server_addNode(server, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, NULL, (const UA_NodeAttributes*)attr,
+                             &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); }
+
+static inline UA_AddNodesResult
+UA_Server_addDataTypeNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_QualifiedName *browseName, const UA_DataTypeAttributes *attr) {
+    return UA_Server_addNode(server, UA_NODECLASS_DATATYPE, requestedNewNodeId, parentNodeId,
+                             referenceTypeId, browseName, NULL, (const UA_NodeAttributes*)attr,
+                             &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]); }
+
+UA_AddNodesResult UA_EXPORT
+UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                                    const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                                    const UA_QualifiedName *browseName, const UA_ExpandedNodeId *typeDefinition,
+                                    const UA_VariableAttributes *attr, const UA_DataSource *dataSource);
 
 UA_StatusCode UA_EXPORT
 UA_Server_addMonodirectionalReference(UA_Server *server, UA_NodeId sourceNodeId,
@@ -227,42 +221,13 @@ UA_Server_addMonodirectionalReference(UA_Server *server, UA_NodeId sourceNodeId,
 #ifdef ENABLE_METHODCALLS
 typedef UA_StatusCode (*UA_MethodCallback)(const UA_NodeId objectId, const UA_Variant *input,
                                            UA_Variant *output, void *handle);
-/** Creates a serverside method including input- and output variable descriptions
- * 
- * @param server The server object.
- * 
- * @param browseName BrowseName to be used for the new method.
- * 
- * @param nodeId Requested NodeId for the new method. If a numeric ID with i=0 is used, the server
- * will assign a random unused id.
- * 
- * @param parentNodeId Parent node containing this method. Note that an ObjectNode needs to
- * reference the method with hasProperty in order for the method to be callable.
- * 
- * @param referenceTypeId Reference type ID to be used by the parent to reference the new method.
- * 
- * @param method Userspace Method/Function of type UA_MethodCallback to be called when a client
- * invokes the method using the Call Service Set.
- * 
- * @param inputArgumentsSize Number of input arguments expected to be passed by a calling client.
- * 
- * @param inputArguments Description of input arguments expected to be passed by a calling client.
- * 
- * @param outputArgumentsSize Description of output arguments expected to be passed by a calling client.
- * 
- * @param outputArguments Description of output arguments expected to be passed by a calling client.
- * 
- * @param createdNodeId Actual nodeId of the new method node if UA_StatusCode indicates success. Can
- * be used to determine the random unique ID assigned by the server if i=0 was passed as a nodeId.
- * 
- */
-UA_StatusCode UA_EXPORT
-UA_Server_addMethodNode(UA_Server *server, const UA_NodeId nodeId, const UA_QualifiedName browseName,
-                        UA_LocalizedText displayName, UA_LocalizedText description, const UA_NodeId parentNodeId, 
-                        const UA_NodeId referenceTypeId, UA_UInt32 userWriteMask, UA_UInt32 writeMask, 
-                        UA_MethodCallback method, void *handle, UA_Int32 inputArgumentsSize, const UA_Argument *inputArguments, 
-                        UA_Int32 outputArgumentsSize, const UA_Argument *outputArguments,
-                        UA_NodeId *createdNodeId);
+UA_AddNodesResult UA_EXPORT
+UA_Server_addMethodNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                        const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                        const UA_QualifiedName *browseName, const UA_NodeAttributes *attr,
+                        UA_MethodCallback method, void *handle,
+                        UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
+                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments);
 #endif
 
 #ifndef _HAVE_UA_NODEITERATORCALLBACK_D

+ 11 - 1
include/ua_types.h

@@ -392,7 +392,9 @@ UA_NodeId UA_EXPORT UA_NodeId_fromCharByteString(UA_UInt16 nsIndex, char identif
 UA_NodeId UA_EXPORT UA_NodeId_fromCharByteStringCopy(UA_UInt16 nsIndex, char const identifier[]);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteString(UA_UInt16 nsIndex, UA_ByteString identifier);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteString identifier);
-#define UA_NODEID_NUMERIC(NSID, NUMERICID) UA_NodeId_fromInteger(NSID, NUMERICID)
+#define UA_NODEID_NUMERIC(NSID, NUMERICID) (UA_NodeId){                 \
+        .namespaceIndex = NSID, .identifierType = UA_NODEIDTYPE_NUMERIC, \
+            .identifier.numeric = NUMERICID }
 #define UA_NODEID_STRING(NSID, CHARS) UA_NodeId_fromCharString(NSID, CHARS)
 #define UA_NODEID_STRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharStringCopy(NSID, CHARS)
 #define UA_NODEID_GUID(NSID, GUID) UA_NodeId_fromGuid(NSID, GUID)
@@ -411,6 +413,14 @@ UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
         .nodeId = {.namespaceIndex = NSID, .identifierType = UA_NODEIDTYPE_NUMERIC, \
                    .identifier.numeric = NUMERICID },                               \
         .serverIndex = 0, .namespaceUri = {.data = (UA_Byte*)0, .length = -1} }
+#define UA_EXPANDEDNODEID_STRING(NSID, CHARS) (UA_ExpandedNodeId) { \
+        .nodeId = {.namespaceIndex = NSID, .identifierType = UA_NODEIDTYPE_STRING, \
+                   .identifier.string = {strlen(CHARS), (UA_Byte*)CHARS} }, \
+            .serverIndex = 0, .namespaceUri = {.data = (UA_Byte*)0, .length = -1} }
+#define UA_EXPANDEDNODEID_NULL (UA_ExpandedNodeId) {                    \
+        .nodeId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, \
+                   .identifier.numeric = 0 },                           \
+            .serverIndex = 0, .namespaceUri = {.data = (UA_Byte*)0, .length = -1} }
 
 /* StatusCode */
 UA_StatusCode UA_EXPORT * UA_StatusCode_new(void);

+ 221 - 169
src/server/ua_server.c

@@ -99,6 +99,74 @@ UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
     return ((UA_UInt16)server->namespacesSize - 1);
 }
 
+UA_StatusCode UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
+    return Service_DeleteNodes_single(server, &adminSession, nodeId, UA_TRUE);
+}
+
+UA_StatusCode UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
+                                             UA_NodeIteratorCallback callback, void *handle) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId);
+    if(!parent)
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    
+    for(int i=0; i<parent->referencesSize; i++) {
+        UA_ReferenceNode *ref = &parent->references[i];
+        retval |= callback(ref->targetId.nodeId, ref->isInverse, ref->referenceTypeId, handle);
+    }
+    
+    UA_NodeStore_release(parent);
+    return retval;
+}
+
+UA_StatusCode
+UA_Server_addReference(UA_Server *server, const UA_NodeId *sourceId, const UA_NodeId *refTypeId,
+                       const UA_ExpandedNodeId *targetId) {
+    UA_AddReferencesItem item;
+    UA_AddReferencesItem_init(&item);
+    item.sourceNodeId = *sourceId;
+    item.referenceTypeId = *refTypeId;
+    item.isForward = UA_TRUE;
+    item.targetNodeId = *targetId;
+    return Service_AddReferences_single(server, &adminSession, (const UA_AddReferencesItem*)&item);
+}
+
+static UA_AddNodesResult
+addNodeInternal(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId *parentNodeId,
+                const UA_NodeId *referenceTypeId) {
+    UA_AddNodesResult res;
+    UA_AddNodesResult_init(&res);
+    Service_AddNodes_single(server, &adminSession, node, parentNodeId, referenceTypeId, &res);
+    return res;
+}
+
+UA_AddNodesResult
+UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_ExpandedNodeId *requestedNewNodeId,
+                  const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                  const UA_QualifiedName *browseName, const UA_ExpandedNodeId *typeDefinition,
+                  const UA_NodeAttributes *attr, const UA_DataType *attributeType) {
+    UA_AddNodesResult result;
+    UA_AddNodesResult_init(&result);
+
+    UA_AddNodesItem item;
+    UA_AddNodesItem_init(&item);
+    result.statusCode = UA_QualifiedName_copy(browseName, &item.browseName);
+    item.nodeClass = nodeClass;
+    result.statusCode |= UA_ExpandedNodeId_copy(parentNodeId, &item.parentNodeId);
+    result.statusCode |= UA_NodeId_copy(referenceTypeId, &item.referenceTypeId);
+    result.statusCode |= UA_ExpandedNodeId_copy(requestedNewNodeId, &item.requestedNewNodeId);
+    if(typeDefinition)
+        result.statusCode |= UA_ExpandedNodeId_copy(typeDefinition, &item.typeDefinition);
+    UA_NodeAttributes *attrCopy = UA_alloca(attributeType->memSize);
+    result.statusCode |= UA_copy(attr, attrCopy, attributeType);
+    if(result.statusCode == UA_STATUSCODE_GOOD)
+        Service_AddNodes_single_fromAttributes(server, &adminSession, &item, attrCopy, attributeType, &result);
+
+    UA_AddNodesItem_deleteMembers(&item);
+    UA_deleteMembers(attrCopy, attributeType);
+    return result;
+}
+
 /*****************/
 /* Configuration */
 /*****************/
@@ -287,7 +355,7 @@ static void addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid,
     UA_DataTypeNode *datatype = UA_DataTypeNode_new();
     copyNames((UA_Node*)datatype, name);
     datatype->nodeId.identifier.numeric = datatypeid;
-    UA_Server_addNode(server, (UA_Node*)datatype, UA_EXPANDEDNODEID_NUMERIC(0, parent), nodeIdOrganizes);
+    addNodeInternal(server, (UA_Node*)datatype, &UA_EXPANDEDNODEID_NUMERIC(0, parent), &nodeIdOrganizes);
 }
 
 static void addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid, UA_Int32 parent,
@@ -295,8 +363,8 @@ static void addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttyp
     UA_ObjectTypeNode *objecttype = UA_ObjectTypeNode_new();
     copyNames((UA_Node*)objecttype, name);
     objecttype->nodeId.identifier.numeric = objecttypeid;
-    UA_Server_addNode(server, (UA_Node*)objecttype, UA_EXPANDEDNODEID_NUMERIC(0, parent),
-                      UA_NODEID_NUMERIC(0, parentreference));
+    addNodeInternal(server, (UA_Node*)objecttype, &UA_EXPANDEDNODEID_NUMERIC(0, parent),
+                      &UA_NODEID_NUMERIC(0, parentreference));
 }
 
 static UA_VariableTypeNode*
@@ -313,15 +381,13 @@ createVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
 static void addVariableTypeNode_organized(UA_Server *server, char* name, UA_UInt32 variabletypeid,
                                           UA_Int32 parent, UA_Boolean abstract) {
     UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
-    UA_Server_addNode(server, (UA_Node*)variabletype, UA_EXPANDEDNODEID_NUMERIC(0, parent), nodeIdOrganizes);
+    addNodeInternal(server, (UA_Node*)variabletype, &UA_EXPANDEDNODEID_NUMERIC(0, parent), &nodeIdOrganizes);
 }
 
 static void addVariableTypeNode_subtype(UA_Server *server, char* name, UA_UInt32 variabletypeid,
                                         UA_Int32 parent, UA_Boolean abstract) {
     UA_VariableTypeNode *variabletype = createVariableTypeNode(server, name, variabletypeid, parent, abstract);
-    UA_Server_addNode(server, (UA_Node*)variabletype,
-                      UA_EXPANDEDNODEID_NUMERIC(0, parent),
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)variabletype, &UA_EXPANDEDNODEID_NUMERIC(0, parent), &nodeIdHasSubType);
 }
 
 UA_Server * UA_Server_new(UA_ServerConfig config) {
@@ -504,24 +570,24 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_HIERARCHICALREFERENCES;
     hierarchicalreferences->isAbstract = UA_TRUE;
     hierarchicalreferences->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hierarchicalreferences,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hierarchicalreferences,
+                    &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *nonhierarchicalreferences = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)nonhierarchicalreferences, "NonHierarchicalReferences");
     nonhierarchicalreferences->nodeId.identifier.numeric = UA_NS0ID_NONHIERARCHICALREFERENCES;
     nonhierarchicalreferences->isAbstract = UA_TRUE;
     nonhierarchicalreferences->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)nonhierarchicalreferences,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)nonhierarchicalreferences,
+                    &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *haschild = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haschild, "HasChild");
     haschild->nodeId.identifier.numeric = UA_NS0ID_HASCHILD;
     haschild->isAbstract = UA_TRUE;
     haschild->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)haschild,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)haschild,
+                    &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *organizes = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)organizes, "Organizes");
@@ -529,8 +595,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     organizes->nodeId.identifier.numeric = UA_NS0ID_ORGANIZES;
     organizes->isAbstract = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)organizes,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)organizes,
+                    &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *haseventsource = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haseventsource, "HasEventSource");
@@ -538,8 +604,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     haseventsource->nodeId.identifier.numeric = UA_NS0ID_HASEVENTSOURCE;
     haseventsource->isAbstract = UA_FALSE;
     haseventsource->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)haseventsource,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)haseventsource,
+                    &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasmodellingrule = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasmodellingrule, "HasModellingRule");
@@ -547,8 +613,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasmodellingrule->nodeId.identifier.numeric = UA_NS0ID_HASMODELLINGRULE;
     hasmodellingrule->isAbstract = UA_FALSE;
     hasmodellingrule->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hasmodellingrule, expandedNodeIdNonHierarchicalReferences,
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasmodellingrule, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasencoding = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasencoding, "HasEncoding");
@@ -556,7 +621,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasencoding->nodeId.identifier.numeric = UA_NS0ID_HASENCODING;
     hasencoding->isAbstract = UA_FALSE;
     hasencoding->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hasencoding, expandedNodeIdNonHierarchicalReferences, nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasencoding, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasdescription = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasdescription, "HasDescription");
@@ -564,8 +629,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasdescription->nodeId.identifier.numeric = UA_NS0ID_HASDESCRIPTION;
     hasdescription->isAbstract = UA_FALSE;
     hasdescription->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hasdescription, expandedNodeIdNonHierarchicalReferences,
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasdescription, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hastypedefinition = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hastypedefinition, "HasTypeDefinition");
@@ -573,8 +637,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hastypedefinition->nodeId.identifier.numeric = UA_NS0ID_HASTYPEDEFINITION;
     hastypedefinition->isAbstract = UA_FALSE;
     hastypedefinition->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hastypedefinition, expandedNodeIdNonHierarchicalReferences,
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hastypedefinition, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *generatesevent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)generatesevent, "GeneratesEvent");
@@ -582,8 +645,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     generatesevent->nodeId.identifier.numeric = UA_NS0ID_GENERATESEVENT;
     generatesevent->isAbstract = UA_FALSE;
     generatesevent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)generatesevent, expandedNodeIdNonHierarchicalReferences,
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)generatesevent, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *aggregates = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)aggregates, "Aggregates");
@@ -591,12 +653,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     aggregates->nodeId.identifier.numeric = UA_NS0ID_AGGREGATES;
     aggregates->isAbstract = UA_TRUE;
     aggregates->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)aggregates, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCHILD),
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)aggregates, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCHILD), &nodeIdHasSubType);
 
     // complete bootstrap of hassubtype
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), &nodeIdHasSubType,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     UA_ReferenceTypeNode *hasproperty = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasproperty, "HasProperty");
@@ -604,8 +665,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasproperty->nodeId.identifier.numeric = UA_NS0ID_HASPROPERTY;
     hasproperty->isAbstract = UA_FALSE;
     hasproperty->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hasproperty, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasproperty, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hascomponent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hascomponent, "HasComponent");
@@ -613,8 +673,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hascomponent->nodeId.identifier.numeric = UA_NS0ID_HASCOMPONENT;
     hascomponent->isAbstract = UA_FALSE;
     hascomponent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hascomponent, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES),
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hascomponent, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasnotifier = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasnotifier, "HasNotifier");
@@ -622,8 +681,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasnotifier->nodeId.identifier.numeric = UA_NS0ID_HASNOTIFIER;
     hasnotifier->isAbstract = UA_FALSE;
     hasnotifier->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hasnotifier, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE),
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasnotifier, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasorderedcomponent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasorderedcomponent, "HasOrderedComponent");
@@ -631,8 +689,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasorderedcomponent->nodeId.identifier.numeric = UA_NS0ID_HASORDEREDCOMPONENT;
     hasorderedcomponent->isAbstract = UA_FALSE;
     hasorderedcomponent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hasorderedcomponent,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasorderedcomponent, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasmodelparent = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hasmodelparent, "HasModelParent");
@@ -640,8 +697,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hasmodelparent->nodeId.identifier.numeric = UA_NS0ID_HASMODELPARENT;
     hasmodelparent->isAbstract = UA_FALSE;
     hasmodelparent->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hasmodelparent, expandedNodeIdNonHierarchicalReferences,
-                      nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasmodelparent, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *fromstate = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)fromstate, "FromState");
@@ -649,7 +705,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     fromstate->nodeId.identifier.numeric = UA_NS0ID_FROMSTATE;
     fromstate->isAbstract = UA_FALSE;
     fromstate->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)fromstate, expandedNodeIdNonHierarchicalReferences, nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)fromstate, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *tostate = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)tostate, "ToState");
@@ -657,7 +713,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     tostate->nodeId.identifier.numeric = UA_NS0ID_TOSTATE;
     tostate->isAbstract = UA_FALSE;
     tostate->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)tostate, expandedNodeIdNonHierarchicalReferences, nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)tostate, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hascause = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hascause, "HasCause");
@@ -665,7 +721,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hascause->nodeId.identifier.numeric = UA_NS0ID_HASCAUSE;
     hascause->isAbstract = UA_FALSE;
     hascause->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hascause, expandedNodeIdNonHierarchicalReferences, nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hascause, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
     
     UA_ReferenceTypeNode *haseffect = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)haseffect, "HasEffect");
@@ -673,7 +729,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     haseffect->nodeId.identifier.numeric = UA_NS0ID_HASEFFECT;
     haseffect->isAbstract = UA_FALSE;
     haseffect->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)haseffect, expandedNodeIdNonHierarchicalReferences, nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)haseffect, &expandedNodeIdNonHierarchicalReferences, &nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hashistoricalconfiguration = UA_ReferenceTypeNode_new();
     copyNames((UA_Node*)hashistoricalconfiguration, "HasHistoricalConfiguration");
@@ -681,8 +737,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hashistoricalconfiguration->nodeId.identifier.numeric = UA_NS0ID_HASHISTORICALCONFIGURATION;
     hashistoricalconfiguration->isAbstract = UA_FALSE;
     hashistoricalconfiguration->symmetric  = UA_FALSE;
-    UA_Server_addNode(server, (UA_Node*)hashistoricalconfiguration,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hashistoricalconfiguration,
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), &nodeIdHasSubType);
 
     /*****************/
     /* Basic Folders */
@@ -696,29 +752,29 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_ObjectNode *objects = UA_ObjectNode_new();
     copyNames((UA_Node*)objects, "Objects");
     objects->nodeId.identifier.numeric = UA_NS0ID_OBJECTSFOLDER;
-    UA_Server_addNode(server, (UA_Node*)objects, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
-                      nodeIdOrganizes);
+    addNodeInternal(server, (UA_Node*)objects, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+                    &nodeIdOrganizes);
 
     UA_ObjectNode *types = UA_ObjectNode_new();
     copyNames((UA_Node*)types, "Types");
     types->nodeId.identifier.numeric = UA_NS0ID_TYPESFOLDER;
-    UA_Server_addNode(server, (UA_Node*)types, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
-                      nodeIdOrganizes);
+    addNodeInternal(server, (UA_Node*)types, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+                    &nodeIdOrganizes);
 
     UA_ObjectNode *views = UA_ObjectNode_new();
     copyNames((UA_Node*)views, "Views");
     views->nodeId.identifier.numeric = UA_NS0ID_VIEWSFOLDER;
-    UA_Server_addNode(server, (UA_Node*)views, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
-                      nodeIdOrganizes);
+    addNodeInternal(server, (UA_Node*)views, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
+                    &nodeIdOrganizes);
 
     UA_ObjectNode *referencetypes = UA_ObjectNode_new();
     copyNames((UA_Node*)referencetypes, "ReferenceTypes");
     referencetypes->nodeId.identifier.numeric = UA_NS0ID_REFERENCETYPESFOLDER;
-    UA_Server_addNode(server, (UA_Node*)referencetypes, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-                      nodeIdOrganizes);
+    addNodeInternal(server, (UA_Node*)referencetypes, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                    &nodeIdOrganizes);
 
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), nodeIdOrganizes,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), &nodeIdOrganizes,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_REFERENCES));
 
     /**********************/
     /* Basic Object Types */
@@ -727,25 +783,22 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_ObjectNode *objecttypes = UA_ObjectNode_new();
     copyNames((UA_Node*)objecttypes, "ObjectTypes");
     objecttypes->nodeId.identifier.numeric = UA_NS0ID_OBJECTTYPESFOLDER;
-    UA_Server_addNode(server, (UA_Node*)objecttypes,
-        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-        nodeIdOrganizes);
+    addNodeInternal(server, (UA_Node*)objecttypes, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), &nodeIdOrganizes);
 
-    addObjectTypeNode(server, "BaseObjectType", UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER,
-                      UA_NS0ID_ORGANIZES);
+    addObjectTypeNode(server, "BaseObjectType", UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_ORGANIZES);
     addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTTYPESFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTTYPESFOLDER), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
     addObjectTypeNode(server, "ServerType", UA_NS0ID_SERVERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerDiagnosticsType", UA_NS0ID_SERVERDIAGNOSTICSTYPE,
                       UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
@@ -763,10 +816,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     UA_ObjectNode *datatypes = UA_ObjectNode_new();
     copyNames((UA_Node*)datatypes, "DataTypes");
     datatypes->nodeId.identifier.numeric = UA_NS0ID_DATATYPESFOLDER;
-    UA_Server_addNode(server, (UA_Node*)datatypes, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-                      nodeIdOrganizes);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATATYPESFOLDER),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+    addNodeInternal(server, (UA_Node*)datatypes, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                      &nodeIdOrganizes);
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_DATATYPESFOLDER), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
 
     addDataTypeNode(server, "BaseDataType", UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER);
     addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, UA_NS0ID_BASEDATATYPE);
@@ -804,10 +857,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    UA_ObjectNode *variabletypes = UA_ObjectNode_new();
    copyNames((UA_Node*)variabletypes, "VariableTypes");
    variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
-   UA_Server_addNode(server, (UA_Node*)variabletypes, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-                     nodeIdOrganizes);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER), nodeIdHasTypeDefinition,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
+   addNodeInternal(server, (UA_Node*)variabletypes, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                     &nodeIdOrganizes);
+   UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER), &nodeIdHasTypeDefinition,
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE));
    addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE,
                                  UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
    addVariableTypeNode_subtype(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
@@ -828,10 +881,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    UA_ObjectNode *servernode = UA_ObjectNode_new();
    copyNames((UA_Node*)servernode, "Server");
    servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
-   UA_Server_addNode(server, (UA_Node*)servernode, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                     nodeIdOrganizes);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasTypeDefinition,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE));
+   addNodeInternal(server, (UA_Node*)servernode, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                     &nodeIdOrganizes);
+   UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &nodeIdHasTypeDefinition,
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE));
 
    UA_VariableNode *namespaceArray = UA_VariableNode_new();
    copyNames((UA_Node*)namespaceArray, "NamespaceArray");
@@ -841,9 +894,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
                                                        .write = UA_NULL};
    namespaceArray->valueRank = 1;
    namespaceArray->minimumSamplingInterval = 1.0;
-   UA_Server_addNode(server, (UA_Node*)namespaceArray, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), nodeIdHasTypeDefinition,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+   addNodeInternal(server, (UA_Node*)namespaceArray, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), &nodeIdHasProperty);
+   UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), &nodeIdHasTypeDefinition,
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
    UA_VariableNode *serverArray = UA_VariableNode_new();
    copyNames((UA_Node*)serverArray, "ServerArray");
@@ -854,17 +907,17 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    *(UA_String *)serverArray->value.variant.value.data = UA_STRING_ALLOC(server->config.Application_applicationURI);
    serverArray->valueRank = 1;
    serverArray->minimumSamplingInterval = 1.0;
-   UA_Server_addNode(server, (UA_Node*)serverArray, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY),
-                          nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+   addNodeInternal(server, (UA_Node*)serverArray, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), &nodeIdHasProperty);
+   UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), &nodeIdHasTypeDefinition,
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
    UA_ObjectNode *servercapablities = UA_ObjectNode_new();
    copyNames((UA_Node*)servercapablities, "ServerCapabilities");
    servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
-   UA_Server_addNode(server, (UA_Node*)servercapablities, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                     nodeIdHasComponent);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasTypeDefinition,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE));
+   addNodeInternal(server, (UA_Node*)servercapablities, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+                     &nodeIdHasComponent);
+   UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), &nodeIdHasTypeDefinition,
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE));
 
    UA_VariableNode *localeIdArray = UA_VariableNode_new();
    copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
@@ -875,10 +928,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
    *(UA_String *)localeIdArray->value.variant.value.data = UA_STRING_ALLOC("en");
    localeIdArray->valueRank = 1;
    localeIdArray->minimumSamplingInterval = 1.0;
-   UA_Server_addNode(server, (UA_Node*)localeIdArray,
-                     UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY),
-                          nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+   addNodeInternal(server, (UA_Node*)localeIdArray,
+                     &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), &nodeIdHasProperty);
+   UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY),
+                          &nodeIdHasTypeDefinition, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
    UA_VariableNode *maxBrowseContinuationPoints = UA_VariableNode_new();
     copyNames((UA_Node*)maxBrowseContinuationPoints, "MaxBrowseContinuationPoints");
@@ -887,11 +940,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     maxBrowseContinuationPoints->value.variant.value.data = UA_UInt16_new();
     *((UA_UInt16*)maxBrowseContinuationPoints->value.variant.value.data) = MAXCONTINUATIONPOINTS;
     maxBrowseContinuationPoints->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT16];
-    UA_Server_addNode(server, (UA_Node*)maxBrowseContinuationPoints,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
+    addNodeInternal(server, (UA_Node*)maxBrowseContinuationPoints,
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), &nodeIdHasProperty);
     UA_Server_addReference(server,
-                           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+                           &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS),
+                           &nodeIdHasTypeDefinition, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
     /** ServerProfileArray **/
 #define MAX_PROFILEARRAY 16 //a *magic* limit to the number of supported profiles
@@ -921,19 +974,18 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     }
     serverProfileArray->valueRank = 1;
     serverProfileArray->minimumSamplingInterval = 1.0;
-    UA_Server_addNode(server, (UA_Node*)serverProfileArray,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+    addNodeInternal(server, (UA_Node*)serverProfileArray,
+                    &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), &nodeIdHasProperty);
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY),
+                           &nodeIdHasTypeDefinition, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
     UA_ObjectNode *serverdiagnostics = UA_ObjectNode_new();
     copyNames((UA_Node*)serverdiagnostics, "ServerDiagnostics");
     serverdiagnostics->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS;
-    UA_Server_addNode(server, (UA_Node*)serverdiagnostics,
-                      UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
-                           nodeIdHasTypeDefinition,
-                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE));
+    addNodeInternal(server, (UA_Node*)serverdiagnostics,
+                    &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER), &nodeIdHasComponent);
+    UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), &nodeIdHasTypeDefinition,
+                           &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE));
 
     UA_VariableNode *enabledFlag = UA_VariableNode_new();
      copyNames((UA_Node*)enabledFlag, "EnabledFlag");
@@ -942,20 +994,20 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
      enabledFlag->value.variant.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
      enabledFlag->valueRank = 1;
      enabledFlag->minimumSamplingInterval = 1.0;
-     UA_Server_addNode(server, (UA_Node*)enabledFlag,
-                       UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), nodeIdHasProperty);
-     UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
-                            nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
+     addNodeInternal(server, (UA_Node*)enabledFlag,
+                     &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), &nodeIdHasProperty);
+     UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
+                            &nodeIdHasTypeDefinition, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
      UA_VariableNode *serverstatus = UA_VariableNode_new();
       copyNames((UA_Node*)serverstatus, "ServerStatus");
       serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
       serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
       serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus, .write = UA_NULL};
-      UA_Server_addNode(server, (UA_Node*)serverstatus, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                        nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                             nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE));
+      addNodeInternal(server, (UA_Node*)serverstatus, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER),
+                      &nodeIdHasComponent);
+      UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), &nodeIdHasTypeDefinition,
+                             &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE));
 
      UA_VariableNode *starttime = UA_VariableNode_new();
       copyNames((UA_Node*)starttime, "StartTime");
@@ -963,10 +1015,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
       starttime->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
       starttime->value.variant.value.data = &server->startTime;
       starttime->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
-      UA_Server_addNode(server, (UA_Node*)starttime, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                        nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
-                             nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+      addNodeInternal(server, (UA_Node*)starttime, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+                      &nodeIdHasComponent);
+      UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME), &nodeIdHasTypeDefinition,
+                             &expandedNodeIdBaseDataVariabletype);
 
      UA_VariableNode *currenttime = UA_VariableNode_new();
       copyNames((UA_Node*)currenttime, "CurrentTime");
@@ -974,10 +1026,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
       currenttime->valueSource = UA_VALUESOURCE_DATASOURCE;
       currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
                                                        .write = UA_NULL};
-      UA_Server_addNode(server, (UA_Node*)currenttime,
-                        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
-                             nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+      addNodeInternal(server, (UA_Node*)currenttime,
+                      &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), &nodeIdHasComponent);
+      UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), &nodeIdHasTypeDefinition,
+                             &expandedNodeIdBaseDataVariabletype);
 
      UA_VariableNode *state = UA_VariableNode_new();
      UA_ServerState *stateEnum = UA_ServerState_new();
@@ -987,10 +1039,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
       state->value.variant.value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
       state->value.variant.value.arrayLength = -1;
       state->value.variant.value.data = stateEnum; // points into the other object.
-      UA_Server_addNode(server, (UA_Node*)state, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                        nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE),
-                             nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+      addNodeInternal(server, (UA_Node*)state, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+                      &nodeIdHasComponent);
+      UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE), &nodeIdHasTypeDefinition,
+                             &expandedNodeIdBaseDataVariabletype);
 
       UA_VariableNode *buildinfo = UA_VariableNode_new();
        copyNames((UA_Node*)buildinfo, "BuildInfo");
@@ -998,10 +1050,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        buildinfo->value.variant.value.data = UA_BuildInfo_new();
        buildinfo->value.variant.value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
        getBulidInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
-       UA_Server_addNode(server, (UA_Node*)buildinfo,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                              nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE));
+       addNodeInternal(server, (UA_Node*)buildinfo,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), &nodeIdHasComponent);
+       UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+                              &nodeIdHasTypeDefinition, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE));
 
        UA_VariableNode *producturi = UA_VariableNode_new();
        copyNames((UA_Node*)producturi, "ProductUri");
@@ -1009,10 +1061,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        producturi->value.variant.value.data = UA_String_new();
        *((UA_String*)producturi->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_URI);
        producturi->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       UA_Server_addNode(server, (UA_Node*)producturi,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+       addNodeInternal(server, (UA_Node*)producturi,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), &nodeIdHasComponent);
+       UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *manufacturername = UA_VariableNode_new();
        copyNames((UA_Node*)manufacturername, "ManufacturererName");
@@ -1020,11 +1072,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        manufacturername->value.variant.value.data = UA_String_new();
        *((UA_String*)manufacturername->value.variant.value.data) = UA_STRING_ALLOC(MANUFACTURER_NAME);
        manufacturername->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       UA_Server_addNode(server, (UA_Node*)manufacturername,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+       addNodeInternal(server, (UA_Node*)manufacturername,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), &nodeIdHasComponent);
        UA_Server_addReference(server,
-                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+                              &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *productname = UA_VariableNode_new();
        copyNames((UA_Node*)productname, "ProductName");
@@ -1032,10 +1084,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        productname->value.variant.value.data = UA_String_new();
        *((UA_String*)productname->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_NAME);
        productname->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       UA_Server_addNode(server, (UA_Node*)productname,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+       addNodeInternal(server, (UA_Node*)productname,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), &nodeIdHasComponent);
+       UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *softwareversion = UA_VariableNode_new();
        copyNames((UA_Node*)softwareversion, "SoftwareVersion");
@@ -1043,11 +1095,11 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        softwareversion->value.variant.value.data = UA_String_new();
        *((UA_String*)softwareversion->value.variant.value.data) = UA_STRING_ALLOC(SOFTWARE_VERSION);
        softwareversion->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       UA_Server_addNode(server, (UA_Node*)softwareversion,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+       addNodeInternal(server, (UA_Node*)softwareversion,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), &nodeIdHasComponent);
        UA_Server_addReference(server,
-                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+                              &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *buildnumber = UA_VariableNode_new();
        copyNames((UA_Node*)buildnumber, "BuildNumber");
@@ -1055,10 +1107,10 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        buildnumber->value.variant.value.data = UA_String_new();
        *((UA_String*)buildnumber->value.variant.value.data) = UA_STRING_ALLOC(BUILD_NUMBER);
        buildnumber->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       UA_Server_addNode(server, (UA_Node*)buildnumber,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+       addNodeInternal(server, (UA_Node*)buildnumber,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), &nodeIdHasComponent);
+       UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *builddate = UA_VariableNode_new();
        copyNames((UA_Node*)builddate, "BuildDate");
@@ -1066,30 +1118,30 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
        builddate->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
        builddate->value.variant.value.data = &server->buildDate;
        builddate->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
-       UA_Server_addNode(server, (UA_Node*)builddate,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+       addNodeInternal(server, (UA_Node*)builddate,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), &nodeIdHasComponent);
+       UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *secondstillshutdown = UA_VariableNode_new();
        copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
        secondstillshutdown->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN);
        secondstillshutdown->value.variant.value.data = UA_UInt32_new();
        secondstillshutdown->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT32];
-       UA_Server_addNode(server, (UA_Node*)secondstillshutdown,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+       addNodeInternal(server, (UA_Node*)secondstillshutdown,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), &nodeIdHasComponent);
+       UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
        UA_VariableNode *shutdownreason = UA_VariableNode_new();
        copyNames((UA_Node*)shutdownreason, "ShutdownReason");
        shutdownreason->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON);
        shutdownreason->value.variant.value.data = UA_LocalizedText_new();
        shutdownreason->value.variant.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
-       UA_Server_addNode(server, (UA_Node*)shutdownreason,
-                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype);
+       addNodeInternal(server, (UA_Node*)shutdownreason,
+                       &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), &nodeIdHasComponent);
+       UA_Server_addReference(server, &UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),
+                              &nodeIdHasTypeDefinition, &expandedNodeIdBaseDataVariabletype);
 
    return server;
 }
@@ -1211,7 +1263,7 @@ UA_Server_setNodeAttribute_value_dataSource(UA_Server *server, const UA_NodeId n
 #endif
 
     if(editable->valueSource == UA_VALUESOURCE_VARIANT)
-        UA_Variant_deleteMembers(&editable->value.variant);
+        UA_Variant_deleteMembers(&editable->value.variant.value);
     editable->value.dataSource = dataSource;
     editable->valueSource = UA_VALUESOURCE_DATASOURCE;
   

+ 0 - 16
src/server/ua_server_internal.h

@@ -76,22 +76,6 @@ struct UA_Server {
 
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg);
 
-UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *node,
-                                               const UA_ExpandedNodeId parentNodeId,
-                                               const UA_NodeId referenceTypeId);
-
-UA_AddNodesResult UA_Server_addNode(UA_Server *server, UA_Node *node, const UA_ExpandedNodeId parentNodeId,
-                                    const UA_NodeId referenceTypeId);
-
-UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
-                                                const UA_AddReferencesItem *item);
-
-UA_StatusCode deleteOneWayReferenceWithSession(UA_Server *server, UA_Session *session, 
-                                               const UA_DeleteReferencesItem *item);
-
-UA_StatusCode addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, 
-                                            const UA_AddReferencesItem *item);
-
 UA_StatusCode UA_Server_addDelayedJob(UA_Server *server, UA_Job job);
 
 void UA_Server_deleteAllRepeatedJobs(UA_Server *server);

+ 9 - 0
src/server/ua_services.h

@@ -108,14 +108,23 @@ void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_Close
 /** Used to add one or more Nodes into the AddressSpace hierarchy. */
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
                       UA_AddNodesResponse *response);
+void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_Node *node,
+                             const UA_ExpandedNodeId *parentNodeId,
+                             const UA_NodeId *referenceTypeId, UA_AddNodesResult *result);
+void Service_AddNodes_single_fromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                            UA_NodeAttributes *attr, const UA_DataType *attributeType, UA_AddNodesResult *result);
 
 /** Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
                            UA_AddReferencesResponse *response);
+UA_StatusCode Service_AddReferences_single(UA_Server *server, UA_Session *session,
+                                           const UA_AddReferencesItem *item);
 
 /** Used to delete one or more Nodes from the AddressSpace. */
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
                          UA_DeleteNodesResponse *response);
+UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId nodeId,
+                                         UA_Boolean deleteReferences);
 
 /** Used to delete one or more References of a Node. */
 void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,

+ 10 - 10
src/server/ua_services_attribute.c

@@ -113,16 +113,16 @@ static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_Ti
             vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId,
                                               &v->value, rangeptr);
         if(rangeptr)
-            retval = UA_Variant_copyRange(&vn->value.variant, &v->value, range);
+            retval = UA_Variant_copyRange(&vn->value.variant.value, &v->value, range);
         else
-            retval = UA_Variant_copy(&vn->value.variant, &v->value);
+            retval = UA_Variant_copy(&vn->value.variant.value, &v->value);
         if(retval == UA_STATUSCODE_GOOD)
             handleSourceTimestamps(timestamps, v);
     } else {
         UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
                                       timestamps == UA_TIMESTAMPSTORETURN_BOTH);
         retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId,
-                                           sourceTimeStamp, &rangeptr, v);
+                                           sourceTimeStamp, rangeptr, v);
     }
 
     if(rangeptr)
@@ -133,7 +133,7 @@ static UA_StatusCode getVariableNodeValue(const UA_VariableNode *vn, const UA_Ti
 static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataValue *v) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-        retval = UA_Variant_setScalarCopy(&v->value, &vn->value.variant.type->typeId,
+        retval = UA_Variant_setScalarCopy(&v->value, &vn->value.variant.value.type->typeId,
                                           &UA_TYPES[UA_TYPES_NODEID]);
     } else {
         /* Read from the datasource to see the data type */
@@ -151,8 +151,8 @@ static UA_StatusCode getVariableNodeDataType(const UA_VariableNode *vn, UA_DataV
 static UA_StatusCode getVariableNodeArrayDimensions(const UA_VariableNode *vn, UA_DataValue *v) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
-        retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.arrayDimensions,
-                                         vn->value.variant.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+        retval = UA_Variant_setArrayCopy(&v->value, vn->value.variant.value.arrayDimensions,
+                                         vn->value.variant.value.arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
     } else {
         /* Read the datasource to see the array dimensions */
         UA_DataValue val;
@@ -464,7 +464,7 @@ Service_Write_single_Value(UA_Server *server, UA_Session *session, UA_VariableNo
     /* The nodeid on the wire may be != the nodeid in the node: opaque types, enums and bytestrings.
        nodeV contains the correct type definition. */
     UA_Variant *newV = &wvalue->value.value;
-    UA_Variant *oldV = &node->value.variant;
+    UA_Variant *oldV = &node->value.variant.value;
     UA_Variant cast_v;
     if(!UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
         cast_v = wvalue->value.value;
@@ -490,11 +490,11 @@ Service_Write_single_Value(UA_Server *server, UA_Session *session, UA_VariableNo
     
     if(!rangeptr) {
         // TODO: Avoid copying the whole node and then delete the old value for multithreading
-        UA_Variant_deleteMembers(&node->value.variant);
-        node->value.variant = *newV;
+        UA_Variant_deleteMembers(&node->value.variant.value);
+        node->value.variant.value = *newV;
         UA_Variant_init(&wvalue->value.value);
     } else {
-        retval = UA_Variant_setRangeCopy(&node->value.variant, newV->data, newV->arrayLength, range);
+        retval = UA_Variant_setRangeCopy(&node->value.variant.value, newV->data, newV->arrayLength, range);
     }
     if(node->value.variant.callback.onWrite)
         node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,

+ 603 - 191
src/server/ua_services_nodemanagement.c

@@ -25,54 +25,120 @@
 
 // TOOD: Ensure that the consistency guarantuees hold until v0.2
 
-/**************************/
-/* Parse Node Definitions */
-/**************************/
-
-/* may _init content in attr */
-static void copyStandardAttributes(UA_Node *node, UA_NodeAttributes *attr) {
-    if(attr->specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {
-        node->displayName = attr->displayName;
-        UA_LocalizedText_init(&attr->displayName);
-    }
-    if(attr->specifiedAttributes & UA_NODEATTRIBUTESMASK_DESCRIPTION) {
-        node->description = attr->description;
-        UA_LocalizedText_init(&attr->description);
-    }
-    if(attr->specifiedAttributes & UA_NODEATTRIBUTESMASK_WRITEMASK)
-        node->writeMask = attr->writeMask;
-    if(attr->specifiedAttributes & UA_NODEATTRIBUTESMASK_USERWRITEMASK)
-        node->userWriteMask = attr->userWriteMask;
+/************/
+/* Add Node */
+/************/
+
+void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_Node *node,
+                             const UA_ExpandedNodeId *parentNodeId,
+                             const UA_NodeId *referenceTypeId, UA_AddNodesResult *result) {
+    if(node->nodeId.namespaceIndex >= server->namespacesSize) {
+        result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
+        return;
+    }
+
+    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId);
+    if(!parent) {
+        result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
+        return;
+    }
+
+    const UA_ReferenceTypeNode *referenceType =
+        (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
+    if(!referenceType) {
+        result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+        goto ret;
+    }
+
+    if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
+        result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
+        goto ret2;
+    }
+
+    if(referenceType->isAbstract == UA_TRUE) {
+        result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
+        goto ret2;
+    }
+
+    // todo: test if the referencetype is hierarchical
+    //FIXME: a bit dirty workaround of preserving namespace
+    //namespace index is assumed to be valid
+    const UA_Node *managed = UA_NULL;
+    UA_NodeId tempNodeid;
+    UA_NodeId_init(&tempNodeid);
+    UA_NodeId_copy(&node->nodeId, &tempNodeid);
+    tempNodeid.namespaceIndex = 0;
+    if(UA_NodeId_isNull(&tempNodeid)) {
+        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
+            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+            goto ret2;
+        }
+        result->addedNodeId = managed->nodeId; // cannot fail as unique nodeids are numeric
+    } else {
+        if(UA_NodeId_copy(&node->nodeId, &result->addedNodeId) != UA_STATUSCODE_GOOD) {
+            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+            goto ret2;
+        }
+
+        if(UA_NodeStore_insert(server->nodestore, node, &managed) != UA_STATUSCODE_GOOD) {
+            result->statusCode = UA_STATUSCODE_BADNODEIDEXISTS;  // todo: differentiate out of memory
+            UA_NodeId_deleteMembers(&result->addedNodeId);
+            goto ret2;
+        }
+    }
+    
+    // reference back to the parent
+    UA_AddReferencesItem item;
+    UA_AddReferencesItem_init(&item);
+    item.sourceNodeId = managed->nodeId;
+    item.referenceTypeId = referenceType->nodeId;
+    item.isForward = UA_FALSE;
+    item.targetNodeId.nodeId = parent->nodeId;
+    Service_AddReferences_single(server, session, &item);
+
+    // todo: error handling. remove new node from nodestore
+    UA_NodeStore_release(managed);
+    
+ ret2:
+    UA_NodeId_deleteMembers(&tempNodeid);
+    UA_NodeStore_release((const UA_Node*)referenceType);
+ ret:
+    UA_NodeStore_release(parent);
 }
 
-static UA_StatusCode parseVariableNode(const UA_ExtensionObject *attributes, UA_Node **new_node) {
-    if(attributes->typeId.identifier.numeric !=
-       UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES].typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY)
-        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+static void moveStandardAttributes(UA_Node *node, UA_AddNodesItem *item, UA_NodeAttributes *attr) {
+    node->nodeId = item->requestedNewNodeId.nodeId;
+    UA_NodeId_init(&item->requestedNewNodeId.nodeId);
 
-    UA_VariableAttributes attr;
-    size_t pos = 0;
-    // todo return more informative error codes from decodeBinary
-    if(UA_VariableAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
-        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+    node->browseName = item->browseName;
+    UA_QualifiedName_deleteMembers(&item->browseName);
+
+    node->displayName = attr->displayName;
+    UA_LocalizedText_init(&attr->displayName);
+
+    node->description = attr->description;
+    UA_LocalizedText_init(&attr->description);
 
+    node->writeMask = attr->writeMask;
+    node->userWriteMask = attr->userWriteMask;
+}
+
+static void
+Service_AddNodes_single_fromVariableAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                               UA_VariableAttributes *attr, UA_AddNodesResult *result) {
     UA_VariableNode *vnode = UA_VariableNode_new();
     if(!vnode) {
-        UA_VariableAttributes_deleteMembers(&attr);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
     }
 
-    copyStandardAttributes((UA_Node*)vnode, (UA_NodeAttributes*)&attr);
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ACCESSLEVEL)
-        vnode->accessLevel = attr.accessLevel;
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERACCESSLEVEL)
-        vnode->userAccessLevel = attr.userAccessLevel;
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_HISTORIZING)
-        vnode->historizing = attr.historizing;
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL)
-        vnode->minimumSamplingInterval = attr.minimumSamplingInterval;
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUERANK)
-        vnode->valueRank = attr.valueRank;
+    moveStandardAttributes((UA_Node*)vnode, item, (UA_NodeAttributes*)attr);
+    // todo: test if the type / valueRank / value attributes are consistent
+    vnode->accessLevel = attr->accessLevel;
+    vnode->userAccessLevel = attr->userAccessLevel;
+    vnode->historizing = attr->historizing;
+    vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
+    vnode->valueRank = attr->valueRank;
 
     // don't use extra dimension spec. This comes from the value.
     /* if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS) { */
@@ -89,176 +155,198 @@ static UA_StatusCode parseVariableNode(const UA_ExtensionObject *attributes, UA_
     /*     UA_NodeId_init(&attr.dataType); */
     /* } */
 
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_VALUE) {
-        vnode->value.variant.value = attr.value;
-        UA_Variant_init(&attr.value);
+    Service_AddNodes_single(server, session, (UA_Node*)vnode, &item->parentNodeId, &item->referenceTypeId, result);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        UA_VariableNode_delete(vnode);
+}
+
+static void
+Service_AddNodes_single_fromObjectAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                             UA_ObjectAttributes *attr, UA_AddNodesResult *result) {
+    UA_ObjectNode *onode = UA_ObjectNode_new();
+    if(!onode) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
     }
 
-    UA_VariableAttributes_deleteMembers(&attr);
+    moveStandardAttributes((UA_Node*)onode, item, (UA_NodeAttributes*)attr);
+    onode->eventNotifier = attr->eventNotifier;
 
-    *new_node = (UA_Node*)vnode;
-    return UA_STATUSCODE_GOOD;
+    Service_AddNodes_single(server, session, (UA_Node*)onode, &item->parentNodeId, &item->referenceTypeId, result);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        UA_ObjectNode_delete(onode);
 }
 
-static UA_StatusCode parseObjectNode(const UA_ExtensionObject *attributes, UA_Node **new_node) {
-    if(attributes->typeId.identifier.numeric !=
-       UA_TYPES[UA_TYPES_OBJECTATTRIBUTES].typeId.identifier.numeric + UA_ENCODINGOFFSET_BINARY)
-        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
-
-    UA_ObjectAttributes attr;
-    size_t pos = 0;
-    // todo return more informative error codes from decodeBinary
-    if (UA_ObjectAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
-        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
-    UA_ObjectNode *vnode = UA_ObjectNode_new();
-    if(!vnode) {
-        UA_ObjectAttributes_deleteMembers(&attr);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+static void
+Service_AddNodes_single_fromReferenceTypeAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                                    UA_ReferenceTypeAttributes *attr, UA_AddNodesResult *result) {
+    UA_ReferenceTypeNode *rtnode = UA_ReferenceTypeNode_new();
+    if(!rtnode) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
     }
+    
+    moveStandardAttributes((UA_Node*)rtnode, item, (UA_NodeAttributes*)&attr);
+    rtnode->isAbstract = attr->isAbstract;
+    rtnode->symmetric = attr->symmetric;
+    rtnode->inverseName = attr->inverseName;
+    UA_LocalizedText_init(&attr->inverseName);
 
-    copyStandardAttributes((UA_Node*)vnode, (UA_NodeAttributes*)&attr);
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_EVENTNOTIFIER)
-      vnode->eventNotifier = attr.eventNotifier;
-    UA_ObjectAttributes_deleteMembers(&attr);
-    *new_node = (UA_Node*) vnode;
-    return UA_STATUSCODE_GOOD;
+    Service_AddNodes_single(server, session, (UA_Node*)rtnode, &item->parentNodeId, &item->referenceTypeId, result);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        UA_ReferenceTypeNode_delete(rtnode);
 }
 
-static UA_StatusCode parseReferenceTypeNode(const UA_ExtensionObject *attributes, UA_Node **new_node) {
-    UA_ReferenceTypeAttributes attr;
-    size_t pos = 0;
-    // todo return more informative error codes from decodeBinary
-    if(UA_ReferenceTypeAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
-        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
-    UA_ReferenceTypeNode *vnode = UA_ReferenceTypeNode_new();
-    if(!vnode) {
-        UA_ReferenceTypeAttributes_deleteMembers(&attr);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+static void
+Service_AddNodes_single_fromObjectTypeAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                                 UA_ObjectTypeAttributes *attr, UA_AddNodesResult *result) {
+    UA_ObjectTypeNode *otnode = UA_ObjectTypeNode_new();
+    if(!otnode) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
     }
 
-    copyStandardAttributes((UA_Node*)vnode, (UA_NodeAttributes*)&attr);
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ISABSTRACT)
-        vnode->isAbstract = attr.isAbstract;
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_SYMMETRIC)
-        vnode->symmetric = attr.symmetric;
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_INVERSENAME) {
-        vnode->inverseName = attr.inverseName;
-        attr.inverseName.text.length = -1;
-        attr.inverseName.text.data = UA_NULL;
-        attr.inverseName.locale.length = -1;
-        attr.inverseName.locale.data = UA_NULL;
-    }
-    UA_ReferenceTypeAttributes_deleteMembers(&attr);
-    *new_node = (UA_Node*) vnode;
-    return UA_STATUSCODE_GOOD;
+    moveStandardAttributes((UA_Node*)otnode, item, (UA_NodeAttributes*)attr);
+    otnode->isAbstract = attr->isAbstract;
+
+    Service_AddNodes_single(server, session, (UA_Node*)otnode, &item->parentNodeId, &item->referenceTypeId, result);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        UA_ObjectTypeNode_delete(otnode);
 }
 
-static UA_StatusCode parseObjectTypeNode(const UA_ExtensionObject *attributes, UA_Node **new_node) {
-    UA_ObjectTypeAttributes attr;
-    size_t pos = 0;
-    // todo return more informative error codes from decodeBinary
-    if(UA_ObjectTypeAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
-        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
-    UA_ObjectTypeNode *vnode = UA_ObjectTypeNode_new();
-    if(!vnode) {
-        UA_ObjectTypeAttributes_deleteMembers(&attr);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+static void
+Service_AddNodes_single_fromVariableTypeAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                                   UA_VariableTypeAttributes *attr, UA_AddNodesResult *result) {
+    UA_VariableTypeNode *vtnode = UA_VariableTypeNode_new();
+    if(!vtnode) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
     }
-    
-    copyStandardAttributes((UA_Node*)vnode, (UA_NodeAttributes*)&attr);
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_ISABSTRACT)
-        vnode->isAbstract = attr.isAbstract;
 
-    UA_ObjectTypeAttributes_deleteMembers(&attr);
-    *new_node = (UA_Node*) vnode;
-    return UA_STATUSCODE_GOOD;
-}
+    moveStandardAttributes((UA_Node*)vtnode, item, (UA_NodeAttributes*)attr);
+    vtnode->value.variant.value = attr->value;
+    UA_Variant_init(&attr->value);
+    // datatype is taken from the value
+    vtnode->valueRank = attr->valueRank;
+    // array dimensions are taken from the value
+    vtnode->isAbstract = attr->isAbstract;
 
-static UA_StatusCode parseViewNode(const UA_ExtensionObject *attributes, UA_Node **new_node) {
-    UA_ViewAttributes attr;
-    size_t pos = 0;
+    Service_AddNodes_single(server, session, (UA_Node*)vtnode, &item->parentNodeId, &item->referenceTypeId, result);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        UA_VariableTypeNode_delete(vtnode);
+}
 
-    // todo return more informative error codes from decodeBinary
-    if(UA_ViewAttributes_decodeBinary(&attributes->body, &pos, &attr) != UA_STATUSCODE_GOOD)
-        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+static void
+Service_AddNodes_single_fromViewAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                           UA_ViewAttributes *attr, UA_AddNodesResult *result) {
     UA_ViewNode *vnode = UA_ViewNode_new();
     if(!vnode) {
-        UA_ViewAttributes_deleteMembers(&attr);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
     }
 
-    copyStandardAttributes((UA_Node*)vnode, (UA_NodeAttributes*)&attr);
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS)
-        vnode->containsNoLoops = attr.containsNoLoops;
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_EVENTNOTIFIER)
-        vnode->eventNotifier = attr.eventNotifier;
+    moveStandardAttributes((UA_Node*)vnode, item, (UA_NodeAttributes*)attr);
+    vnode->containsNoLoops = attr->containsNoLoops;
+    vnode->eventNotifier = attr->eventNotifier;
 
-    UA_ViewAttributes_deleteMembers(&attr);
-    *new_node = (UA_Node*) vnode;
-    return UA_STATUSCODE_GOOD;
+    Service_AddNodes_single(server, session, (UA_Node*)vnode, &item->parentNodeId, &item->referenceTypeId, result);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        UA_ViewNode_delete(vnode);
 }
 
-/************/
-/* Add Node */
-/************/
+static void
+Service_AddNodes_single_fromDataTypeAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                               UA_DataTypeAttributes *attr, UA_AddNodesResult *result) {
+    UA_DataTypeNode *dtnode = UA_DataTypeNode_new();
+    if(!dtnode) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
+    }
+
+    moveStandardAttributes((UA_Node*)dtnode, item, (UA_NodeAttributes*)attr);
+    dtnode->isAbstract = attr->isAbstract;
+
+    Service_AddNodes_single(server, session, (UA_Node*)dtnode, &item->parentNodeId, &item->referenceTypeId, result);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        UA_DataTypeNode_delete(dtnode);
+}
+
+void Service_AddNodes_single_fromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                            UA_NodeAttributes *attr, const UA_DataType *attributeType,
+                                            UA_AddNodesResult *result) {
+    switch(attributeType->typeIndex) {
+    case UA_TYPES_OBJECTATTRIBUTES:
+        Service_AddNodes_single_fromObjectAttributes(server, session, item, (UA_ObjectAttributes*)attr, result);
+        break;
+    case UA_TYPES_OBJECTTYPEATTRIBUTES:
+        Service_AddNodes_single_fromObjectTypeAttributes(server, session, item, (UA_ObjectTypeAttributes*)attr, result);
+        break;
+    case UA_TYPES_VARIABLEATTRIBUTES:
+        Service_AddNodes_single_fromVariableAttributes(server, session, item, (UA_VariableAttributes*)attr, result);
+        break;
+    case UA_TYPES_VARIABLETYPEATTRIBUTES:
+        Service_AddNodes_single_fromVariableTypeAttributes(server, session, item, (UA_VariableTypeAttributes*)attr, result);
+        break;
+    case UA_TYPES_REFERENCETYPEATTRIBUTES:
+        Service_AddNodes_single_fromReferenceTypeAttributes(server, session, item, (UA_ReferenceTypeAttributes*)attr, result);
+        break;
+    case UA_TYPES_VIEWATTRIBUTES:
+        Service_AddNodes_single_fromViewAttributes(server, session, item, (UA_ViewAttributes*)attr, result);
+        break;
+    case UA_TYPES_DATATYPEATTRIBUTES:
+        Service_AddNodes_single_fromDataTypeAttributes(server, session, item, (UA_DataTypeAttributes*)attr, result);
+        break;
+    default:
+        result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
+    }
+}
 
-static void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                                    UA_AddNodesResult *result) {
-    // adding nodes to ns0 is not allowed over the wire
+static void Service_AddNodes_single_unparsed(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                             UA_AddNodesResult *result) {
+    /* adding nodes to ns0 is not allowed over the wire */
     if(item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
         result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
         return;
     }
 
-    // parse the node
-    UA_Node *node = UA_NULL;
-
+    const UA_DataType *attributeType;
     switch (item->nodeClass) {
     case UA_NODECLASS_OBJECT:
-        result->statusCode = parseObjectNode(&item->nodeAttributes, &node);
+        attributeType = &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES];
         break;
     case UA_NODECLASS_OBJECTTYPE:
-        result->statusCode = parseObjectTypeNode(&item->nodeAttributes, &node);
+        attributeType = &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES];
         break;
     case UA_NODECLASS_REFERENCETYPE:
-        result->statusCode = parseReferenceTypeNode(&item->nodeAttributes, &node);
+        attributeType = &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES];
         break;
     case UA_NODECLASS_VARIABLE:
-        result->statusCode = parseVariableNode(&item->nodeAttributes, &node);
+        attributeType = &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES];
+        break;
+    case UA_NODECLASS_VIEW:
+        attributeType = &UA_TYPES[UA_TYPES_VIEWATTRIBUTES];
+        break;
+    case UA_NODECLASS_DATATYPE:
+        attributeType = &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES];
         break;
     default:
         result->statusCode = UA_STATUSCODE_BADNOTIMPLEMENTED;
+        return;
     }
 
-    if(result->statusCode != UA_STATUSCODE_GOOD)
+    if(!UA_NodeId_equal(&item->nodeAttributes.typeId, &attributeType->typeId)) {
+        result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
         return;
-    
-    // The BrowseName was not included with the NodeAttribute ExtensionObject
-    UA_QualifiedName_init(&(node->browseName));
-    UA_QualifiedName_copy(&(item->browseName), &(node->browseName));
-    UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
-    
-    // add the node
-    *result = UA_Server_addNodeWithSession(server, session, node, item->parentNodeId,
-                                           item->referenceTypeId);
-    if(result->statusCode != UA_STATUSCODE_GOOD) {
-        switch (node->nodeClass) {
-        case UA_NODECLASS_OBJECT:
-            UA_ObjectNode_delete((UA_ObjectNode*)node);
-            break;
-        case UA_NODECLASS_OBJECTTYPE:
-            UA_ObjectTypeNode_delete((UA_ObjectTypeNode*)node);
-            break;
-        case UA_NODECLASS_REFERENCETYPE:
-            UA_ReferenceTypeNode_delete((UA_ReferenceTypeNode*)node);
-            break;
-        case UA_NODECLASS_VARIABLE:
-            UA_VariableNode_delete((UA_VariableNode*)node);
-            break;
-        default:
-            UA_assert(UA_FALSE);
-        }
     }
+
+    UA_NodeAttributes *attr = UA_alloca(attributeType->memSize);
+    size_t pos = 0;
+    result->statusCode = UA_decodeBinary(&item->nodeAttributes.body, &pos, &attr, attributeType);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        return;
+
+    Service_AddNodes_single_fromAttributes(server, session, item, attr, attributeType, result);
+    UA_deleteMembers(attr, attributeType);
 }
 
 void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesRequest *request,
@@ -307,14 +395,285 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
 #ifdef UA_EXTERNAL_NAMESPACES
         if(!isExternal[i])
 #endif
-            Service_AddNodes_single(server, session, &request->nodesToAdd[i], &response->results[i]);
+            Service_AddNodes_single_unparsed(server, session, &request->nodesToAdd[i], &response->results[i]);
+    }
+}
+
+/**************************************************/
+/* Add Special Nodes (not possible over the wire) */
+/**************************************************/
+
+UA_AddNodesResult
+UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                                    const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                                    const UA_QualifiedName *browseName, const UA_ExpandedNodeId *typeDefinition,
+                                    const UA_VariableAttributes *attr, const UA_DataSource *dataSource) {
+    UA_AddNodesResult result;
+    UA_AddNodesResult_init(&result);
+
+    UA_AddNodesItem item;
+    UA_AddNodesItem_init(&item);
+    result.statusCode = UA_QualifiedName_copy(browseName, &item.browseName);
+    item.nodeClass = UA_NODECLASS_METHOD;
+    result.statusCode |= UA_ExpandedNodeId_copy(parentNodeId, &item.parentNodeId);
+    result.statusCode |= UA_NodeId_copy(referenceTypeId, &item.referenceTypeId);
+    result.statusCode |= UA_ExpandedNodeId_copy(requestedNewNodeId, &item.requestedNewNodeId);
+    result.statusCode |= UA_ExpandedNodeId_copy(typeDefinition, &item.typeDefinition);
+    
+    UA_VariableAttributes attrCopy;
+    result.statusCode |= UA_VariableAttributes_copy(attr, &attrCopy);
+    if(result.statusCode != UA_STATUSCODE_GOOD) {
+        UA_AddNodesItem_deleteMembers(&item);
+        UA_VariableAttributes_deleteMembers(&attrCopy);
+        return result;
     }
+
+    UA_VariableNode *node = UA_VariableNode_new();
+    if(!node) {
+        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        UA_AddNodesItem_deleteMembers(&item);
+        UA_VariableAttributes_deleteMembers(&attrCopy);
+        return result;
+    }
+
+    moveStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
+    node->valueSource = UA_VALUESOURCE_DATASOURCE;
+    node->value.dataSource = *dataSource;
+    node->accessLevel = attr->accessLevel;
+    node->userAccessLevel = attr->userAccessLevel;
+    node->historizing = attr->historizing;
+    node->minimumSamplingInterval = attr->minimumSamplingInterval;
+    node->valueRank = attr->valueRank;
+
+    Service_AddNodes_single(server, &adminSession, (UA_Node*)node, &item.parentNodeId,
+                            &item.referenceTypeId, &result);
+    UA_AddNodesItem_deleteMembers(&item);
+    UA_VariableAttributes_deleteMembers(&attrCopy);
+
+    if(result.statusCode != UA_STATUSCODE_GOOD)
+        UA_VariableNode_delete(node);
+    return result;
 }
 
+#ifdef ENABLE_METHODCALLS
+UA_AddNodesResult UA_EXPORT
+UA_Server_addMethodNode(UA_Server *server, const UA_ExpandedNodeId *requestedNewNodeId,
+                        const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                        const UA_QualifiedName *browseName, const UA_NodeAttributes *attr,
+                        UA_MethodCallback method, void *handle,
+                        UA_Int32 inputArgumentsSize, const UA_Argument* inputArguments, 
+                        UA_Int32 outputArgumentsSize, const UA_Argument* outputArguments) {
+    UA_AddNodesResult result;
+    UA_AddNodesResult_init(&result);
+    
+    UA_AddNodesItem item;
+    UA_AddNodesItem_init(&item);
+    result.statusCode = UA_QualifiedName_copy(browseName, &item.browseName);
+    item.nodeClass = UA_NODECLASS_METHOD;
+    result.statusCode |= UA_ExpandedNodeId_copy(parentNodeId, &item.parentNodeId);
+    result.statusCode |= UA_NodeId_copy(referenceTypeId, &item.referenceTypeId);
+    result.statusCode |= UA_ExpandedNodeId_copy(requestedNewNodeId, &item.requestedNewNodeId);
+    
+    UA_NodeAttributes attrCopy;
+    result.statusCode |= UA_NodeAttributes_copy(attr, &attrCopy);
+    if(result.statusCode != UA_STATUSCODE_GOOD) {
+        UA_AddNodesItem_deleteMembers(&item);
+        UA_NodeAttributes_deleteMembers(&attrCopy);
+        return result;
+    }
+
+    UA_MethodNode *node = UA_MethodNode_new();
+    if(!node) {
+        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        UA_AddNodesItem_deleteMembers(&item);
+        UA_NodeAttributes_deleteMembers(&attrCopy);
+        return result;
+    }
+    
+    moveStandardAttributes((UA_Node*)node, &item, &attrCopy);
+    node->executable = UA_TRUE;
+    node->userExecutable = UA_TRUE;
+    UA_AddNodesItem_deleteMembers(&item);
+    UA_NodeAttributes_deleteMembers(&attrCopy);
+
+    Service_AddNodes_single(server, &adminSession, (UA_Node*)node, &item.parentNodeId,
+                            &item.referenceTypeId, &result);
+    if(result.statusCode != UA_STATUSCODE_GOOD) {
+        UA_MethodNode_delete(node);
+        return result;
+    }
+    
+    /* Only proceed with creating in/outputArguments if the method and both arguments are not
+     * UA_NULL; otherwise this is a pretty strong indicator that this node was generated,
+     * in which case these arguments will be created later and individually.
+     */
+    if(method == UA_NULL && inputArguments == UA_NULL && outputArguments == UA_NULL &&
+       inputArgumentsSize <= 0 && outputArgumentsSize <= 0)
+        return result;
+
+    UA_ExpandedNodeId parent;
+    UA_ExpandedNodeId_init(&parent);
+    parent.nodeId = result.addedNodeId;
+    
+    /* create InputArguments */
+    UA_VariableNode *inputArgumentsVariableNode = UA_VariableNode_new();
+    inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    inputArgumentsVariableNode->browseName = UA_QUALIFIEDNAME_ALLOC(0,"InputArguments");
+    inputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "InputArguments");
+    inputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&inputArgumentsVariableNode->value.variant.value, inputArguments,
+                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult inputAddRes;
+    Service_AddNodes_single(server, &adminSession, (UA_Node*)inputArgumentsVariableNode, &parent,
+                            &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), &inputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&inputAddRes);
+
+    /* create OutputArguments */
+    UA_VariableNode *outputArgumentsVariableNode  = UA_VariableNode_new();
+    outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
+    outputArgumentsVariableNode->browseName  = UA_QUALIFIEDNAME_ALLOC(0,"OutputArguments");
+    outputArgumentsVariableNode->displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->description = UA_LOCALIZEDTEXT_ALLOC("en_US", "OutputArguments");
+    outputArgumentsVariableNode->valueRank = 1;
+    UA_Variant_setArrayCopy(&outputArgumentsVariableNode->value.variant.value, outputArguments,
+                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
+    UA_AddNodesResult outputAddRes;
+    Service_AddNodes_single(server, &adminSession, (UA_Node*)inputArgumentsVariableNode, &parent,
+                            &UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), &outputAddRes);
+    // todo: check if adding succeeded
+    UA_AddNodesResult_deleteMembers(&outputAddRes);
+
+    return result;
+}
+#endif
+
 /******************/
 /* Add References */
 /******************/
 
+/* Adds a one-way reference to the local nodestore */
+static UA_StatusCode
+addOneWayReferenceWithSession(UA_Server *server, UA_Session *session, const UA_AddReferencesItem *item) {
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
+    if(!node)
+        return UA_STATUSCODE_BADINTERNALERROR;
+	UA_StatusCode retval = UA_STATUSCODE_GOOD;
+#ifndef UA_MULTITHREADING
+	size_t i = node->referencesSize;
+	if(node->referencesSize < 0)
+		i = 0;
+    size_t refssize = (i+1) | 3; // so the realloc is not necessary every time
+	UA_ReferenceNode *new_refs = UA_realloc(node->references, sizeof(UA_ReferenceNode) * refssize);
+	if(!new_refs)
+		retval = UA_STATUSCODE_BADOUTOFMEMORY;
+	else {
+		UA_ReferenceNode_init(&new_refs[i]);
+		retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[i].referenceTypeId);
+		new_refs[i].isInverse = !item->isForward;
+		retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[i].targetId);
+		/* hack. be careful! possible only in the single-threaded case. */
+		UA_Node *mutable_node = (UA_Node*)(uintptr_t)node;
+		mutable_node->references = new_refs;
+		if(retval != UA_STATUSCODE_GOOD) {
+			UA_NodeId_deleteMembers(&new_refs[node->referencesSize].referenceTypeId);
+			UA_ExpandedNodeId_deleteMembers(&new_refs[node->referencesSize].targetId);
+		} else
+			mutable_node->referencesSize = i+1;
+	}
+	UA_NodeStore_release(node);
+	return retval;
+#else
+    UA_Node *newNode = UA_Node_copyAnyNodeClass(node);
+    if(!newNode) {
+        UA_NodeStore_release(node);
+        return UA_STATUSCODE_BADINTERNALERROR;
+    }
+
+    UA_Int32 count = node->referencesSize;
+    if(count < 0)
+        count = 0;
+    UA_ReferenceNode *old_refs = newNode->references;
+    UA_ReferenceNode *new_refs = UA_malloc(sizeof(UA_ReferenceNode)*(count+1));
+    if(!new_refs) {
+        UA_Node_deleteAnyNodeClass(newNode);
+        UA_NodeStore_release(node);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    // insert the new reference
+    UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
+    UA_ReferenceNode_init(&new_refs[count]);
+    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, &UA_TYPES[UA_TYPES_REFERENCENODE], ++count);
+        newNode->references = UA_NULL;
+        newNode->referencesSize = 0;
+        UA_Node_deleteAnyNodeClass(newNode);
+        UA_NodeStore_release(node);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    UA_free(old_refs);
+    newNode->references = new_refs;
+    newNode->referencesSize = ++count;
+    retval = UA_NodeStore_replace(server->nodestore, node, newNode, UA_NULL);
+	UA_NodeStore_release(node);
+	if(retval == UA_STATUSCODE_BADINTERNALERROR) {
+		/* presumably because the node was replaced and an old version was updated at the same time.
+           just try again */
+        UA_Node_deleteAnyNodeClass(newNode);
+		return addOneWayReferenceWithSession(server, session, item);
+	}
+	return retval;
+#endif
+}
+
+UA_StatusCode Service_AddReferences_single(UA_Server *server, UA_Session *session,
+                                           const UA_AddReferencesItem *item) {
+    if(item->targetServerUri.length > 0)
+        return UA_STATUSCODE_BADNOTIMPLEMENTED; // currently no expandednodeids are allowed
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+
+#ifdef UA_EXTERNAL_NAMESPACES
+    UA_ExternalNodeStore *ensFirst = UA_NULL;
+    UA_ExternalNodeStore *ensSecond = UA_NULL;
+    for(size_t j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
+        if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
+            ensFirst = &server->externalNamespaces[j].externalNodeStore;
+        if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)
+            ensSecond = &server->externalNamespaces[j].externalNodeStore;
+    }
+
+    if(ensFirst) {
+        // todo: use external nodestore
+    } else
+#endif
+        retval = addOneWayReferenceWithSession(server, session, item);
+
+    if(retval)
+        return retval;
+
+    UA_AddReferencesItem secondItem;
+    secondItem = *item;
+    secondItem.targetNodeId.nodeId = item->sourceNodeId;
+    secondItem.sourceNodeId = item->targetNodeId.nodeId;
+    secondItem.isForward = !item->isForward;
+#ifdef UA_EXTERNAL_NAMESPACES
+    if(ensSecond) {
+        // todo: use external nodestore
+    } else
+#endif
+        retval = addOneWayReferenceWithSession (server, session, &secondItem);
+
+    // todo: remove reference if the second direction failed
+    return retval;
+} 
+
 void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
                            UA_AddReferencesResponse *response) {
 	if(request->referencesToAddSize <= 0) {
@@ -362,16 +721,18 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 #ifdef UA_EXTERNAL_NAMESPACES
 		if(!isExternal[i])
 #endif
-			UA_Server_addReferenceWithSession(server, session, &request->referencesToAdd[i]);
+            Service_AddReferences_single(server, session, &request->referencesToAdd[i]);
 	}
 }
 
-/***************/
-/* Delete Node */
-/***************/
+/****************/
+/* Delete Nodes */
+/****************/
+
+// TODO: Check consistency constraints, remove the references.
 
-static UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_NodeId nodeId,
-                                                UA_Boolean deleteReferences) {
+UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId nodeId,
+                                         UA_Boolean deleteReferences) {
   const UA_Node *delNode = UA_NodeStore_get(server->nodestore, &nodeId);
   if (!delNode)
     return UA_STATUSCODE_BADNODEIDINVALID;
@@ -383,11 +744,9 @@ static UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_NodeId nod
     UA_NodeId_copy(&nodeId, &delItem->targetNodeId.nodeId);
     
     for(int i=0; i<delNode->referencesSize; i++) {
-      UA_NodeId_copy(&delNode->references[i].targetId.nodeId, &delItem->sourceNodeId);
-      
-      UA_NodeId_deleteMembers(&delItem->sourceNodeId);
+        UA_NodeId_copy(&delNode->references[i].targetId.nodeId, &delItem->sourceNodeId);
+        UA_NodeId_deleteMembers(&delItem->sourceNodeId);
     }
-    
     UA_DeleteReferencesItem_delete(delItem);
   }
   
@@ -397,26 +756,79 @@ static UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_NodeId nod
 
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
                          UA_DeleteNodesResponse *response) {
-  UA_StatusCode retval = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
+  response->results = UA_malloc(sizeof(UA_StatusCode) * request->nodesToDeleteSize);
+  if(!response->results) {
+      response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;;
+      return;
+  }
   response->resultsSize = request->nodesToDeleteSize;
-  response->results = (UA_StatusCode *) UA_malloc(sizeof(UA_StatusCode) * request->nodesToDeleteSize);
-  
-  UA_DeleteNodesItem *item;
   for(int i=0; i<request->nodesToDeleteSize; i++) {
-    item = &request->nodesToDelete[i];
-    response->results[i] = Service_DeleteNodes_single(server, item->nodeId, item->deleteTargetReferences);
+      UA_DeleteNodesItem *item = &request->nodesToDelete[i];
+      response->results[i] = Service_DeleteNodes_single(server, session, item->nodeId, item->deleteTargetReferences);
   }
-  
-  response->responseHeader.serviceResult = retval;
 }
 
-/********************/
-/* Delete Reference */
-/********************/
+/*********************/
+/* Delete References */
+/*********************/
+
+// TODO: Add to service
+
+static UA_StatusCode
+deleteOneWayReference(UA_Server *server, UA_Session *session, const UA_DeleteReferencesItem *item) {
+    const UA_Node *orig;
+ repeat_deleteref_oneway:
+    orig = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
+    if(!orig)
+        return UA_STATUSCODE_BADNODEIDUNKNOWN;
+
+#ifndef UA_MULTITHREADING
+    /* We cheat if multithreading is not enabled and treat the node as mutable. */
+    UA_Node *editable = (UA_Node*)(uintptr_t)orig;
+#else
+    UA_Node *editable = UA_Node_copyAnyNodeClass(orig);
+    UA_Boolean edited = UA_FALSE;;
+#endif
+
+    for(UA_Int32 i = editable->referencesSize - 1; i >= 0; i--) {
+        if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &editable->references[i].targetId.nodeId))
+            continue;
+        if(!UA_NodeId_equal(&item->referenceTypeId, &editable->references[i].referenceTypeId))
+            continue;
+        if(item->isForward == editable->references[i].isInverse)
+            continue;
+        /* move the last entry to override the current position */
+        UA_ReferenceNode_deleteMembers(&editable->references[i]);
+        editable->references[i] = editable->references[editable->referencesSize-1];
+        editable->referencesSize--;
+
+#ifdef UA_MULTITHREADING
+        edited = UA_TRUE;
+#endif
+    }
+
+    /* we removed the last reference */
+    if(editable->referencesSize <= 0 && editable->references)
+        UA_free(editable->references);
+    
+#ifdef UA_MULTITHREADING
+    if(!edited) {
+        UA_Node_deleteAnyNodeClass(editable);
+    } else if(UA_NodeStore_replace(server->nodestore, orig, editable, UA_NULL) != UA_STATUSCODE_GOOD) {
+        /* the node was changed by another thread. repeat. */
+        UA_Node_deleteAnyNodeClass(editable);
+        UA_NodeStore_release(orig);
+        goto repeat_deleteref_oneway;
+    }
+#endif
+
+    UA_NodeStore_release(orig);
+    return UA_STATUSCODE_GOOD;;
+}
+
 
-void Service_DeleteReferences(UA_Server *server, UA_Session *session,
-                              const UA_DeleteReferencesRequest *request,
+void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request,
                               UA_DeleteReferencesResponse *response) {
-  UA_StatusCode retval = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
-  response->responseHeader.serviceResult = retval;
+    UA_StatusCode retval = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
+    response->responseHeader.serviceResult = retval;
 }

+ 6 - 7
tests/check_services_attributes.c

@@ -52,23 +52,22 @@ static UA_Server* makeTestSequence(void) {
     organizes->isAbstract = UA_FALSE;
     organizes->symmetric  = UA_FALSE;
     UA_Server_addNode(server, (UA_Node*)organizes,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
-                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+                          &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES),
+                          &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
     /* ViewNode */
     UA_ViewNode *viewtest = UA_ViewNode_new();
     copyNames((UA_Node*)viewtest, "Viewtest");
     viewtest->nodeId.identifier.numeric = UA_NS0ID_VIEWNODE;
-    UA_Server_addNode(server, (UA_Node*)viewtest, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
-                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+    UA_Server_addNode(server, (UA_Node*)viewtest, &UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 
 	/* MethodNode */
     UA_MethodNode *methodtest = UA_MethodNode_new();
     copyNames((UA_Node*)methodtest, "Methodtest");
     methodtest->nodeId.identifier.numeric = UA_NS0ID_METHODNODE;
-    UA_Server_addNode(server, (UA_Node*)methodtest,
-                      UA_EXPANDEDNODEID_NUMERIC(0, 3),
-                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
+    UA_Server_addNode(server, (UA_Node*)methodtest, &UA_EXPANDEDNODEID_NUMERIC(0, 3),
+                      &UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE));
 	return server;
 }
 

+ 4 - 3
tools/generate_datatypes.py

@@ -53,9 +53,10 @@ minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "Applicati
                  "AddNodesItem", "AddNodesResult", "DeleteNodesItem","AddReferencesRequest", "AddReferencesResponse",
                  "AddReferencesItem","DeleteReferencesItem", "VariableNode", "MethodNode", "VariableTypeNode",
                  "ViewNode", "ReferenceTypeNode", "BrowseResultMask", "ServerState", "ServerStatusDataType", "BuildInfo",
-                 "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "VariableAttributes", "ObjectAttributes",
-                 "NodeAttributes","ReferenceTypeAttributes", "ViewAttributes", "ObjectTypeAttributes",
-                 "NodeAttributesMask","DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
+                 "ObjectNode", "DataTypeNode", "ObjectTypeNode", "IdType", "NodeAttributes",
+                 "VariableAttributes", "ObjectAttributes", "ReferenceTypeAttributes", "ViewAttributes",
+                 "ObjectTypeAttributes", "VariableTypeAttributes", "DataTypeAttributes", "NodeAttributesMask",
+                 "DeleteNodesItem", "DeleteNodesRequest", "DeleteNodesResponse",
                  "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
                  "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse", 
                  "UserIdentityToken", "UserNameIdentityToken", "AnonymousIdentityToken", "ServiceFault",