Browse Source

Conflicts:
src/ua_types_encoding_binary.h

ichrispa 9 years ago
parent
commit
d9c16defb5

+ 6 - 0
CMakeLists.txt

@@ -174,6 +174,12 @@ if(ENABLE_EXTERNAL_NAMESPACES)
     add_definitions(-DUA_EXTERNAL_NAMESPACES)
 endif()
 
+## enable dynamic nodeset
+option(ENABLE_ADDNODES "Enable dynamic addition of nodes" ON)
+if(ENABLE_ADDNODES)
+    add_definitions(-DENABLE_ADDNODES )
+endif()
+
 ## set the precompiler flags
 configure_file("include/ua_config.h.in" "${PROJECT_BINARY_DIR}/src_generated/ua_config.h")
 

+ 81 - 2
examples/client.c

@@ -4,8 +4,11 @@
     #include "ua_nodeids.h"
     #include "networklayer_tcp.h"
     #include "logger_stdout.h"
+    #include "ua_types_encoding_binary.h"
 #else
     #include "open62541.h"
+    #include <string.h>
+    #include <stdlib.h>
 #endif
 
 #include <stdio.h>
@@ -86,14 +89,90 @@ int main(int argc, char *argv[]) {
     wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT32];
     wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the integer on deletion
     wReq.nodesToWrite[0].value.value.data = &value;
-
+    
     UA_WriteResponse wResp = UA_Client_write(client, &wReq);
     if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
             printf("the new value is: %i\n", value);
-
     UA_WriteRequest_deleteMembers(&wReq);
     UA_WriteResponse_deleteMembers(&wResp);
 
+#ifdef ENABLE_ADDNODES 
+    /* Create a new object type node */
+    // New ReferenceType
+    UA_AddNodesResponse *adResp = UA_Client_createReferenceTypeNode(client,
+        UA_EXPANDEDNODEID_NUMERIC(1, 12133), // Assign this NodeId (will fail if client is called multiple times)
+        UA_QUALIFIEDNAME(0, "NewReference"),
+        UA_LOCALIZEDTEXT("en_US", "TheNewReference"),
+        UA_LOCALIZEDTEXT("en_US", "References something that might or might not exist."),
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+        (UA_UInt32) 0, (UA_UInt32) 0, 
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+        UA_LOCALIZEDTEXT("en_US", "IsNewlyReferencedBy"));
+    if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) {
+        printf("Created 'NewReference' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric );
+    }
+    UA_AddNodesResponse_deleteMembers(adResp);
+    free(adResp);
+    
+    // New ObjectType
+    adResp = UA_Client_createObjectTypeNode(client,    
+        UA_EXPANDEDNODEID_NUMERIC(1, 12134), // Assign this NodeId (will fail if client is called multiple times)
+        UA_QUALIFIEDNAME(0, "NewObjectType"),
+        UA_LOCALIZEDTEXT("en_US", "TheNewObjectType"),
+        UA_LOCALIZEDTEXT("en_US", "Put innovative description here."),
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+        (UA_UInt32) 0, (UA_UInt32) 0, 
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER));
+        if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) {
+        printf("Created 'NewObjectType' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric );
+    }
+    
+    // New Object
+    adResp = UA_Client_createObjectNode(client,    
+        UA_EXPANDEDNODEID_NUMERIC(1, 0), // Assign new/random NodeID  
+        UA_QUALIFIEDNAME(0, "TheNewGreatNodeBrowseName"),
+        UA_LOCALIZEDTEXT("en_US", "TheNewGreatNode"),
+        UA_LOCALIZEDTEXT("de_DE", "Hier koennte Ihre Webung stehen!"),
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+        (UA_UInt32) 0, (UA_UInt32) 0, 
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER));
+    if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) {
+        printf("Created 'NewObject' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric );
+    }
+    
+    UA_AddNodesResponse_deleteMembers(adResp);
+    free(adResp);
+    
+    // New Integer Variable
+    UA_Variant *theValue = UA_Variant_new();
+    UA_Int32 *theValueDate = UA_Int32_new();
+    *theValueDate = 1234;
+    theValue->type = &UA_TYPES[UA_TYPES_INT32];
+    theValue->data = theValueDate;
+    
+    adResp = UA_Client_createVariableNode(client,
+        UA_EXPANDEDNODEID_NUMERIC(1, 0), // Assign new/random NodeID  
+        UA_QUALIFIEDNAME(0, "VariableNode"),
+        UA_LOCALIZEDTEXT("en_US", "TheNewVariableNode"),
+        UA_LOCALIZEDTEXT("en_US", "This integer is just amazing - it has digits and everything."),
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+        (UA_UInt32) 0, (UA_UInt32) 0, 
+        UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+        UA_NODEID_NUMERIC(0, UA_NS0ID_INT32),
+        theValue);
+    if (adResp->resultsSize > 0 && adResp->results[0].statusCode == UA_STATUSCODE_GOOD ) {
+        printf("Created 'NewVariable' with numeric NodeID %u\n", adResp->results[0].addedNodeId.identifier.numeric );
+    }
+    UA_AddNodesResponse_deleteMembers(adResp);
+    free(adResp);
+    free(theValue);
+    /* Done creating a new node*/
+#endif
+
     UA_Client_disconnect(client);
     UA_Client_delete(client);
     return UA_STATUSCODE_GOOD;

+ 21 - 1
include/ua_client.h

@@ -57,7 +57,27 @@ UA_AddReferencesResponse UA_EXPORT
 UA_DeleteNodesResponse UA_EXPORT UA_Client_deleteNodes(UA_Client *client, UA_DeleteNodesRequest *request);
 UA_DeleteReferencesResponse UA_EXPORT
     UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request);
