Ver código fonte

split reference insertion into two "single" operations for backwards/forwards

Julius Pfrommer 10 anos atrás
pai
commit
d5bc5493a8

+ 2 - 4
CMakeLists.txt

@@ -25,18 +25,16 @@ set(lib_sources src/ua_types.c
                 src/ua_session.c
                 src/ua_util.c
                 src/server/ua_server.c
+				src/server/ua_server_addressspace.c
+				src/server/ua_server_binary.c
                 src/server/ua_securechannel_manager.c
                 src/server/ua_session_manager.c
-				src/server/ua_server_binary.c
                 src/server/ua_services_attribute.c
                 src/server/ua_services_session.c
                 src/server/ua_services_discovery.c
                 src/server/ua_services_securechannel.c
                 src/server/ua_services_nodemanagement.c
                 src/server/ua_services_view.c
-				#src/server/nodestore/open62541_nodestore_view.c
-				#src/server/nodestore/open62541_nodestore_attribute.c
-				#src/server/nodestore/open62541_nodestore_nodemanagement.c
 				${exported_headers}
 				${generated_headers}
                 ${headers})

+ 6 - 10
examples/opcuaServer.c

@@ -54,19 +54,14 @@ int main(int argc, char** argv) {
 	UA_String endpointUrl;
     UA_String_copycstring("opc.tcp://192.168.56.101:16664",&endpointUrl);
 	UA_ByteString certificate = loadCertificate();
-	//create a nodestore which holds all nodes
-	/* open62541NodeStore *open62541NodeStore; */
-	/* open62541NodeStore_new(&open62541NodeStore); */
-	/* open62541NodeStore_setNodeStore(open62541NodeStore); */
-
-	//create server and use default open62541Nodestore for storing the nodes
 	UA_Server *server = UA_Server_new(&endpointUrl, &certificate);
 
 	//add a node to the adresspace
-    UA_Int32 myInteger = 42;
+    UA_Int32 *myInteger = malloc(sizeof(UA_Int32));
+    *myInteger = 42;
     UA_QualifiedName myIntegerName;
     UA_QualifiedName_copycstring("the answer is",&myIntegerName);
-    UA_Server_addScalarVariableNode(server, &myIntegerName, (void*)&myInteger, &UA_TYPES[UA_INT32],
+    UA_Server_addScalarVariableNode(server, &myIntegerName, myInteger, &UA_TYPES[UA_INT32],
                                     &UA_EXPANDEDNODEIDS[UA_OBJECTSFOLDER], &UA_NODEIDS[UA_ORGANIZES]);
     UA_QualifiedName_deleteMembers(&myIntegerName);
     
@@ -87,7 +82,8 @@ int main(int argc, char** argv) {
         tmpNode->value.storage.data.dataPtr = &data;
         tmpNode->value.storageType = UA_VARIANT_DATA_NODELETE;
         tmpNode->value.storage.data.arrayLength = 1;
-        UA_Server_addNode(server, (UA_Node**)&tmpNode, &UA_NODEIDS[UA_OBJECTSFOLDER], &UA_NODEIDS[UA_HASCOMPONENT]);
+        UA_Server_addNode(server, (const UA_Node**)&tmpNode, &UA_EXPANDEDNODEIDS[UA_OBJECTSFOLDER],
+                          &UA_NODEIDS[UA_HASCOMPONENT]);
     }
 #endif
 	
@@ -99,5 +95,5 @@ int main(int argc, char** argv) {
 	UA_Server_delete(server);
 	NetworklayerTCP_delete(nl);
     UA_String_deleteMembers(&endpointUrl);
-	return retval == UA_STATUSCODE_GOOD ? 0 : retval;
+	return retval;
 }

+ 90 - 43
include/ua_server.h

@@ -25,54 +25,98 @@ extern "C" {
 #include "ua_connection.h"
 #include "ua_log.h"
 
-/** @defgroup server Server */
+/**
+ * @defgroup server Server
+ *
+ * @brief This module describes the server object and functions to interact with * it.
+ *
+ * @{
+ */
 
 struct UA_Server;
 typedef struct UA_Server UA_Server;
 
 UA_Server UA_EXPORT * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertificate);
 void UA_EXPORT UA_Server_delete(UA_Server *server);
-void UA_EXPORT UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, const UA_ByteString *msg);
-
-/* Services for local use */
-UA_AddNodesResult UA_EXPORT UA_Server_addNode(UA_Server *server, const UA_Node **node,
-                                              const UA_ExpandedNodeId *parentNodeId,
-                                              const UA_NodeId *referenceTypeId);
-UA_StatusCode UA_EXPORT UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item);
-void UA_EXPORT UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
-                                               const UA_VTable_Entry *vt, const UA_ExpandedNodeId *parentNodeId,
-                                               const UA_NodeId *referenceTypeId );
-
-/** @ingroup server
-
-    @defgroup external_nodestore External Nodestore
-
-    To plug in outside data sources, one can use
-
-    - VariableNodes with a data source (functions that are called for read and write access)
-    - An external nodestore that is mapped to specific namespaces
-
-    If no external nodestore is defined for a nodeid, it is always looked up in
-    the "local" nodestore of open62541. Namespace Zero is always in the local nodestore.
-*/
-
-typedef UA_Int32 (*UA_ExternalNodeStore_addNodes)(void *ensHandle, const UA_RequestHeader *requestHeader, UA_AddNodesItem *nodesToAdd,
-                                                  UA_UInt32 *indices,UA_UInt32 indicesSize, UA_AddNodesResult* addNodesResults,
-                                                  UA_DiagnosticInfo *diagnosticInfos);
-typedef UA_Int32 (*UA_ExternalNodeStore_addReferences)(void *ensHandle, const UA_RequestHeader *requestHeader, UA_AddReferencesItem* referencesToAdd,
-                                                       UA_UInt32 *indices,UA_UInt32 indicesSize, UA_StatusCode *addReferencesResults,
-                                                       UA_DiagnosticInfo *diagnosticInfos);
-typedef UA_Int32 (*UA_ExternalNodeStore_deleteNodes)(void *ensHandle, const UA_RequestHeader *requestHeader, UA_DeleteNodesItem *nodesToDelete, UA_UInt32 *indices,
-                                                     UA_UInt32 indicesSize, UA_StatusCode *deleteNodesResults, UA_DiagnosticInfo *diagnosticInfos);
-typedef UA_Int32 (*UA_ExternalNodeStore_deleteReferences)(void *ensHandle, const UA_RequestHeader *requestHeader, UA_DeleteReferencesItem *referenceToDelete,
-                                                          UA_UInt32 *indices, UA_UInt32 indicesSize, UA_StatusCode deleteReferencesresults,
-                                                          UA_DiagnosticInfo *diagnosticInfos);
-typedef UA_Int32 (*UA_ExternalNodeStore_readNodes)(void *ensHandle, const UA_RequestHeader *requestHeader, UA_ReadValueId *readValueIds, UA_UInt32 *indices,
-                                                   UA_UInt32 indicesSize,UA_DataValue *readNodesResults, UA_Boolean timeStampToReturn, UA_DiagnosticInfo *diagnosticInfos);
-typedef UA_Int32 (*UA_ExternalNodeStore_writeNodes)(void *ensHandle, const UA_RequestHeader *requestHeader, UA_WriteValue *writeValues, UA_UInt32 *indices,
-                                                    UA_UInt32 indicesSize, UA_StatusCode *writeNodesResults, UA_DiagnosticInfo *diagnosticInfo);
-typedef UA_Int32 (*UA_ExternalNodeStore_browseNodes)(void *ensHandle, const UA_RequestHeader *requestHeader, UA_BrowseDescription *browseDescriptions, UA_UInt32 *indices,
-                                                     UA_UInt32 indicesSize, UA_UInt32 requestedMaxReferencesPerNode, UA_BrowseResult *browseResults, UA_DiagnosticInfo *diagnosticInfos);
+void UA_EXPORT UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection,
+                                              const UA_ByteString *msg);
+
+/**
+ * @brief Adds a node to the server's address space
+ *
+ * If adding the node succeeds, the pointer to the node is set to null. If the
+ * original nodeid is null (ns=0,i=0), a unique new nodeid is created for the
+ * node and returned in the AddNodesResult struct. */
+UA_AddNodesResult UA_EXPORT
+UA_Server_addNode(UA_Server *server, const UA_Node **node, const UA_ExpandedNodeId *parentNodeId,
+                  const UA_NodeId *referenceTypeId);
+
+/** @brief Adds a reference to the server's address space */
+UA_StatusCode UA_EXPORT
+UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item);
+
+/**
+ * @brief Adds a VariableNode to the server's address space that points to a
+ * scalar value. The value must lie on the heap and cannot be reused afterwards
+ * as it becomes attached to the lifecycle of the VariableNode */
+void UA_EXPORT
+UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
+                                const UA_TypeVTable *vt, const UA_ExpandedNodeId *parentNodeId,
+                                const UA_NodeId *referenceTypeId );
+/** @} */
+
+/**
+ * @ingroup server
+ *
+ * @defgroup external_nodestore External Nodestore
+ *
+ * @brief This modules describes the VTable and function signatures to add an
+ * external nodestore to the server.
+ *
+ * To plug in outside data sources, one can use
+ *
+ * - VariableNodes with a data source (functions that are called for read and write access)
+ * - An external nodestore that is mapped to specific namespaces
+ *
+ * If no external nodestore is defined for a nodeid, it is always looked up in
+ * the "local" nodestore of open62541. Namespace Zero is always in the local
+ * nodestore.
+ *
+ *  @{
+ */
+
+typedef UA_Int32 (*UA_ExternalNodeStore_addNodes)
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_AddNodesItem *nodesToAdd, UA_UInt32 *indices,
+ UA_UInt32 indicesSize, UA_AddNodesResult* addNodesResults, UA_DiagnosticInfo *diagnosticInfos);
+
+typedef UA_Int32 (*UA_ExternalNodeStore_addReferences)
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_AddReferencesItem* referencesToAdd,
+ UA_UInt32 *indices,UA_UInt32 indicesSize, UA_StatusCode *addReferencesResults,
+ UA_DiagnosticInfo *diagnosticInfos);
+
+typedef UA_Int32 (*UA_ExternalNodeStore_deleteNodes)
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_DeleteNodesItem *nodesToDelete, UA_UInt32 *indices,
+ UA_UInt32 indicesSize, UA_StatusCode *deleteNodesResults, UA_DiagnosticInfo *diagnosticInfos);
+
+typedef UA_Int32 (*UA_ExternalNodeStore_deleteReferences)
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_DeleteReferencesItem *referenceToDelete,
+ UA_UInt32 *indices, UA_UInt32 indicesSize, UA_StatusCode deleteReferencesresults,
+ UA_DiagnosticInfo *diagnosticInfos);
+
+typedef UA_Int32 (*UA_ExternalNodeStore_readNodes)
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_ReadValueId *readValueIds, UA_UInt32 *indices,
+ UA_UInt32 indicesSize,UA_DataValue *readNodesResults, UA_Boolean timeStampToReturn,
+ UA_DiagnosticInfo *diagnosticInfos);
+
+typedef UA_Int32 (*UA_ExternalNodeStore_writeNodes)
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_WriteValue *writeValues, UA_UInt32 *indices,
+ UA_UInt32 indicesSize, UA_StatusCode *writeNodesResults, UA_DiagnosticInfo *diagnosticInfo);
+
+typedef UA_Int32 (*UA_ExternalNodeStore_browseNodes)
+(void *ensHandle, const UA_RequestHeader *requestHeader, UA_BrowseDescription *browseDescriptions,
+ UA_UInt32 *indices, UA_UInt32 indicesSize, UA_UInt32 requestedMaxReferencesPerNode,
+ UA_BrowseResult *browseResults, UA_DiagnosticInfo *diagnosticInfos);
+
 typedef UA_Int32 (*UA_ExternalNodeStore_delete)(void *ensHandle);
 
 typedef struct UA_ExternalNodeStore {
@@ -87,7 +131,10 @@ typedef struct UA_ExternalNodeStore {
 	UA_ExternalNodeStore_delete delete;
 } UA_ExternalNodeStore;
 
-UA_StatusCode UA_EXPORT UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, UA_ExternalNodeStore *nodeStore);
+UA_StatusCode UA_EXPORT
+UA_Server_addExternalNamespace(UA_Server *server, UA_UInt16 namespaceIndex, UA_ExternalNodeStore *nodeStore);
+
+/** @} */
 
 #ifdef __cplusplus
 } // extern "C"

