Selaa lähdekoodia

Merge pull request #627 from open62541/addnodes_verification

Addnodes verification
Julius Pfrommer 8 vuotta sitten
vanhempi
commit
1411251032

+ 1 - 1
examples/server.c

@@ -200,7 +200,7 @@ nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, voi
 }
 
 static UA_StatusCode
-instantiationHandle(UA_NodeId newNodeId, UA_NodeId templateId, void *handle ) {
+instantiationHandle(const UA_NodeId newNodeId, const UA_NodeId templateId, void *handle ) {
   printf("Instantiated Node ns=%d; id=%d from ns=%d; id=%d\n", newNodeId.namespaceIndex,
          newNodeId.identifier.numeric, templateId.namespaceIndex, templateId.identifier.numeric);
   return UA_STATUSCODE_GOOD;

+ 4 - 5
include/ua_server.h

@@ -302,14 +302,13 @@ UA_Server_setMethodNode_callback(UA_Server *server, const UA_NodeId methodNodeId
  * ^^^^^^^^^^^^^^^^^^^^^^^^^ */
 UA_StatusCode UA_EXPORT
 UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId, UA_Boolean deleteReferences);
-    
+
 /**
  * The instantiation callback is used to track the addition of new nodes. It is
  * also called for all sub-nodes contained in an object or variable type node
- * that is instantiated.
- */
-typedef struct UA_InstantiationCallback_s {
-  UA_StatusCode (*method)(UA_NodeId objectId, UA_NodeId definitionId, void *handle);
+ * that is instantiated. */
+typedef struct {
+  UA_StatusCode (*method)(const UA_NodeId objectId, const UA_NodeId typeDefinitionId, void *handle);
   void *handle;
 } UA_InstantiationCallback;
 

+ 26 - 23
src/server/ua_server.c

@@ -184,7 +184,7 @@ addNodeInternal(UA_Server *server, UA_Node *node, const UA_NodeId parentNodeId,
     UA_AddNodesResult_init(&res);
     UA_RCU_LOCK();
     Service_AddNodes_existing(server, &adminSession, node, &parentNodeId,
-                              &referenceTypeId, &res);
+                              &referenceTypeId, &UA_NODEID_NULL, NULL, &res);
     UA_RCU_UNLOCK();
     return res;
 }
@@ -194,7 +194,7 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                     const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                     const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                     const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
-                    const UA_DataType *attributeType, 
+                    const UA_DataType *attributeType,
                     UA_InstantiationCallback *instantiationCallback, UA_NodeId *outNewNodeId) {
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
@@ -503,8 +503,10 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     /**************/
     /* References */
     /**************/
+
 #ifndef UA_ENABLE_GENERATE_NAMESPACE0
-    /* Bootstrap by manually inserting "references" and "hassubtype" */
+    /* Bootstrap reference hierarchy by manually inserting "references" and "hassubtype" */
+
     UA_ReferenceTypeNode *references = UA_NodeStore_newReferenceTypeNode();
     copyNames((UA_Node*)references, "References");
     references->nodeId.identifier.numeric = UA_NS0ID_REFERENCES;
@@ -608,8 +610,7 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     generatesevent->nodeId.identifier.numeric = UA_NS0ID_GENERATESEVENT;
     generatesevent->isAbstract = false;
     generatesevent->symmetric  = false;
-    addNodeInternal(server, (UA_Node*)generatesevent, nodeIdNonHierarchicalReferences,
-                    nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)generatesevent, nodeIdNonHierarchicalReferences, nodeIdHasSubType);
 
     UA_ReferenceTypeNode *aggregates = UA_NodeStore_newReferenceTypeNode();
     copyNames((UA_Node*)aggregates, "Aggregates");
@@ -617,8 +618,7 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     aggregates->nodeId.identifier.numeric = UA_NS0ID_AGGREGATES;
     aggregates->isAbstract = false;
     aggregates->symmetric  = false;
-    addNodeInternal(server, (UA_Node*)aggregates,
-                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)aggregates, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType);
 
     // complete bootstrap of hassubtype
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCHILD), nodeIdHasSubType,
@@ -639,8 +639,7 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     hascomponent->nodeId.identifier.numeric = UA_NS0ID_HASCOMPONENT;
     hascomponent->isAbstract = false;
     hascomponent->symmetric  = false;
-    addNodeInternal(server, (UA_Node*)hascomponent,
-                    UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hascomponent, UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasnotifier = UA_NodeStore_newReferenceTypeNode();
     copyNames((UA_Node*)hasnotifier, "HasNotifier");
@@ -648,8 +647,7 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     hasnotifier->nodeId.identifier.numeric = UA_NS0ID_HASNOTIFIER;
     hasnotifier->isAbstract = false;
     hasnotifier->symmetric  = false;
-    addNodeInternal(server, (UA_Node*)hasnotifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE),
-                    nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasnotifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASEVENTSOURCE), nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasorderedcomponent = UA_NodeStore_newReferenceTypeNode();
     copyNames((UA_Node*)hasorderedcomponent, "HasOrderedComponent");