-    
+
+
+/* Client-Side Macro/Procy functions */
+UA_AddNodesResponse UA_EXPORT *UA_Client_createObjectNode(  UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                            UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                            UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition);
+
+UA_AddNodesResponse UA_EXPORT *UA_Client_createVariableNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                            UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                            UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition, 
+                                                            UA_NodeId dataType, UA_Variant *value );
+
+UA_AddNodesResponse UA_EXPORT *UA_Client_createReferenceTypeNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                            UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                            UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition,
+                                                            UA_LocalizedText inverseName );
+
+UA_AddNodesResponse UA_EXPORT *UA_Client_createObjectTypeNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                            UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                            UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 170 - 0
src/client/ua_client.c

@@ -578,3 +578,173 @@ UA_DeleteReferencesResponse UA_Client_deleteReferences(UA_Client *client, UA_Del
                        &response, &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]);
     return response;
 }
+
+/**********************************/
+/* User-Facing Macros-Function    */
+/**********************************/
+#define ADDNODES_COPYDEFAULTATTRIBUTES(REQUEST,ATTRIBUTES) do {                           \
+    ATTRIBUTES.specifiedAttributes = 0;                                                   \
+    if(! UA_LocalizedText_copy(&description, &(ATTRIBUTES.description)))                  \
+        ATTRIBUTES.specifiedAttributes |=  UA_NODEATTRIBUTESMASK_DESCRIPTION;             \
+    if(! UA_LocalizedText_copy(&displayName, &(ATTRIBUTES.displayName)))                  \
+        ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_DISPLAYNAME;              \
+    ATTRIBUTES.userWriteMask       = userWriteMask;                                       \
+    ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERWRITEMASK;                \
+    ATTRIBUTES.writeMask           = writeMask;                                           \
+    ATTRIBUTES.specifiedAttributes |= UA_NODEATTRIBUTESMASK_WRITEMASK;                    \
+    UA_QualifiedName_copy(&browseName, &(REQUEST.nodesToAdd[0].browseName));              \
+    UA_ExpandedNodeId_copy(&parentNodeId, &(REQUEST.nodesToAdd[0].parentNodeId));         \
+    UA_NodeId_copy(&referenceTypeId, &(REQUEST.nodesToAdd[0].referenceTypeId));           \
+    UA_ExpandedNodeId_copy(&typeDefinition, &(REQUEST.nodesToAdd[0].typeDefinition));     \
+    UA_ExpandedNodeId_copy(&reqId, &(REQUEST.nodesToAdd[0].requestedNewNodeId ));         \
+    REQUEST.nodesToAddSize = 1;                                                           \
+    } while(0)
+    
+#define ADDNODES_PACK_AND_SEND(PREQUEST,PATTRIBUTES,PNODETYPE) do {                                                                     \
+    PREQUEST.nodesToAdd[0].nodeAttributes.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;                                  \
+    PREQUEST.nodesToAdd[0].nodeAttributes.typeId   = UA_NODEID_NUMERIC(0, UA_NS0ID_##PNODETYPE##ATTRIBUTES + UA_ENCODINGOFFSET_BINARY); \
+    PREQUEST.nodesToAdd[0].nodeAttributes.body.length = UA_calcSizeBinary(&PATTRIBUTES, &UA_TYPES[UA_TYPES_##PNODETYPE##ATTRIBUTES]);   \
+    PREQUEST.nodesToAdd[0].nodeAttributes.body.data = (void *) malloc(PREQUEST.nodesToAdd[0].nodeAttributes.body.length);               \
+    size_t encOffset = 0;                                                                                                               \
+    UA_encodeBinary(&PATTRIBUTES,&UA_TYPES[UA_TYPES_##PNODETYPE##ATTRIBUTES], &(PREQUEST.nodesToAdd[0].nodeAttributes.body), &encOffset);       \
+    *(adRes) = UA_Client_addNodes(client, &PREQUEST);                                                                                   \
+    UA_AddNodesRequest_deleteMembers(&PREQUEST);                                                                                        \
+} while(0)
+    
+/* NodeManagement */
+UA_AddNodesResponse *UA_Client_createObjectNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition ) {
+    UA_AddNodesRequest adReq;
+    UA_AddNodesRequest_init(&adReq);
+
+    UA_AddNodesResponse *adRes;
+    adRes = UA_AddNodesResponse_new();
+    UA_AddNodesResponse_init(adRes);
+
+    UA_ObjectAttributes vAtt;
+    UA_ObjectAttributes_init(&vAtt);
+    adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
+    UA_AddNodesItem_init(adReq.nodesToAdd);
+
+    // Default node properties and attributes
+    ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
+    
+    // Specific to objects
+    adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_OBJECT;
+    vAtt.eventNotifier       = 0;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_EVENTNOTIFIER;
+
+    ADDNODES_PACK_AND_SEND(adReq,vAtt,OBJECT);
+
+    return adRes;
+}
+
+UA_AddNodesResponse *UA_Client_createVariableNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                    UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                    UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition, 
+                                                    UA_NodeId dataType, UA_Variant *value) {
+    UA_AddNodesRequest adReq;
+    UA_AddNodesRequest_init(&adReq);
+    
+    UA_AddNodesResponse *adRes;
+    adRes = UA_AddNodesResponse_new();
+    UA_AddNodesResponse_init(adRes);
+    
+    UA_VariableAttributes vAtt;
+    UA_VariableAttributes_init(&vAtt);
+    adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
+    UA_AddNodesItem_init(adReq.nodesToAdd);
+    
+    // Default node properties and attributes
+    ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
+    
+    // Specific to variables
+    adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_VARIABLE;
+    vAtt.accessLevel              = 0;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ACCESSLEVEL;
+    vAtt.userAccessLevel          = 0;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_USERACCESSLEVEL;
+    vAtt.minimumSamplingInterval  = 100;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL;
+    vAtt.historizing              = UA_FALSE;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_HISTORIZING;
+    
+    if (value != NULL) {
+        UA_Variant_copy(value, &(vAtt.value));
+        vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUE;
+        vAtt.valueRank            = -2;
+        vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_VALUERANK;
+        // These are defined by the variant
+        //vAtt.arrayDimensionsSize  = value->arrayDimensionsSize;
+        //vAtt.arrayDimensions      = NULL;
+    }
+    UA_NodeId_copy(&dataType, &(vAtt.dataType));
+    
+    ADDNODES_PACK_AND_SEND(adReq,vAtt,VARIABLE);
+    
+    return adRes;
+}
+
+UA_AddNodesResponse *UA_Client_createReferenceTypeNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                  UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                  UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition,
+                                                  UA_LocalizedText inverseName ) {
+    UA_AddNodesRequest adReq;
+    UA_AddNodesRequest_init(&adReq);
+    
+    UA_AddNodesResponse *adRes;
+    adRes = UA_AddNodesResponse_new();
+    UA_AddNodesResponse_init(adRes);
+    
+    UA_ReferenceTypeAttributes vAtt;
+    UA_ReferenceTypeAttributes_init(&vAtt);
+    adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
+    UA_AddNodesItem_init(adReq.nodesToAdd);
+    
+    // Default node properties and attributes
+    ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
+
+    // Specific to referencetypes
+    adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_REFERENCETYPE;
+    UA_LocalizedText_copy(&inverseName, &(vAtt.inverseName));
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_INVERSENAME;
+    vAtt.symmetric = UA_FALSE;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_SYMMETRIC;
+    vAtt.isAbstract = UA_FALSE;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ISABSTRACT;
+    
+    
+    ADDNODES_PACK_AND_SEND(adReq,vAtt,REFERENCETYPE);
+    
+    return adRes;
+}
+
+UA_AddNodesResponse *UA_Client_createObjectTypeNode(UA_Client *client, UA_ExpandedNodeId reqId, UA_QualifiedName browseName, UA_LocalizedText displayName, 
+                                                    UA_LocalizedText description, UA_ExpandedNodeId parentNodeId, UA_NodeId referenceTypeId,
+                                                    UA_UInt32 userWriteMask, UA_UInt32 writeMask, UA_ExpandedNodeId typeDefinition) {
+    UA_AddNodesRequest adReq;
+    UA_AddNodesRequest_init(&adReq);
+    
+    UA_AddNodesResponse *adRes;
+    adRes = UA_AddNodesResponse_new();
+    UA_AddNodesResponse_init(adRes);
+    
+    UA_ObjectTypeAttributes vAtt;
+    UA_ObjectTypeAttributes_init(&vAtt);
+    adReq.nodesToAdd = (UA_AddNodesItem *) UA_AddNodesItem_new();
+    UA_AddNodesItem_init(adReq.nodesToAdd);
+    
+    // Default node properties and attributes
+    ADDNODES_COPYDEFAULTATTRIBUTES(adReq, vAtt);
+    
+    // Specific to referencetypes
+    adReq.nodesToAdd[0].nodeClass = UA_NODECLASS_OBJECTTYPE;
+    vAtt.isAbstract = UA_FALSE;
+    vAtt.specifiedAttributes |= UA_NODEATTRIBUTESMASK_ISABSTRACT;
+    
+    
+    ADDNODES_PACK_AND_SEND(adReq,vAtt,OBJECTTYPE);
+    
+    return adRes;
+}

+ 13 - 6
src/server/ua_nodestore.c

@@ -245,16 +245,23 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
         if(expand(ns) != UA_STATUSCODE_GOOD)
             return UA_STATUSCODE_BADINTERNALERROR;
     }