+ 21 - 37
include/ua_types.h

@@ -186,22 +186,11 @@ typedef struct UA_ExtensionObject {
     UA_ByteString body; // contains either the bytestring or a pointer to the memory-object
 } UA_ExtensionObject;
 
-struct UA_VTable_Entry; // forwards declaration
-typedef struct UA_VTable_Entry UA_VTable_Entry;
-
-/* Variant */
-/** @defgroup variant Variant
- *
- * @brief Variants may contain (arrays of) any other datatype.
- *
- * For that, we provide a reference to the utility functions of the type as well
- * as possible encoding by pointing an entry in the vtable of types. References
- * may either contain a structure with the variants data, or a datasource where
- * this structure may be obtained (using reference counting for async access).
- *
- * @{
- */
+struct UA_TypeVTable; // forward declaration
+typedef struct UA_TypeVTable UA_TypeVTable;
 
+/** @brief Pointers to data that is stored in memory. The "type" of the data is
+    stored in the variant itself. */
 typedef struct UA_VariantData {
     UA_Int32  arrayLength;        // total number of elements in the data-pointer
     void     *dataPtr;
@@ -222,16 +211,15 @@ typedef struct UA_VariantDataSource {
     void (*delete)(const void *identifier); /**< Indicates that the node with the datasource was removed from the namespace. */
 } UA_VariantDataSource;
 
-/** @brief A union of all of the types specified above.
- *
- * Variants store (arrays of) built-in types. If you want to store a more
- * complex (or self-defined) type, you have to use an UA_ExtensionObject.*/
+/** @brief Variants store (arrays of) any data type. Either they provide a
+    pointer to the data in memory, or functions from which the data can be
+    accessed. */
 typedef struct UA_Variant {
-    const UA_VTable_Entry *vt; // internal entry into vTable
+    const UA_TypeVTable *vt; /// The VTable of the datatype in question
     enum {
-        UA_VARIANT_DATA,
-        UA_VARIANT_DATA_NODELETE, // do not free the data (e.g. because it is "borrowed" and points into a larger structure)
-        UA_VARIANT_DATASOURCE
+        UA_VARIANT_DATA, ///< The data is stored in memory and "owned" by this variant
+        UA_VARIANT_DATA_NODELETE, ///< The data is stored in memory, but only "borrowed" and shall not be deleted at the end of this variant's lifecycle
+        UA_VARIANT_DATASOURCE ///< The data is provided externally. Call the functions in the datasource to get a current version
     } storageType;
     union {
         UA_VariantData       data;
@@ -239,8 +227,6 @@ typedef struct UA_Variant {
     } storage;
 } UA_Variant;
 
-/** @} */
-
 /** @brief A data value with an associated status code and timestamps. */
 typedef struct UA_DataValue {
     UA_Byte       encodingMask;
@@ -413,18 +399,18 @@ void UA_EXPORT UA_QualifiedName_printf(char const *label, const UA_QualifiedName
 UA_StatusCode UA_EXPORT UA_LocalizedText_copycstring(char const *src, UA_LocalizedText *dst);
 
 /* Variant */
-UA_StatusCode UA_EXPORT UA_Variant_copySetValue(UA_Variant *v, const UA_VTable_Entry *vt, const void *value);
-UA_StatusCode UA_EXPORT UA_Variant_copySetArray(UA_Variant *v, const UA_VTable_Entry *vt, UA_Int32 arrayLength, const void *array);
+UA_StatusCode UA_EXPORT UA_Variant_copySetValue(UA_Variant *v, const UA_TypeVTable *vt, const void *value);
+UA_StatusCode UA_EXPORT UA_Variant_copySetArray(UA_Variant *v, const UA_TypeVTable *vt, UA_Int32 arrayLength, const void *array);
 
 /* Array operations */
-UA_StatusCode UA_EXPORT UA_Array_new(void **p, UA_Int32 noElements, const UA_VTable_Entry *vt);
-void UA_EXPORT UA_Array_init(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt);
-void UA_EXPORT UA_Array_delete(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt);
+UA_StatusCode UA_EXPORT UA_Array_new(void **p, UA_Int32 noElements, const UA_TypeVTable *vt);
+void UA_EXPORT UA_Array_init(void *p, UA_Int32 noElements, const UA_TypeVTable *vt);
+void UA_EXPORT UA_Array_delete(void *p, UA_Int32 noElements, const UA_TypeVTable *vt);
 
 /* @brief The destination array is allocated with size noElements. */
-UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, UA_Int32 noElements, const UA_VTable_Entry *vt, void **dst);
+UA_StatusCode UA_EXPORT UA_Array_copy(const void *src, UA_Int32 noElements, const UA_TypeVTable *vt, void **dst);
 #ifdef DEBUG
-void UA_EXPORT UA_Array_print(const void *p, UA_Int32 noElements, const UA_VTable_Entry *vt, FILE *stream);
+void UA_EXPORT UA_Array_print(const void *p, UA_Int32 noElements, const UA_TypeVTable *vt, FILE *stream);
 #endif
 
 /**********/
@@ -442,7 +428,7 @@ typedef struct UA_Encoding {
 
 #define UA_ENCODING_BINARY 0 // Binary encoding is always available
 
-struct UA_VTable_Entry {
+struct UA_TypeVTable {
     UA_NodeId     typeId;
     UA_Byte       *name;
     void *        (*new)();
@@ -453,10 +439,8 @@ struct UA_VTable_Entry {
 #ifdef DEBUG
     void          (*print)(const void *p, FILE *stream);
 #endif
-    UA_UInt32  memSize;                        // size of the struct only in memory (no dynamic components)
-    UA_Boolean dynMembers;                     // does the type contain members that are dynamically
-                                               // allocated (strings, ..)? Otherwise, the size on
-                                               // the wire == size in memory.
+    UA_UInt32  memSize;                        // size of the struct
+    UA_Boolean dynMembers;                     // does the type contain members that are dynamically on the heap?
     UA_Encoding encodings[UA_ENCODING_AMOUNT]; // binary, xml, ... UA_ENCODING_AMOUNT is set by the build script
 };
 

+ 0 - 17
src/server/ua_server.c

@@ -460,20 +460,3 @@ UA_Server * UA_Server_new(UA_String *endpointUrl, UA_ByteString *serverCertifica
 
     return server;
 }
-
-void UA_EXPORT
-UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
-                                const UA_VTable_Entry *vt, const UA_ExpandedNodeId *parentNodeId,
-                                const UA_NodeId *referenceTypeId) {
-    UA_VariableNode *tmpNode = UA_VariableNode_new();
-    UA_QualifiedName_copy(browseName, &tmpNode->browseName);
-    UA_String_copy(&browseName->name, &tmpNode->displayName.text);
-    /* UA_LocalizedText_copycstring("integer value", &tmpNode->description); */
-    tmpNode->nodeClass = UA_NODECLASS_VARIABLE;
-    tmpNode->valueRank = -1;
-    tmpNode->value.vt = vt;
-    tmpNode->value.storage.data.dataPtr = value;
-    tmpNode->value.storageType = UA_VARIANT_DATA_NODELETE;
-    tmpNode->value.storage.data.arrayLength = 1;
-    UA_Server_addNode(server, (const UA_Node**)&tmpNode, parentNodeId, referenceTypeId);
-}

+ 210 - 0
src/server/ua_server_addressspace.c

@@ -0,0 +1,210 @@
+#include "ua_server.h"
+#include "ua_server_internal.h"
+#include "ua_namespace_0.h"
+
+const UA_TypeVTable * UA_Node_getTypeVT(const UA_Node *node) {
+    switch(node->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        return &UA_TYPES[UA_OBJECTNODE];
+    case UA_NODECLASS_VARIABLE:
+        return &UA_TYPES[UA_VARIABLENODE];
+    case UA_NODECLASS_METHOD:
+        return &UA_TYPES[UA_METHODNODE];
+    case UA_NODECLASS_OBJECTTYPE:
+        return &UA_TYPES[UA_OBJECTTYPENODE];
+    case UA_NODECLASS_VARIABLETYPE:
+        return &UA_TYPES[UA_VARIABLETYPENODE];
+    case UA_NODECLASS_REFERENCETYPE:
+        return &UA_TYPES[UA_REFERENCETYPENODE];
+    case UA_NODECLASS_DATATYPE:
+        return &UA_TYPES[UA_DATATYPENODE];
+    case UA_NODECLASS_VIEW:
+        return &UA_TYPES[UA_VIEWNODE];
+    default: break;
+    }
+
+    return &UA_TYPES[UA_INVALIDTYPE];
+}
+
+void UA_Server_addScalarVariableNode(UA_Server *server, UA_QualifiedName *browseName, void *value,
+                                     const UA_TypeVTable *vt, const UA_ExpandedNodeId *parentNodeId,
+                                     const UA_NodeId *referenceTypeId) {
+    UA_VariableNode *tmpNode = UA_VariableNode_new();
+    UA_QualifiedName_copy(browseName, &tmpNode->browseName);
+    UA_String_copy(&browseName->name, &tmpNode->displayName.text);
+    /* UA_LocalizedText_copycstring("integer value", &tmpNode->description); */
+    tmpNode->nodeClass = UA_NODECLASS_VARIABLE;
+    tmpNode->valueRank = -1;
+    tmpNode->value.vt = vt;
+    tmpNode->value.storage.data.dataPtr = value;
+    tmpNode->value.storageType = UA_VARIANT_DATA;
+    tmpNode->value.storage.data.arrayLength = 1;
+    UA_Server_addNode(server, (const UA_Node**)&tmpNode, parentNodeId, referenceTypeId);
+}
+
+/* Adds a one-way reference to the local nodestore */
+UA_StatusCode addOneWayReferenceWithSession (UA_Server *server, UA_Session *session,
+                                             const UA_AddReferencesItem *item) {
+    // use the servers nodestore
+    const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
+    // todo differentiate between error codes
+    if(!node)
+        return UA_STATUSCODE_BADINTERNALERROR;
+
+    const UA_TypeVTable *nodeVT = UA_Node_getTypeVT(node);
+    UA_Node *newNode = nodeVT->new();
+    nodeVT->copy(node, newNode);
+
+    UA_Int32 count = node->referencesSize;
+    if(count < 0)
+        count = 0;
+    UA_ReferenceNode *old_refs = newNode->references;
+    UA_ReferenceNode *new_refs = UA_alloc(sizeof(UA_ReferenceNode)*(count+1));
+    if(!new_refs) {
+        nodeVT->delete(newNode);
+        UA_NodeStore_release(node);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    // insert the new reference
+    UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
+    UA_ReferenceNode_init(&new_refs[count]);
+    UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
+    new_refs[count].isInverse = !item->isForward;
+    retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_Array_delete(new_refs, ++count, &UA_TYPES[UA_REFERENCENODE]);
+        newNode->references = UA_NULL;
+        newNode->referencesSize = 0;
+        nodeVT->delete(newNode);
+        UA_NodeStore_release(node);
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
+
+    UA_free(old_refs);
+    newNode->references = new_refs;
+    newNode->referencesSize = ++count;
+    retval = UA_NodeStore_replace(server->nodestore, (const UA_Node **)&newNode, UA_FALSE);
+    if(retval)
+        nodeVT->delete(newNode);
+    UA_NodeStore_release(node);
+
+    return retval;
+}
+
+UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item) {
+    return UA_Server_addReferenceWithSession(server, &adminSession, item);
+}
+
+UA_StatusCode UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session,
+                                                const UA_AddReferencesItem *item) {
+    // todo: we don't support references to other servers (expandednodeid) for now
+    if(item->targetServerUri.length > 0)
+        return UA_STATUSCODE_BADNOTIMPLEMENTED;
+    
+    // Is this for an external nodestore?
+    UA_ExternalNodeStore *ensFirst = UA_NULL;
+    UA_ExternalNodeStore *ensSecond = UA_NULL;
+    for(UA_Int32 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;
+    }
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(ensFirst) {
+        // todo: use external nodestore
+    } else
+        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;
+    if(ensSecond) {
+        // todo: use external nodestore
+    } else
+        retval = addOneWayReferenceWithSession (server, session, &secondItem);
+    // todo: remove reference if the second direction failed
+
+    return retval;
+} 
+
+UA_AddNodesResult UA_Server_addNode(UA_Server *server, const UA_Node **node,
+                                    const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
+    return UA_Server_addNodeWithSession(server, &adminSession, node, parentNodeId, referenceTypeId);
+}
+
+UA_AddNodesResult UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, const UA_Node **node,
+                                               const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
+    UA_AddNodesResult result;
+    UA_AddNodesResult_init(&result);
+
+    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId);
+    if(!parent) {
+        result.statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
+        return result;
+    }
+
+    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
+    if(UA_NodeId_isNull(&(*node)->nodeId)) {
+        if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
+            result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
+            goto ret2;
+        }
+        result.addedNodeId = (*node)->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, UA_TRUE) != 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 = (*node)->nodeId;
+    item.referenceTypeId = referenceType->nodeId;
+    item.isForward = UA_FALSE;
+    item.targetNodeId.nodeId = parent->nodeId;
+    UA_Server_addReference(server, &item);
+
+    // todo: error handling. remove new node from nodestore
+
+    UA_NodeStore_release(*node);
+    *node = UA_NULL;
+    
+ ret2:
+    UA_NodeStore_release((UA_Node*)referenceType);
+ ret:
+    UA_NodeStore_release(parent);
+
+    return result;
+}

+ 7 - 0
src/server/ua_server_internal.h

@@ -32,4 +32,11 @@ struct UA_Server {
     UA_ExternalNamespace *externalNamespaces;
 };
 
+UA_AddNodesResult
+UA_Server_addNodeWithSession(UA_Server *server, UA_Session *session, const 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);
+
 #endif /* UA_SERVER_INTERNAL_H_ */

+ 16 - 54
src/server/ua_services.h

@@ -6,32 +6,6 @@
 #include "ua_server.h"
 #include "ua_session.h"
 
-/** The (nodes) AttributeIds are defined in part 6, table A1 of the standard */
-typedef enum UA_AttributeId {
-    UA_ATTRIBUTEID_NODEID                  = 1,
-    UA_ATTRIBUTEID_NODECLASS               = 2,
-    UA_ATTRIBUTEID_BROWSENAME              = 3,
-    UA_ATTRIBUTEID_DISPLAYNAME             = 4,
-    UA_ATTRIBUTEID_DESCRIPTION             = 5,
-    UA_ATTRIBUTEID_WRITEMASK               = 6,
-    UA_ATTRIBUTEID_USERWRITEMASK           = 7,
-    UA_ATTRIBUTEID_ISABSTRACT              = 8,
-    UA_ATTRIBUTEID_SYMMETRIC               = 9,
-    UA_ATTRIBUTEID_INVERSENAME             = 10,
-    UA_ATTRIBUTEID_CONTAINSNOLOOPS         = 11,
-    UA_ATTRIBUTEID_EVENTNOTIFIER           = 12,
-    UA_ATTRIBUTEID_VALUE                   = 13,
-    UA_ATTRIBUTEID_DATATYPE                = 14,
-    UA_ATTRIBUTEID_VALUERANK               = 15,
-    UA_ATTRIBUTEID_ARRAYDIMENSIONS         = 16,
-    UA_ATTRIBUTEID_ACCESSLEVEL             = 17,
-    UA_ATTRIBUTEID_USERACCESSLEVEL         = 18,
-    UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL = 19,
-    UA_ATTRIBUTEID_HISTORIZING             = 20,
-    UA_ATTRIBUTEID_EXECUTABLE              = 21,
-    UA_ATTRIBUTEID_USEREXECUTABLE          = 22
-} UA_AttributeId;
-
 /**
  * @defgroup services Services
  *
@@ -53,8 +27,7 @@ typedef enum UA_AttributeId {
  * the configuration information required to establish a SecureChannel and a
  * Session.
  */
-void Service_GetEndpoints(UA_Server                    *server,
-                          const UA_GetEndpointsRequest *request, UA_GetEndpointsResponse *response);
+void Service_GetEndpoints(UA_Server *server, const UA_GetEndpointsRequest *request, UA_GetEndpointsResponse *response);
 // Service_RegisterServer
 /** @} */
 
@@ -108,9 +81,7 @@ void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
 void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
                              const UA_ActivateSessionRequest *request, UA_ActivateSessionResponse *response);
 