@@ -657,8 +655,7 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     hasorderedcomponent->nodeId.identifier.numeric = UA_NS0ID_HASORDEREDCOMPONENT;
     hasorderedcomponent->isAbstract = false;
     hasorderedcomponent->symmetric  = false;
-    addNodeInternal(server, (UA_Node*)hasorderedcomponent, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                    nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hasorderedcomponent, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), nodeIdHasSubType);
 
     UA_ReferenceTypeNode *hasmodelparent = UA_NodeStore_newReferenceTypeNode();
     copyNames((UA_Node*)hasmodelparent, "HasModelParent");
@@ -706,18 +703,24 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     hashistoricalconfiguration->nodeId.identifier.numeric = UA_NS0ID_HASHISTORICALCONFIGURATION;
     hashistoricalconfiguration->isAbstract = false;
     hashistoricalconfiguration->symmetric  = false;
-    addNodeInternal(server, (UA_Node*)hashistoricalconfiguration,
-                    UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
+    addNodeInternal(server, (UA_Node*)hashistoricalconfiguration, UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES), nodeIdHasSubType);
 
-    /*****************/
-    /* Basic Folders */
-    /*****************/
+    /********************/
+    /* Object Hierarchy */
+    /********************/
 
+    /* Bootstrap object hierarchy by manually inserting "root" and "baseobjecttype" */
     UA_ObjectNode *root = UA_NodeStore_newObjectNode();
     copyNames((UA_Node*)root, "Root");
     root->nodeId.identifier.numeric = UA_NS0ID_ROOTFOLDER;
+
+    UA_ObjectTypeNode *baseobjtype = UA_NodeStore_newObjectTypeNode();
+    copyNames((UA_Node*)baseobjtype, "BaseObjectType");
+    baseobjtype->nodeId.identifier.numeric = UA_NS0ID_BASEOBJECTTYPE;
+
     UA_RCU_LOCK();
     UA_NodeStore_insert(server->nodestore, (UA_Node*)root);
+    UA_NodeStore_insert(server->nodestore, (UA_Node*)baseobjtype);
     UA_RCU_UNLOCK();
 
     UA_ObjectNode *objects = UA_NodeStore_newObjectNode();
@@ -756,9 +759,10 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     objecttypes->nodeId.identifier.numeric = UA_NS0ID_OBJECTTYPESFOLDER;
     addNodeInternal(server, (UA_Node*)objecttypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
                     nodeIdOrganizes);
+    /* Link in the bootstrapped baseobjecttype */
+    addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTTYPESFOLDER), nodeIdOrganizes,
+                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), true);
 
-    addObjectTypeNode(server, "BaseObjectType", UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_OBJECTTYPESFOLDER,
-                      UA_NS0ID_ORGANIZES);
     addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTTYPESFOLDER), nodeIdHasTypeDefinition,
                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), true);
@@ -772,6 +776,7 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), true);
     addReferenceInternal(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCETYPESFOLDER),
                          nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), true);
+
     addObjectTypeNode(server, "ServerType", UA_NS0ID_SERVERTYPE, UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
     addObjectTypeNode(server, "ServerDiagnosticsType", UA_NS0ID_SERVERDIAGNOSTICSTYPE,
                       UA_NS0ID_BASEOBJECTTYPE, UA_NS0ID_HASSUBTYPE);
@@ -840,8 +845,6 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
     addVariableTypeNode_subtype(server, "PropertyType", UA_NS0ID_PROPERTYTYPE,
                                 UA_NS0ID_BASEVARIABLETYPE, false);
 
-
-    //Event types folder below is needed by CTT
     /***************/
     /* Event Types */
     /***************/
@@ -855,7 +858,7 @@ UA_Server * UA_Server_new(const UA_ServerConfig config) {
 #endif
 
 #ifdef UA_ENABLE_GENERATE_NAMESPACE0
-    //load the generated namespace
+    /* load the generated namespace externally */
     ua_namespaceinit_generated(server);
 #endif
 

+ 4 - 0
src/server/ua_server_internal.h

@@ -90,4 +90,8 @@ void UA_Server_deleteAllRepeatedJobs(UA_Server *server);
 UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range);
 #endif
 
+UA_StatusCode
+isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode, const UA_NodeId *nodeToFind,
+             const UA_NodeId *referenceTypeId, size_t maxDepth, UA_Boolean *found);
+
 #endif /* UA_SERVER_INTERNAL_H_ */