-    
     // get a free slot
     struct nodeEntry **slot;
-    if(UA_NodeId_isNull(&node->nodeId)) {
+    //FIXME: a bit dirty workaround of preserving namespace
+    //namespace index is assumed to be valid
+    UA_NodeId tempNodeid;
+    UA_NodeId_copy(&node->nodeId, &tempNodeid);
+    tempNodeid.namespaceIndex = 0;
+    if(UA_NodeId_isNull(&tempNodeid)) {
         // find a unique nodeid that is not taken
         node->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-        node->nodeId.namespaceIndex = 1; // namespace 1 is always in the local nodestore
-        if(node->nodeClass==UA_NODECLASS_VARIABLE){ //set namespaceIndex in browseName in case id is generated
-        	((UA_VariableNode*)node)->browseName.namespaceIndex=node->nodeId.namespaceIndex;
-        }
+
+        if(node->nodeId.namespaceIndex==0) //original request for ns=0 should yield ns=1
+            node->nodeId.namespaceIndex=1;
+
+        //set namespaceIndex in browseName in case id is generated
+        node->browseName.namespaceIndex=node->nodeId.namespaceIndex;
+
         UA_Int32 identifier = ns->count+1; // start value
         UA_Int32 size = ns->size;
         hash_t increase = mod2(identifier, size);

+ 11 - 2
src/server/ua_nodestore_concurrent.c

@@ -154,7 +154,12 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
         entry->refcount++;
 
     struct cds_lfht_node *result;
-    if(!UA_NodeId_isNull(&node->nodeId)) {
+    //FIXME: a bit dirty workaround of preserving namespace
+    //namespace index is assumed to be valid
+    UA_NodeId tempNodeid;
+    UA_NodeId_copy(&node->nodeId, &tempNodeid);
+    tempNodeid.namespaceIndex = 0;
+    if(!UA_NodeId_isNull(&tempNodeid)) {
         hash_t h = hash(&node->nodeId);
         rcu_read_lock();
         result = cds_lfht_add_unique(ns->ht, h, compare, &entry->node.nodeId, &entry->htn);
@@ -168,10 +173,14 @@ UA_StatusCode UA_NodeStore_insert(UA_NodeStore *ns, UA_Node *node, const UA_Node
     } else {
         /* create a unique nodeid */
         ((UA_Node *)&entry->node)->nodeId.identifierType = UA_NODEIDTYPE_NUMERIC;
-        ((UA_Node *)&entry->node)->nodeId.namespaceIndex = 1; // namespace 1 is always in the local nodestore
+        if(((UA_Node *)&entry->node)->nodeId.namespaceIndex == 0) //original request for ns=0 should yield ns=1
+            ((UA_Node *)&entry->node)->nodeId.namespaceIndex = 1;
         if(((UA_Node *)&entry->node)->nodeClass==UA_NODECLASS_VARIABLE){ //set namespaceIndex in browseName in case id is generated
         	((UA_VariableNode*)&entry->node)->browseName.namespaceIndex=((UA_Node *)&entry->node)->nodeId.namespaceIndex;
         }
+        //set namespaceIndex in browseName in case id is generated
+        ((UA_Node *)&entry->node)->browseName.namespaceIndex=node->nodeId.namespaceIndex;
+
         unsigned long identifier;
         long before, after;
         rcu_read_lock();

+ 6 - 1
src/server/ua_server_addressspace.c

@@ -331,8 +331,13 @@ UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, UA_Node *no
     }
 
     // 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;
-    if(UA_NodeId_isNull(&node->nodeId)) {
+    UA_NodeId 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;

+ 5 - 0
src/server/ua_server_binary.c

@@ -326,6 +326,11 @@ static void processMSG(UA_Connection *connection, UA_Server *server, const UA_By
     case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
         INVOKE_SERVICE(TranslateBrowsePathsToNodeIds, UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE);
         break;
+#ifdef ENABLE_ADDNODES 
+    case UA_NS0ID_ADDNODESREQUEST:
+        INVOKE_SERVICE(AddNodes, UA_TYPES_ADDNODESRESPONSE);
+        break;
+#endif
     default: {
         if(requestType.namespaceIndex == 0 && requestType.identifier.numeric==787)
             UA_LOG_INFO(server->logger, UA_LOGCATEGORY_COMMUNICATION,

+ 22 - 16
src/server/ua_services_nodemanagement.c

@@ -5,20 +5,21 @@
 #include "ua_session.h"
 #include "ua_util.h"
 
-#define COPY_STANDARDATTRIBUTES do {                                    \
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {  \
-        vnode->displayName = attr.displayName;                          \
-        UA_LocalizedText_init(&attr.displayName);                       \
-    }                                                                   \
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DESCRIPTION) {  \
-        vnode->description = attr.description;                          \
-        UA_LocalizedText_init(&attr.description);                       \
-    }                                                                   \
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_WRITEMASK)      \
-        vnode->writeMask = attr.writeMask;                              \
-    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERWRITEMASK)  \
-        vnode->userWriteMask = attr.userWriteMask;                      \
-    } while(0)
+#define COPY_STANDARDATTRIBUTES do {                                       \
+    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {     \
+        vnode->displayName = attr.displayName;                             \
+        UA_LocalizedText_copy(&attr.displayName, &(vnode->displayName));   \
+        UA_LocalizedText_init(&attr.displayName);                          \
+    }                                                                      \
+    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DESCRIPTION) {     \
+        UA_LocalizedText_copy(&attr.description, &(vnode->description));   \
+        UA_LocalizedText_init(&attr.description);                          \
+    }                                                                      \
+    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_WRITEMASK)         \
+        vnode->writeMask = attr.writeMask;                                 \
+    if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_USERWRITEMASK)     \
+        vnode->userWriteMask = attr.userWriteMask;                         \
+} while(0)
 
 static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node) {
     if(attributes->typeId.identifier.numeric !=
@@ -207,7 +208,12 @@ static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_Add
 
     if(result->statusCode != UA_STATUSCODE_GOOD)
         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);
@@ -244,7 +250,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
-
+    
 #ifdef UA_EXTERNAL_NAMESPACES
 #ifdef NO_ALLOCA
     UA_Boolean isExternal[size];

+ 0 - 1
src/ua_types_encoding_binary.h

@@ -61,7 +61,6 @@ UA_TYPE_BINARY_ENCODING(UA_DiagnosticInfo)
 UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *dataType, UA_ByteString *dst,
                               size_t *UA_RESTRICT offset);
 UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t * UA_RESTRICT offset, void *dst,
-                              const UA_DataType *dataType);
 /// @}
 
 #endif /* UA_TYPES_ENCODING_BINARY_H_ */