-/**
- * @brief This Service is used to terminate a Session.
- */
+/** @brief This Service is used to terminate a Session. */
 void Service_CloseSession(UA_Server *server, const UA_CloseSessionRequest *request, UA_CloseSessionResponse *response);
 // Service_Cancel
 /** @} */
@@ -125,20 +96,18 @@ void Service_CloseSession(UA_Server *server, const UA_CloseSessionRequest *reque
  * @{
  */
 
-/**
- * @brief This Service is 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);
+/** @brief This Service is 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);
 
-/**
- * @brief This Service is 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);
+/** @brief This Service is 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);
+
+/** @brief This Service is 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);
+
+/** @brief This Service is used to delete one or more References of a Node. */
+void Service_DeleteReferences(UA_Server *server, UA_Session *session, const UA_DeleteReferencesRequest *request, UA_DeleteReferencesResponse *response);
 
-// Service_DeleteNodes
-// Service_DeleteReferences
 /** @} */
 
 /**
@@ -158,20 +127,15 @@ void Service_AddReferences(UA_Server *server, UA_Session *session,
 void Service_Browse(UA_Server *server, UA_Session *session,
                     const UA_BrowseRequest *request, UA_BrowseResponse *response);
 
-/**
- * @brief This Service is used to translate textual node paths to their respective ids.
- */
+/** @brief This Service is used to translate textual node paths to their respective ids. */
 void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
                                            const UA_TranslateBrowsePathsToNodeIdsRequest *request,
                                            UA_TranslateBrowsePathsToNodeIdsResponse *response);
 // Service_BrowseNext
-// Service_TranslateBrowsePathsToNodeIds
 // Service_RegisterNodes
 // Service_UnregisterNodes
 /** @} */
 
-
-/* Part 4: 5.9 Query Service Set */
 /**
  * @name Query Service Set
  *
@@ -189,7 +153,6 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
 // Service_QueryNext
 /** @} */
 
-/* Part 4: 5.10 Attribute Service Set */
 /**
  * @name Attribute Service Set
  *
@@ -206,9 +169,9 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
  * values as a composite, to read individual elements or to read ranges of
  * elements of the composite.
  */
-void Service_Read(UA_Server *server, UA_Session *session,
-                  const UA_ReadRequest *request, UA_ReadResponse *response);
+void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *request, UA_ReadResponse *response);
 // Service_HistoryRead