+ 5 - 3
src/server/ua_services.h

@@ -106,9 +106,11 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session,
 
 /* Add an existing node. The node is assumed to be "finished", i.e. no
  * instantiation from inheritance is necessary */
-void Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
-                               const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
-                               UA_AddNodesResult *result);
+void
+Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
+                          const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_NodeId *typeDefinition, UA_InstantiationCallback *instantiationCallback,
+                          UA_AddNodesResult *result);
 
 /* Used to add one or more References to one or more Nodes. */
 void Service_AddReferences(UA_Server *server, UA_Session *session,

+ 39 - 92
src/server/ua_services_call.c

@@ -24,35 +24,6 @@ getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
     return NULL;
 }
 
-static UA_StatusCode
-isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode, const UA_NodeId *nodeToFind,
-             const UA_NodeId *referenceTypeId, size_t *maxDepth, UA_Boolean *found){
-    *maxDepth = *maxDepth-1;
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    const UA_Node *node = UA_NodeStore_get(ns,rootNode);
-    if(!node)
-        return UA_STATUSCODE_BADINTERNALERROR;
-
-    *found = false;
-    for(size_t i=0; i<node->referencesSize;i++) {
-        if(UA_NodeId_equal(&node->references[i].referenceTypeId, referenceTypeId) &&
-           node->references[i].isInverse == false) {
-           if(UA_NodeId_equal(&node->references[i].targetId.nodeId, nodeToFind)) {
-               *found = true;
-               return UA_STATUSCODE_GOOD;
-           }
-           if(*maxDepth > 0) {
-               retval = isNodeInTree(ns, &node->references[i].targetId.nodeId, nodeToFind,
-                                     referenceTypeId, maxDepth, found);
-               if(*found)
-                   break;
-           }
-        }
-    }
-    *maxDepth = *maxDepth+1;
-    return retval;
-}
-
 static UA_StatusCode
 satisfySignature(UA_Server *server, const UA_Variant *var, const UA_Argument *arg) {
     if(!UA_NodeId_equal(&var->type->typeId, &arg->dataType)){
@@ -63,8 +34,7 @@ satisfySignature(UA_Server *server, const UA_Variant *var, const UA_Argument *ar
         UA_NodeId ENUMERATION_NODEID_NS0 = UA_NODEID_NUMERIC(0,29);
         UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
         UA_Boolean found = false;
-        size_t maxDepth = 1;
-        UA_StatusCode retval = isNodeInTree(server->nodestore, &ENUMERATION_NODEID_NS0, &arg->dataType, &hasSubTypeNodeId, &maxDepth, &found);
+        UA_StatusCode retval = isNodeInTree(server->nodestore, &arg->dataType, &ENUMERATION_NODEID_NS0, &hasSubTypeNodeId, 1, &found);
         if(retval != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADINTERNALERROR;
         if(!found)
@@ -148,95 +118,72 @@ argConformsToDefinition(UA_Server *server, const UA_VariableNode *argRequirement
 void
 Service_Call_single(UA_Server *server, UA_Session *session, const UA_CallMethodRequest *request,
                     UA_CallMethodResult *result) {
+    /* Verify method/object relations. Object must have a hasComponent reference to the method node. */
+    UA_Boolean found = false;
+    UA_NodeId hasComponentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASCOMPONENT);
+    result->statusCode = isNodeInTree(server->nodestore, &request->methodId, &request->objectId,
+                                      &hasComponentNodeId, 1, &found);
+    if(!found)
+        result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        return;
+
+    /* Get/verify the method node */
     const UA_MethodNode *methodCalled =
         (const UA_MethodNode*)UA_NodeStore_get(server->nodestore, &request->methodId);
     if(!methodCalled) {
         result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
         return;
     }
+    if(methodCalled->nodeClass != UA_NODECLASS_METHOD) {
+        result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
+        return;
+    }
+    if(!methodCalled->executable || !methodCalled->userExecutable || !methodCalled->attachedMethod) {
+        result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
+        return;
+    }
 
+    /* Get/verify the object node */
     const UA_ObjectNode *withObject =
         (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, &request->objectId);
     if(!withObject) {
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         return;
     }
-
-    if(methodCalled->nodeClass != UA_NODECLASS_METHOD) {
-        result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
-        return;
-    }
-
     if(withObject->nodeClass != UA_NODECLASS_OBJECT && withObject->nodeClass != UA_NODECLASS_OBJECTTYPE) {
         result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
         return;
     }
 
-    /* Verify method/object relations */
-    // Object must have a hasComponent reference (or any inherited referenceType from sayd reference)
-    // to be valid for a methodCall...
-    result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
-    UA_Boolean found = false;
-    size_t maxDepth = 10;
-    UA_NodeId hasSubTypeNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASSUBTYPE);
-    UA_NodeId hasComponentNodeId = UA_NODEID_NUMERIC(0,UA_NS0ID_HASCOMPONENT);
-    for(size_t i = 0; i < withObject->referencesSize; i++) {
-        if(UA_NodeId_equal(&withObject->references[i].targetId.nodeId, &methodCalled->nodeId)) {
-            if(UA_NodeId_equal(&withObject->references[i].referenceTypeId, &hasComponentNodeId)){
-                result->statusCode = UA_STATUSCODE_GOOD;
-                break;
-            }
-            UA_StatusCode retval = isNodeInTree(server->nodestore, &hasComponentNodeId, &withObject->references[i].referenceTypeId,
-                                                &hasSubTypeNodeId, &maxDepth, &found);
-            if(retval == UA_STATUSCODE_GOOD && found){
-                result->statusCode = UA_STATUSCODE_GOOD;
-                break;
-            }
-            return;
-        }
-    }
-
-    if(result->statusCode != UA_STATUSCODE_GOOD)
-        return;
-
-    /* Verify method executable */
-    if(!methodCalled->executable || !methodCalled->userExecutable) {
-        result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
-        return;
-    }
-
     /* Verify Input Argument count, types and sizes */
-    const UA_VariableNode *inputArguments;
-    inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
-    if(inputArguments) {
-        result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize,
-                                                     request->inputArguments);
-        if(result->statusCode != UA_STATUSCODE_GOOD)
-            return;
-    } else if(request->inputArgumentsSize > 0) {
+    const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
+    if(!inputArguments) {
         result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
         return;
     }
+    result->statusCode = argConformsToDefinition(server, inputArguments, request->inputArgumentsSize,
+                                                 request->inputArguments);
+    if(result->statusCode != UA_STATUSCODE_GOOD)
+        return;
 
-    const UA_VariableNode *outputArguments =
-        getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
+    /* Allocate the output arguments */
+    const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
     if(!outputArguments) {
-        // A MethodNode must have an OutputArguments variable (which may be empty)
         result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
         return;
     }
-
-    /* Call method if available */
-    if(methodCalled->attachedMethod) {
-        result->outputArguments = UA_Array_new(outputArguments->value.variant.value.arrayLength,
-                                               &UA_TYPES[UA_TYPES_VARIANT]);
-        result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
-        result->statusCode = methodCalled->attachedMethod(methodCalled->methodHandle, withObject->nodeId,
-                                                          request->inputArgumentsSize, request->inputArguments,
-                                                          result->outputArgumentsSize, result->outputArguments);
+    result->outputArguments = UA_Array_new(outputArguments->value.variant.value.arrayLength, &UA_TYPES[UA_TYPES_VARIANT]);
+    if(!result->outputArguments) {
+        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+        return;
     }
-    else
-        result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
+    result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
+
+    /* Call the method */
+    result->statusCode = methodCalled->attachedMethod(methodCalled->methodHandle, withObject->nodeId,
+                                                      request->inputArgumentsSize, request->inputArguments,
+                                                      result->outputArgumentsSize, result->outputArguments);
     /* TODO: Verify Output Argument count, types and sizes */
 }
 void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *request,

+ 169 - 77
src/server/ua_services_nodemanagement.c

@@ -1,15 +1,62 @@
 #include "ua_server_internal.h"
 #include "ua_services.h"
 
+/********************/
+/* Helper Functions */
+/********************/
+
+/* Recursively searches "upwards" in the tree following a specific reference type */
+UA_StatusCode
+isNodeInTree(UA_NodeStore *ns, const UA_NodeId *rootNode, const UA_NodeId *nodeToFind,
+             const UA_NodeId *referenceTypeId, size_t maxDepth, UA_Boolean *found) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(UA_NodeId_equal(rootNode, nodeToFind)) {
+        *found = true;
+        return UA_STATUSCODE_GOOD;
+    }
+    const UA_Node *node = UA_NodeStore_get(ns,rootNode);
+    if(!node)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    *found = false;
+    maxDepth = maxDepth - 1;
+    for(size_t i = 0; i < node->referencesSize; i++) {
+        if(!UA_NodeId_equal(&node->references[i].referenceTypeId, referenceTypeId))
+            continue; /* not the reference type we are looking for */
+        if(!node->references[i].isInverse)
+            continue; /* search only upwards */
+        if(UA_NodeId_equal(&node->references[i].targetId.nodeId, nodeToFind)) {
+            *found = true;
+            return UA_STATUSCODE_GOOD;
+        }
+        if(maxDepth > 0) { /* recurse */
+            retval = isNodeInTree(ns, &node->references[i].targetId.nodeId, nodeToFind,
+                                  referenceTypeId, maxDepth, found);
+            if(*found || retval != UA_STATUSCODE_GOOD)
+                break;
+        }
+    }
+    return retval;
+}
+
 /************/
 /* Add Node */
 /************/
 
+static UA_StatusCode
+instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                        const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback);
+static UA_StatusCode
+instantiateObjectNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                      const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback);
+
 void
 Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
                           const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                          const UA_NodeId *typeDefinition, UA_InstantiationCallback *instantiationCallback,
                           UA_AddNodesResult *result) {
     if(node->nodeId.namespaceIndex >= server->namespacesSize) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Namespace invalid");
         result->statusCode = UA_STATUSCODE_BADNODEIDINVALID;
         UA_NodeStore_deleteNode(node);
         return;
@@ -17,6 +64,7 @@ Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
 
     const UA_Node *parent = UA_NodeStore_get(server->nodestore, parentNodeId);
     if(!parent) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Parent node not found");
         result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
         UA_NodeStore_deleteNode(node);
         return;
@@ -25,18 +73,19 @@ Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
     const UA_ReferenceTypeNode *referenceType =
         (const UA_ReferenceTypeNode *)UA_NodeStore_get(server->nodestore, referenceTypeId);
     if(!referenceType) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Reference type to the parent not found");
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         UA_NodeStore_deleteNode(node);
         return;
     }
-
     if(referenceType->nodeClass != UA_NODECLASS_REFERENCETYPE) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Reference type to the parent invalid");
         result->statusCode = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
         UA_NodeStore_deleteNode(node);
         return;
     }
-
     if(referenceType->isAbstract == true) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Abstract feference type to the parent invalid");
         result->statusCode = UA_STATUSCODE_BADREFERENCENOTALLOWED;
         UA_NodeStore_deleteNode(node);
         return;
@@ -45,30 +94,83 @@ Service_AddNodes_existing(UA_Server *server, UA_Session *session, UA_Node *node,
     // todo: test if the referencetype is hierarchical
     // todo: namespace index is assumed to be valid
     result->statusCode = UA_NodeStore_insert(server->nodestore, node);
-    if(result->statusCode == UA_STATUSCODE_GOOD)
-        result->statusCode = UA_NodeId_copy(&node->nodeId, &result->addedNodeId);
-    else
+    if(result->statusCode != UA_STATUSCODE_GOOD) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Node could not be added to the nodestore with error code 0x%08x",
+                             result->statusCode);
         return;
+    }
+    result->statusCode = UA_NodeId_copy(&node->nodeId, &result->addedNodeId);
 
-    // reference back to the parent
+    /* Hierarchical reference back to the parent */
     UA_AddReferencesItem item;
     UA_AddReferencesItem_init(&item);
     item.sourceNodeId = node->nodeId;
     item.referenceTypeId = *referenceTypeId;
     item.isForward = false;
     item.targetNodeId.nodeId = *parentNodeId;