+
 /**
  * @brief This Service is used to write one or more Attributes of one or more
  *  Nodes. For constructed Attribute values whose elements are indexed, such as
@@ -216,8 +179,7 @@ void Service_Read(UA_Server *server, UA_Session *session,
  *  values as a composite, to write individual elements or to write ranges of
  *  elements of the composite.
  */
-void Service_Write(UA_Server *server, UA_Session *session,
-                   const UA_WriteRequest *request, UA_WriteResponse *response);
+void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request, UA_WriteResponse *response);
 // Service_HistoryUpdate
 /** @} */
 

+ 11 - 11
src/server/ua_services_attribute.c

@@ -1,19 +1,20 @@
 #include "ua_server_internal.h"
 #include "ua_services.h"
+#include "ua_services_internal.h"
 #include "ua_statuscodes.h"
 #include "ua_nodestore.h"
 #include "ua_namespace_0.h"
 #include "ua_util.h"
 
-#define CHECK_NODECLASS(CLASS)                                 \
-    if(!(node->nodeClass & (CLASS))) {                         \
+#define CHECK_NODECLASS(CLASS)                                  \
+    if(!(node->nodeClass & (CLASS))) {                          \
         v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE; \
         v->status       = UA_STATUSCODE_BADNOTREADABLE;         \
-        break;                                                 \
-    }                                                          \
+        break;                                                  \
+    }
 
 /** Reads a single attribute from a node in the nodestore. */