-    Service_AddReferences_single(server, session, &item);
-    // todo: error handling. remove new node from nodestore
-}
+    result->statusCode = Service_AddReferences_single(server, session, &item);
+    if(result->statusCode != UA_STATUSCODE_GOOD) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Could not add the reference to the parent");
+        goto remove_node;
+    }
 
-static UA_StatusCode
-instantiateVariableNode(UA_Server *server, UA_Session *session,
-                        const UA_NodeId *nodeId, const UA_NodeId *typeId, 
-                        UA_InstantiationCallback *instantiationCallback);
-static UA_StatusCode
-instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
-                      UA_InstantiationCallback *instantiationCallback);
+    const UA_NodeId hassubtype = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
+    if(node->nodeClass == UA_NODECLASS_OBJECT) {
+        const UA_NodeId baseobjtype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
+        if(!typeDefinition || UA_NodeId_equal(typeDefinition, &UA_NODEID_NULL)) {
+            /* Objects must have a type reference. Default to BaseObjectType */
+            UA_NodeId *writableTypeDef = UA_alloca(sizeof(UA_NodeId));
+            *writableTypeDef = baseobjtype;
+            typeDefinition = writableTypeDef;
+        } else {
+            /* Check if the supplied type is a subtype of BaseObjectType */
+            UA_Boolean found = false;
+            result->statusCode = isNodeInTree(server->nodestore, typeDefinition, &baseobjtype, &hassubtype, 10, &found);
+            if(!found)
+                result->statusCode = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+            if(result->statusCode != UA_STATUSCODE_GOOD) {
+                UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: The object if not derived from BaseObjectType");
+                goto remove_node;
+            }
+        }
+        result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
+                                                   typeDefinition, instantiationCallback);
+        if(result->statusCode != UA_STATUSCODE_GOOD)
+            goto remove_node;
+    } else if(node->nodeClass == UA_NODECLASS_VARIABLE) {
+        const UA_NodeId basevartype = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE);
+        if(!typeDefinition || UA_NodeId_equal(typeDefinition, &UA_NODEID_NULL)) {
+            /* Variables must have a type reference. Default to BaseVariableType */
+            UA_NodeId *writableTypeDef = UA_alloca(sizeof(UA_NodeId));
+            *writableTypeDef = basevartype;
+            typeDefinition = writableTypeDef;
+        } else {
+            /* Check if the supplied type is a subtype of BaseVariableType */
+            UA_Boolean found = false;
+            result->statusCode = isNodeInTree(server->nodestore, typeDefinition, &basevartype, &hassubtype, 10, &found);
+            if(!found)
+                result->statusCode = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
+            if(result->statusCode != UA_STATUSCODE_GOOD) {
+                UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: The variable if not derived from BaseVariableType");
+                goto remove_node;
+            }
+        }
+        result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
+                                                     typeDefinition, instantiationCallback);
+        if(result->statusCode != UA_STATUSCODE_GOOD)
+            goto remove_node;
+    }
+
+    /* Custom callback */
+    if(instantiationCallback)
+        instantiationCallback->method(result->addedNodeId, *typeDefinition, instantiationCallback->handle);
+
+    return;
+
+ remove_node:
+    Service_DeleteNodes_single(server, &adminSession, &result->addedNodeId, true);
+    UA_AddNodesResult_deleteMembers(result);
+}
 
 /* copy an existing variable under the given parent. then instantiate the
    variable for all hastypedefinitions of the original version. */