-static void __readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue *v) {
+static void readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValue *v) {
     UA_Node const *node = UA_NodeStore_get(server->nodestore, &(id->nodeId));
     if(!node) {
         v->encodingMask = UA_DATAVALUE_ENCODINGMASK_STATUSCODE;
@@ -60,9 +61,8 @@ static void __readValue(UA_Server *server, const UA_ReadValueId *id, UA_DataValu
         break;
 
     case UA_ATTRIBUTEID_ISABSTRACT:
-        CHECK_NODECLASS(
-            UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE |
-            UA_NODECLASS_DATATYPE);
+        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE |
+                        UA_NODECLASS_DATATYPE);
         v->encodingMask = UA_DATAVALUE_ENCODINGMASK_VARIANT;
         retval |= UA_Variant_copySetValue(&v->value, &UA_TYPES[UA_BOOLEAN], &((UA_ReferenceTypeNode *)node)->isAbstract);
         break;
@@ -219,11 +219,11 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     response->resultsSize = request->nodesToReadSize;
     for(UA_Int32 i = 0;i < response->resultsSize;i++) {
         if(!isExternal[i])
-            __readValue(server, &request->nodesToRead[i], &response->results[i]);
+            readValue(server, &request->nodesToRead[i], &response->results[i]);
     }
 }
 
-static UA_StatusCode __writeValue(UA_Server *server, UA_WriteValue *writeValue) {
+static UA_StatusCode writeValue(UA_Server *server, UA_WriteValue *writeValue) {
     const UA_Node *node = UA_NodeStore_get(server->nodestore, &writeValue->nodeId);
     if(!node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
@@ -385,6 +385,6 @@ void Service_Write(UA_Server *server, UA_Session *session,
     response->resultsSize = request->nodesToWriteSize;
     for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++) {
         if(!isExternal[i])
-            response->results[i] = __writeValue(server, &request->nodesToWrite[i]);
+            response->results[i] = writeValue(server, &request->nodesToWrite[i]);
     }
 }

+ 26 - 9
src/server/ua_services_internal.h

@@ -10,14 +10,31 @@
 #include "ua_nodestore.h"
 #include "ua_types_generated.h"
 #include "ua_namespace_0.h"
-/* @brief Add a reference (and the inverse reference to the target node).
- *
- * @param The node to which the reference shall be added
- * @param The reference itself
- * @param The namespace where the target node is looked up for the reverse reference (this is omitted if targetns is UA_NULL)
- */
-UA_AddNodesResult AddNode(UA_Server *server, UA_Session *session, const UA_Node **node,
-                          const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId);
-UA_StatusCode AddReference(UA_Server *server, const UA_AddReferencesItem *item);
+
+/** The (nodes) AttributeIds are defined in part 6, table A1 of the standard */
+typedef enum UA_AttributeId {
+    UA_ATTRIBUTEID_NODEID                  = 1,
+    UA_ATTRIBUTEID_NODECLASS               = 2,
+    UA_ATTRIBUTEID_BROWSENAME              = 3,
+    UA_ATTRIBUTEID_DISPLAYNAME             = 4,
+    UA_ATTRIBUTEID_DESCRIPTION             = 5,
+    UA_ATTRIBUTEID_WRITEMASK               = 6,
+    UA_ATTRIBUTEID_USERWRITEMASK           = 7,
+    UA_ATTRIBUTEID_ISABSTRACT              = 8,
+    UA_ATTRIBUTEID_SYMMETRIC               = 9,
+    UA_ATTRIBUTEID_INVERSENAME             = 10,
+    UA_ATTRIBUTEID_CONTAINSNOLOOPS         = 11,
+    UA_ATTRIBUTEID_EVENTNOTIFIER           = 12,
+    UA_ATTRIBUTEID_VALUE                   = 13,
+    UA_ATTRIBUTEID_DATATYPE                = 14,
+    UA_ATTRIBUTEID_VALUERANK               = 15,
+    UA_ATTRIBUTEID_ARRAYDIMENSIONS         = 16,
+    UA_ATTRIBUTEID_ACCESSLEVEL             = 17,
+    UA_ATTRIBUTEID_USERACCESSLEVEL         = 18,
+    UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL = 19,
+    UA_ATTRIBUTEID_HISTORIZING             = 20,
+    UA_ATTRIBUTEID_EXECUTABLE              = 21,
+    UA_ATTRIBUTEID_USEREXECUTABLE          = 22
+} UA_AttributeId;
 
 #endif /* UA_SERVICES_INTERNAL_H_ */

+ 23 - 196
src/server/ua_services_nodemanagement.c

@@ -7,29 +7,6 @@
 #include "ua_session.h"
 #include "ua_util.h"
 
-const UA_VTable_Entry * UA_Node_getVT(const UA_Node *node) {
-    switch(node->nodeClass) {
-    case UA_NODECLASS_OBJECT:
-        return &UA_TYPES[UA_OBJECTNODE];
-    case UA_NODECLASS_VARIABLE:
-        return &UA_TYPES[UA_VARIABLENODE];
-    case UA_NODECLASS_METHOD:
-        return &UA_TYPES[UA_METHODNODE];
-    case UA_NODECLASS_OBJECTTYPE:
-        return &UA_TYPES[UA_OBJECTTYPENODE];
-    case UA_NODECLASS_VARIABLETYPE:
-        return &UA_TYPES[UA_VARIABLETYPENODE];
-    case UA_NODECLASS_REFERENCETYPE:
-        return &UA_TYPES[UA_REFERENCETYPENODE];
-    case UA_NODECLASS_DATATYPE:
-        return &UA_TYPES[UA_DATATYPENODE];
-    case UA_NODECLASS_VIEW:
-        return &UA_TYPES[UA_VIEWNODE];
-    default: break;
-    }
-    return &UA_TYPES[UA_INVALIDTYPE];
-}
-
 #define COPY_STANDARDATTRIBUTES do {                                    \
     if(attr.specifiedAttributes & UA_NODEATTRIBUTESMASK_DISPLAYNAME) {  \
         vnode->displayName = attr.displayName;                          \
@@ -46,8 +23,9 @@ const UA_VTable_Entry * UA_Node_getVT(const UA_Node *node) {
     } while(0)
 
 static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node **new_node,
-                                       const UA_VTable_Entry **vt) {
-    if(attributes->typeId.identifier.numeric != 357) // VariableAttributes_Encoding_DefaultBinary,357,Object
+                                       const UA_TypeVTable **vt) {
+    if(attributes->typeId.identifier.numeric !=
+       UA_NODEIDS[UA_VARIABLEATTRIBUTES].identifier.numeric + UA_ENCODINGOFFSET_BINARY)
         return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
 
     UA_VariableAttributes attr;
@@ -105,90 +83,8 @@ static UA_StatusCode parseVariableNode(UA_ExtensionObject *attributes, UA_Node *
     return UA_STATUSCODE_GOOD;
 }
 
-/**
-   If adding the node succeeds, the pointer will be set to zero. If the nodeid
-   of the node is null (ns=0,i=0), a unique new nodeid will be assigned and
-   returned in the AddNodesResult.
- */
-static void __addNode(UA_Server *server, UA_Session *session, const UA_Node **node,
-                      const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId,
-                      UA_AddNodesResult *result) {
-    const UA_Node *parent = UA_NodeStore_get(server->nodestore, &parentNodeId->nodeId);
-    if(!parent) {
-        result->statusCode = UA_STATUSCODE_BADPARENTNODEIDINVALID;
-        return;
-    }
-
-    const UA_ReferenceTypeNode *referenceType =
-        (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
-    if(UA_NodeId_isNull(&(*node)->nodeId)) {
-        if(UA_NodeStore_insert(server->nodestore, node, UA_TRUE) != UA_STATUSCODE_GOOD) {
-            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
-            goto ret2;
-        }
-        result->addedNodeId = (*node)->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, UA_TRUE) != 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 = (*node)->nodeId;
-    item.referenceTypeId = referenceType->nodeId;
-    item.isForward = UA_FALSE;
-    item.targetNodeId.nodeId = parent->nodeId;
-    UA_Server_addReference(server, &item);
-
-    // todo: error handling. remove new node from nodestore
-
-    UA_NodeStore_release(*node);
-    *node = UA_NULL;
-    
- ret2:
-    UA_NodeStore_release((UA_Node*)referenceType);
- ret:
-    UA_NodeStore_release(parent);
-
-    return;
-}
-
-/* Exposed to userland */
-UA_AddNodesResult UA_Server_addNode(UA_Server *server, const UA_Node **node,
-                                    const UA_ExpandedNodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
-    UA_AddNodesResult result;
-    UA_AddNodesResult_init(&result);
-    __addNode(server, &adminSession, node, parentNodeId, referenceTypeId, &result);
-    return result;
-}
-
-static void __addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
-                                    UA_AddNodesResult *result) {
+static void addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_AddNodesItem *item,
+                                  UA_AddNodesResult *result) {
     // adding nodes to ns0 is not allowed over the wire
     if(item->requestedNewNodeId.nodeId.namespaceIndex == 0) {
         result->statusCode = UA_STATUSCODE_BADNODEIDREJECTED;
@@ -197,7 +93,7 @@ static void __addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_A
 
     // parse the node
     UA_Node *node;
-    const UA_VTable_Entry *nodeVT = UA_NULL;
+    const UA_TypeVTable *nodeVT = UA_NULL;
     if(item->nodeClass == UA_NODECLASS_VARIABLE)
         result->statusCode = parseVariableNode(&item->nodeAttributes, &node, &nodeVT);
     else // add more node types here..
@@ -207,7 +103,8 @@ static void __addNodeFromAttributes(UA_Server *server, UA_Session *session, UA_A
         return;
 
     // add the node
-    __addNode(server, session, (const UA_Node **)&node, &item->parentNodeId, &item->referenceTypeId, result);
+    *result = UA_Server_addNodeWithSession(server, session, (const UA_Node **)&node,
+                                           &item->parentNodeId, &item->referenceTypeId);
     if(result->statusCode != UA_STATUSCODE_GOOD)
         nodeVT->delete(node);
 }
@@ -233,8 +130,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
     for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
         UA_UInt32 indexSize = 0;
         for(UA_Int32 i = 0;i < request->nodesToAddSize;i++) {
-            if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex !=
-               server->externalNamespaces[j].index)
+            if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex != server->externalNamespaces[j].index)
                 continue;
             isExternal[i] = UA_TRUE;
             indices[indexSize] = i;
@@ -251,91 +147,10 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
     response->resultsSize = request->nodesToAddSize;
     for(int i = 0;i < request->nodesToAddSize;i++) {
         if(!isExternal[i])
-            __addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
+            addNodeFromAttributes(server, session, &request->nodesToAdd[i], &response->results[i]);
     }
 }
 
-static UA_StatusCode __addSingleReference(UA_Server *server, const UA_AddReferencesItem *item) {
-    // todo: we don't support references to other servers (expandednodeid) for now
-    if(item->targetServerUri.length > 0)
-        return UA_STATUSCODE_BADNOTIMPLEMENTED;
-    
-    // Is this for an external nodestore?
-    UA_ExternalNodeStore *ens = UA_NULL;
-    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
-        if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index) {
-            ens = &server->externalNamespaces[j].externalNodeStore;
-            break;
-        }
-    }
-
-    if(ens) {
-        // todo: use external nodestore
-
-    } else {
-        // use the servers nodestore
-        const UA_Node *node = UA_NodeStore_get(server->nodestore, &item->sourceNodeId);
-        // todo differentiate between error codes
-        if(!node)
-            return UA_STATUSCODE_BADINTERNALERROR;
-
-        const UA_VTable_Entry *nodeVT = UA_Node_getVT(node);
-        UA_Node *newNode = nodeVT->new();
-        nodeVT->copy(node, newNode);
-
-        UA_Int32 count = node->referencesSize;
-        if(count < 0)
-            count = 0;
-        UA_ReferenceNode *old_refs = newNode->references;
-        UA_ReferenceNode *new_refs = UA_alloc(sizeof(UA_ReferenceNode)*(count+1));
-        if(!new_refs) {
-            nodeVT->delete(newNode);
-            UA_NodeStore_release(node);
-            return UA_STATUSCODE_BADOUTOFMEMORY;
-        }
-
-        // insert the new reference
-        UA_memcpy(new_refs, old_refs, sizeof(UA_ReferenceNode)*count);
-        UA_ReferenceNode_init(&new_refs[count]);
-        UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &new_refs[count].referenceTypeId);
-        new_refs[count].isInverse = !item->isForward;
-        retval |= UA_ExpandedNodeId_copy(&item->targetNodeId, &new_refs[count].targetId);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_Array_delete(new_refs, ++count, &UA_TYPES[UA_REFERENCENODE]);
-            newNode->references = UA_NULL;
-            newNode->referencesSize = 0;
-            nodeVT->delete(newNode);
-            UA_NodeStore_release(node);
-            return UA_STATUSCODE_BADOUTOFMEMORY;
-        }
-        UA_free(old_refs);
-        newNode->references = new_refs;
-        newNode->referencesSize = ++count;
-        UA_NodeStore_replace(server->nodestore, (const UA_Node **)&newNode, UA_FALSE);
-        UA_NodeStore_release(node);
-    }
-    return UA_STATUSCODE_GOOD;
-} 
-
-UA_StatusCode UA_Server_addReference(UA_Server *server, const UA_AddReferencesItem *item) {
-    // the first direction
-    UA_StatusCode retval = __addSingleReference(server, item);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-
-    // detect when the inverse reference shall be added as well
-    UA_AddReferencesItem item2;
-    UA_AddReferencesItem_init(&item2);
-    item2.sourceNodeId = item->targetNodeId.nodeId;
-    item2.referenceTypeId = item->referenceTypeId;
-    item2.isForward = !item->isForward;
-    item2.targetNodeId.nodeId = item->sourceNodeId;
-    retval = __addSingleReference(server, &item2);
-    // todo: if this fails, remove the first reference
-
-    return retval;
-}
-
 void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddReferencesRequest *request,
                            UA_AddReferencesResponse *response) {
     if(request->referencesToAddSize <= 0) {
@@ -351,5 +166,17 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 
     response->resultsSize = request->referencesToAddSize;
     for(UA_Int32 i = 0;i < response->resultsSize;i++)
-            response->results[i] = UA_Server_addReference(server, &request->referencesToAdd[i]);
+        response->results[i] = UA_Server_addReferenceWithSession(server, session,
+                                                                 &request->referencesToAdd[i]);
+}
+
+void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
+                         UA_DeleteNodesResponse *response) {
+
+}
+
+void Service_DeleteReferences(UA_Server *server, UA_Session *session,
+                              const UA_DeleteReferencesRequest *request,
+                              UA_DeleteReferencesResponse *response) {
+
 }

+ 7 - 7
src/ua_types.c

@@ -859,7 +859,7 @@ UA_StatusCode UA_Variant_copy(UA_Variant const *src, UA_Variant *dst) {
 }
 
 /** Copies data into a variant. The target variant has always a storagetype UA_VARIANT_DATA */
-UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const UA_VTable_Entry *vt, const void *value) {
+UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const UA_TypeVTable *vt, const void *value) {
     UA_Variant_init(v);
     v->vt = vt;
     v->storage.data.arrayLength = 1; // no array but a single entry
@@ -875,7 +875,7 @@ UA_StatusCode UA_Variant_copySetValue(UA_Variant *v, const UA_VTable_Entry *vt,
     return retval;
 }
 
-UA_StatusCode UA_Variant_copySetArray(UA_Variant *v, const UA_VTable_Entry *vt, UA_Int32 arrayLength, const void *array) {
+UA_StatusCode UA_Variant_copySetArray(UA_Variant *v, const UA_TypeVTable *vt, UA_Int32 arrayLength, const void *array) {
     UA_Variant_init(v);
     v->vt = vt;
     v->storage.data.arrayLength = arrayLength;
@@ -1012,7 +1012,7 @@ void UA_InvalidType_print(const UA_InvalidType *p, FILE *stream) {
 /* Array */
 /*********/
 
-UA_StatusCode UA_Array_new(void **p, UA_Int32 noElements, const UA_VTable_Entry *vt) {
+UA_StatusCode UA_Array_new(void **p, UA_Int32 noElements, const UA_TypeVTable *vt) {
     if(noElements <= 0) {
         *p = UA_NULL;
         return UA_STATUSCODE_GOOD;
@@ -1032,7 +1032,7 @@ UA_StatusCode UA_Array_new(void **p, UA_Int32 noElements, const UA_VTable_Entry
     return UA_STATUSCODE_GOOD;
 }
 
-void UA_Array_init(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt) {
+void UA_Array_init(void *p, UA_Int32 noElements, const UA_TypeVTable *vt) {
     UA_Byte *cp = (UA_Byte *)p; // so compilers allow pointer arithmetic
     UA_UInt32 memSize = vt->memSize;
     for(UA_Int32 i = 0;i<noElements;i++) {
@@ -1041,7 +1041,7 @@ void UA_Array_init(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt) {
     }
 }
 
-void UA_Array_delete(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt) {
+void UA_Array_delete(void *p, UA_Int32 noElements, const UA_TypeVTable *vt) {
     UA_Byte *cp = (UA_Byte *)p; // so compilers allow pointer arithmetic
     UA_UInt32 memSize = vt->memSize;
     for(UA_Int32 i = 0;i<noElements;i++) {
@@ -1052,7 +1052,7 @@ void UA_Array_delete(void *p, UA_Int32 noElements, const UA_VTable_Entry *vt) {
         UA_free(p);
 }
 
-UA_StatusCode UA_Array_copy(const void *src, UA_Int32 noElements, const UA_VTable_Entry *vt, void **dst) {
+UA_StatusCode UA_Array_copy(const void *src, UA_Int32 noElements, const UA_TypeVTable *vt, void **dst) {
     UA_StatusCode retval = UA_Array_new(dst, noElements, vt);
     if(retval)
         return retval;
@@ -1077,7 +1077,7 @@ UA_StatusCode UA_Array_copy(const void *src, UA_Int32 noElements, const UA_VTabl
 }
 
 #ifdef DEBUG
-void UA_Array_print(const void *p, UA_Int32 noElements, const UA_VTable_Entry *vt, FILE *stream) {
+void UA_Array_print(const void *p, UA_Int32 noElements, const UA_TypeVTable *vt, FILE *stream) {
     fprintf(stream, "(%s){", vt->name);
     char     *cp      = (char *)p; // so compilers allow pointer arithmetic
     UA_UInt32 memSize = vt->memSize;

+ 6 - 6
src/ua_types_encoding_binary.c

@@ -13,7 +13,7 @@ static INLINE UA_Boolean is_builtin(const UA_NodeId *typeid ) {
 /*********/
 
 /** The data-pointer may be null. Then the array is assumed to be empy. */
-UA_UInt32 UA_Array_calcSizeBinary(UA_Int32 length, const UA_VTable_Entry *vt, const void *data) {
+UA_UInt32 UA_Array_calcSizeBinary(UA_Int32 length, const UA_TypeVTable *vt, const void *data) {
     if(!data) //empty arrays are encoded with the length member either 0 or -1
         return sizeof(UA_Int32);
 
@@ -28,7 +28,7 @@ UA_UInt32 UA_Array_calcSizeBinary(UA_Int32 length, const UA_VTable_Entry *vt, co
 }
 
 /** The data-pointer may be null. Then the array is assumed to be empy. */
-static UA_UInt32 UA_Array_calcSizeBinary_asExtensionObject(UA_Int32 length, const UA_VTable_Entry *vt, const void *data) {
+static UA_UInt32 UA_Array_calcSizeBinary_asExtensionObject(UA_Int32 length, const UA_TypeVTable *vt, const void *data) {
     UA_UInt32 l = UA_Array_calcSizeBinary(length, vt, data);
     if(!is_builtin(&vt->typeId))
         l += 9*length;  // extensionobject header for each element
@@ -36,7 +36,7 @@ static UA_UInt32 UA_Array_calcSizeBinary_asExtensionObject(UA_Int32 length, cons
 }
 
 /* The src-pointer may be null if the array length is <= 0. */
-UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 length, const UA_VTable_Entry *vt,
+UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 length, const UA_TypeVTable *vt,
                                     UA_ByteString *dst, UA_UInt32 *offset) {
     //Null Arrays are encoded with length = -1 // part 6 - §5.24
     if(length < -1)
@@ -52,7 +52,7 @@ UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 length, const UA_V
     return retval;
 }
 
-static UA_StatusCode UA_Array_encodeBinary_asExtensionObject(const void *src, UA_Int32 length, const UA_VTable_Entry *vt,
+static UA_StatusCode UA_Array_encodeBinary_asExtensionObject(const void *src, UA_Int32 length, const UA_TypeVTable *vt,
                                                              UA_ByteString *dst, UA_UInt32 *offset) {
     //Null Arrays are encoded with length = -1 // part 6 - §5.24
     if(length < -1)
@@ -78,7 +78,7 @@ static UA_StatusCode UA_Array_encodeBinary_asExtensionObject(const void *src, UA
 }
 
 UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, UA_UInt32 *offset, UA_Int32 length,
-                                    const UA_VTable_Entry *vt, void **dst) {
+                                    const UA_TypeVTable *vt, void **dst) {
     if(length <= 0) {
         *dst = UA_NULL;
         return UA_STATUSCODE_GOOD;
@@ -902,7 +902,7 @@ UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, UA_UInt32 *offse
     UA_NodeId typeid = { .namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
                          .identifier.numeric = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK };
     UA_Int32 typeNs0Id = UA_ns0ToVTableIndex(&typeid );
-    const UA_VTable_Entry *vt = &UA_TYPES[typeNs0Id];
+    const UA_TypeVTable *vt = &UA_TYPES[typeNs0Id];
 
     if(!isArray) {
         if(!(data->dataPtr = UA_alloc(vt->memSize)))

+ 3 - 3
src/ua_types_encoding_binary.h

@@ -94,15 +94,15 @@ UA_TYPE_BINARY_ENCODING(UA_InvalidType)
 /*********/
 
 /* Computes the size of an array (incl. length field) in a binary blob. */
-UA_UInt32 UA_Array_calcSizeBinary(UA_Int32 length, const UA_VTable_Entry *vt, const void *data);
+UA_UInt32 UA_Array_calcSizeBinary(UA_Int32 length, const UA_TypeVTable *vt, const void *data);
 
 /* @brief Encodes an array into a binary blob. The array size is printed as well. */
-UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 length, const UA_VTable_Entry *vt,
+UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 length, const UA_TypeVTable *vt,
                                     UA_ByteString *dst, UA_UInt32 *offset);
 
 /* @brief Decodes an array from a binary blob. The array is allocated automatically before decoding. */
 UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, UA_UInt32 *offset, UA_Int32 length,
-                                    const UA_VTable_Entry *vt, void **dst);
+                                    const UA_TypeVTable *vt, void **dst);
 
 /// @} /* end of group */
 

+ 2 - 2
tools/generate_namespace.py

@@ -132,7 +132,7 @@ printh('''/**********************************************************
  */
 
 UA_Int32 UA_ns0ToVTableIndex(const UA_NodeId *id);\n
-extern const UA_VTable_Entry UA_EXPORT *UA_TYPES;
+extern const UA_TypeVTable UA_EXPORT *UA_TYPES;
 extern const UA_NodeId UA_EXPORT *UA_NODEIDS;
 extern const UA_ExpandedNodeId UA_EXPORT *UA_EXPANDEDNODEIDS;
 
@@ -176,7 +176,7 @@ for row in rows:
     printh('#define '+name.upper()+'_NS0 '+row[1])
     i=i+1
 
-printc('''const UA_VTable_Entry *UA_TYPES = (UA_VTable_Entry[]){''')
+printc('''const UA_TypeVTable *UA_TYPES = (UA_TypeVTable[]){''')
 for row in rows:
     if row[0] not in type_names:
         continue