@@ -81,7 +183,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(node->nodeClass != UA_NODECLASS_VARIABLE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    
+
     // copy the variable attributes
     UA_VariableAttributes attr;
     UA_VariableAttributes_init(&attr);
@@ -127,10 +229,10 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
             continue;
         instantiateVariableNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
-    
-    if (instantiationCallback != NULL)
-      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
-    
+
+    if(instantiationCallback)
+        instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
 }
@@ -139,14 +241,14 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
-                   const UA_NodeId *referenceType, const UA_NodeId *parent, 
+                   const UA_NodeId *referenceType, const UA_NodeId *parent,
                    UA_InstantiationCallback *instantiationCallback) {
-    const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);  
+    const UA_ObjectNode *node = (const UA_ObjectNode*)UA_NodeStore_get(server->nodestore, variable);
     if(!node)
         return UA_STATUSCODE_BADNODEIDINVALID;
     if(node->nodeClass != UA_NODECLASS_OBJECT)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    
+
     // copy the variable attributes
     UA_ObjectAttributes attr;
     UA_ObjectAttributes_init(&attr);
@@ -184,10 +286,10 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
             continue;
         instantiateObjectNode(server, session, &res.addedNodeId, &rn->targetId.nodeId, instantiationCallback);
     }
-    
-    if (instantiationCallback != NULL)
-      instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
-    
+
+    if(instantiationCallback)
+        instantiationCallback->method(res.addedNodeId, node->nodeId, instantiationCallback->handle);
+
     UA_AddNodesResult_deleteMembers(&res);
     return UA_STATUSCODE_GOOD;
 }
@@ -201,15 +303,18 @@ setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* n
 }
 
 static UA_StatusCode
-instantiateObjectNode(UA_Server *server, UA_Session *session,
-                      const UA_NodeId *nodeId, const UA_NodeId *typeId, 
-                      UA_InstantiationCallback *instantiationCallback) {   
+instantiateObjectNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                      const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
     const UA_ObjectTypeNode *typenode = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
-    if(!typenode)
-      return UA_STATUSCODE_BADNODEIDINVALID;
-    if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE)
-      return UA_STATUSCODE_BADNODECLASSINVALID;
-    
+    if(!typenode) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Could not instantiate an object from an unknown nodeid");
+        return UA_STATUSCODE_BADNODEIDINVALID;
+    }
+    if(typenode->nodeClass != UA_NODECLASS_OBJECTTYPE) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Could not instantiate an object from a non-objecttype node");
+        return UA_STATUSCODE_BADNODECLASSINVALID;
+    }
+
     /* Add all the child nodes */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
@@ -265,13 +370,17 @@ instantiateObjectNode(UA_Server *server, UA_Session *session,
 
 static UA_StatusCode
 instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-    const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
+                        const UA_NodeId *typeId, UA_InstantiationCallback *instantiationCallback) {
     const UA_ObjectTypeNode *typenode = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
-    if(!typenode)
+    if(!typenode) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Could not instantiate a variable from an unknown nodeid");
         return UA_STATUSCODE_BADNODEIDINVALID;
-    if(typenode->nodeClass != UA_NODECLASS_VARIABLETYPE)
+    }
+    if(typenode->nodeClass != UA_NODECLASS_VARIABLETYPE) {
+        UA_LOG_DEBUG_SESSION(server->config.logger, session, "AddNodes: Could not instantiate a variable from a non-variabletype node");
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    
+    }
+
     /* get the references to child properties */
     UA_BrowseDescription browseChildren;
     UA_BrowseDescription_init(&browseChildren);
@@ -436,8 +545,8 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_Ad
         result->statusCode = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
         return;
     }
-    
-    /* create the node */
+
+    /* Create the node */
     UA_Node *node;
     switch(item->nodeClass) {
     case UA_NODECLASS_OBJECT:
@@ -503,25 +612,8 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, const UA_Ad
 
     /* add it to the server */
     Service_AddNodes_existing(server, session, node, &item->parentNodeId.nodeId,
-                              &item->referenceTypeId, result);
-    if(result->statusCode != UA_STATUSCODE_GOOD)
-        return;
-    
-    /* instantiate if it has a type */
-    if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
-        if (instantiationCallback != NULL)
-          instantiationCallback->method(result->addedNodeId, item->typeDefinition.nodeId,
-                                        instantiationCallback->handle);
-        
-        if(item->nodeClass == UA_NODECLASS_OBJECT)
-            result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
-                                                       &item->typeDefinition.nodeId, instantiationCallback);
-        else if(item->nodeClass == UA_NODECLASS_VARIABLE)
-            result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
-                                                         &item->typeDefinition.nodeId, instantiationCallback);
-    }
-
-    /* if instantiation failed, remove the node */
+                              &item->referenceTypeId, &item->typeDefinition.nodeId,
+                              instantiationCallback, result);
     if(result->statusCode != UA_STATUSCODE_GOOD)
         Service_DeleteNodes_single(server, session, &result->addedNodeId, true);
 }
@@ -540,7 +632,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
-    
+
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
 #ifdef _MSC_VER
     UA_Boolean *isExternal = UA_alloca(size);
@@ -567,7 +659,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
                       indices, (UA_UInt32)indexSize, response->results, response->diagnosticInfos);
     }
 #endif
-    
+
     response->resultsSize = size;
     for(size_t i = 0; i < size; i++) {
 #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
@@ -598,7 +690,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     result.statusCode |= UA_NodeId_copy(&referenceTypeId, &item.referenceTypeId);
     result.statusCode |= UA_NodeId_copy(&requestedNewNodeId, &item.requestedNewNodeId.nodeId);
     result.statusCode |= UA_NodeId_copy(&typeDefinition, &item.typeDefinition.nodeId);
-    
+
     UA_VariableAttributes attrCopy;
     result.statusCode |= UA_VariableAttributes_copy(&attr, &attrCopy);
     if(result.statusCode != UA_STATUSCODE_GOOD) {
@@ -624,7 +716,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
     node->valueRank = attr.valueRank;
     UA_RCU_LOCK();
     Service_AddNodes_existing(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
-                              &item.referenceTypeId, &result);
+                              &item.referenceTypeId, &item.typeDefinition.nodeId, NULL, &result);
     UA_RCU_UNLOCK();
     UA_AddNodesItem_deleteMembers(&item);
     UA_VariableAttributes_deleteMembers(&attrCopy);
@@ -643,12 +735,12 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
                         const UA_QualifiedName browseName, const UA_MethodAttributes attr,
                         UA_MethodCallback method, void *handle,
-                        size_t inputArgumentsSize, const UA_Argument* inputArguments, 
+                        size_t inputArgumentsSize, const UA_Argument* inputArguments,
                         size_t outputArgumentsSize, const UA_Argument* outputArguments,
                         UA_NodeId *outNewNodeId) {
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
-    
+
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
     result.statusCode = UA_QualifiedName_copy(&browseName, &item.browseName);
@@ -656,7 +748,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     result.statusCode |= UA_NodeId_copy(&parentNodeId, &item.parentNodeId.nodeId);
     result.statusCode |= UA_NodeId_copy(&referenceTypeId, &item.referenceTypeId);
     result.statusCode |= UA_NodeId_copy(&requestedNewNodeId, &item.requestedNewNodeId.nodeId);
-    
+
     UA_MethodAttributes attrCopy;
     result.statusCode |= UA_MethodAttributes_copy(&attr, &attrCopy);
     if(result.statusCode != UA_STATUSCODE_GOOD) {
@@ -672,7 +764,7 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
         UA_MethodAttributes_deleteMembers(&attrCopy);
         return result.statusCode;
     }
-    
+
     copyStandardAttributes((UA_Node*)node, &item, (UA_NodeAttributes*)&attrCopy);
     node->executable = attrCopy.executable;
     node->userExecutable = attrCopy.executable;
@@ -683,15 +775,15 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
 
     UA_RCU_LOCK();
     Service_AddNodes_existing(server, &adminSession, (UA_Node*)node, &item.parentNodeId.nodeId,
-                              &item.referenceTypeId, &result);
+                              &item.referenceTypeId, &item.typeDefinition.nodeId, NULL, &result);
     UA_RCU_UNLOCK();
     if(result.statusCode != UA_STATUSCODE_GOOD)
         return result.statusCode;
-    
+
     UA_ExpandedNodeId parent;
     UA_ExpandedNodeId_init(&parent);
     parent.nodeId = result.addedNodeId;
-    
+
     const UA_NodeId hasproperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
     UA_VariableNode *inputArgumentsVariableNode = UA_NodeStore_newVariableNode();
     inputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
@@ -704,11 +796,11 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     UA_AddNodesResult inputAddRes;
     UA_RCU_LOCK();
     Service_AddNodes_existing(server, &adminSession, (UA_Node*)inputArgumentsVariableNode,
-                             &parent.nodeId, &hasproperty, &inputAddRes);
+                              &parent.nodeId, &hasproperty, &UA_NODEID_NULL, NULL, &inputAddRes);
     UA_RCU_UNLOCK();
     // todo: check if adding succeeded
     UA_AddNodesResult_deleteMembers(&inputAddRes);
-    
+
     /* create OutputArguments */
     UA_VariableNode *outputArgumentsVariableNode  = UA_NodeStore_newVariableNode();
     outputArgumentsVariableNode->nodeId.namespaceIndex = result.addedNodeId.namespaceIndex;
@@ -721,11 +813,11 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
     UA_AddNodesResult outputAddRes;
     UA_RCU_LOCK();
     Service_AddNodes_existing(server, &adminSession, (UA_Node*)outputArgumentsVariableNode,
-                              &parent.nodeId, &hasproperty, &outputAddRes);
+                              &parent.nodeId, &hasproperty, &UA_NODEID_NULL, NULL, &outputAddRes);
     UA_RCU_UNLOCK();
     // todo: check if adding succeeded
     UA_AddNodesResult_deleteMembers(&outputAddRes);
-    
+
     if(outNewNodeId)
         *outNewNodeId = result.addedNodeId; // don't deleteMember the result
     else

+ 7 - 14
src/server/ua_services_view.c

@@ -20,10 +20,10 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
         if(curr->nodeClass == UA_NODECLASS_OBJECT || curr->nodeClass == UA_NODECLASS_VARIABLE) {
             for(size_t i = 0; i < curr->referencesSize; i++) {
                 UA_ReferenceNode *refnode = &curr->references[i];
-                if(refnode->referenceTypeId.identifier.numeric != UA_NS0ID_HASTYPEDEFINITION)
-                    continue;
-                retval |= UA_ExpandedNodeId_copy(&refnode->targetId, &descr->typeDefinition);
-                break;
+                if(refnode->referenceTypeId.identifier.numeric == UA_NS0ID_HASTYPEDEFINITION) {
+                    retval |= UA_ExpandedNodeId_copy(&refnode->targetId, &descr->typeDefinition);
+                    break;
+                }
             }
         }
     }
@@ -285,8 +285,8 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
     UA_Boolean isExternal = false;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     for(; referencesIndex < node->referencesSize && referencesCount < real_maxrefs; referencesIndex++) {
-    	isExternal = false;
-    	const UA_Node *current =
+        isExternal = false;
+        const UA_Node *current =
             returnRelevantNode(server, descr, all_refs, &node->references[referencesIndex],
                                relevant_refs, relevant_refs_size, &isExternal);
         if(!current)
@@ -299,13 +299,6 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
                                                descr->resultMask, &result->references[referencesCount]);
             referencesCount++;
         }
-#ifdef UA_ENABLE_EXTERNAL_NAMESPACES
-        /* relevant_node returns a node malloced by the nodestore.
-           if it is external (there is no UA_Node_new function) */
-   //     if(isExternal == true)
-   //         UA_Node_deleteMembersAnyNodeClass(current);
-   //TODO something's wrong here...
-#endif
     }
 
     result->referencesSize = referencesCount;
@@ -584,7 +577,7 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
 #else
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-#endif /*NO_ALLOCA */
+#endif /* NO_ALLOCA */
     memset(isExternal, false, sizeof(UA_Boolean) * size);
     for(size_t j = 0; j < server->externalNamespacesSize; j++) {
         size_t indexSize = 0;