瀏覽代碼

finish nodeContext pointer for every node

Julius Pfrommer 6 年之前
父節點
當前提交
394df3be8d

+ 2 - 1
CMakeLists.txt

@@ -253,11 +253,12 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_handling.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_server.h
                      ${PROJECT_SOURCE_DIR}/include/ua_plugin_network.h
                      ${PROJECT_SOURCE_DIR}/include/ua_plugin_log.h
                      ${PROJECT_SOURCE_DIR}/include/ua_plugin_access_control.h
                      ${PROJECT_SOURCE_DIR}/include/ua_plugin_securitypolicy.h
-                     ${PROJECT_SOURCE_DIR}/include/ua_server.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_server_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
                      ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.h

+ 27 - 15
examples/discovery/server_multicast.c

@@ -21,27 +21,39 @@ static void stopHandler(int sign) {
 }
 
 static UA_StatusCode
-readInteger(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
-            const UA_NumericRange *range, UA_DataValue *dataValue) {
-    dataValue->hasValue = true;
-    UA_Variant_setScalarCopy(&dataValue->value, (UA_UInt32 *) handle, &UA_TYPES[UA_TYPES_INT32]);
+readInteger(UA_Server *server, const UA_NodeId *sessionId,
+            void *sessionContext, const UA_NodeId *nodeId,
+            void *nodeContext, UA_Boolean includeSourceTimeStamp,
+            const UA_NumericRange *range, UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    value->hasValue = true;
+    UA_Variant_setScalarCopy(&value->value, myInteger, &UA_TYPES[UA_TYPES_INT32]);
+
     // we know the nodeid is a string
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node read %.*s",
-                (int)nodeid.identifier.string.length, nodeid.identifier.string.data);
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "read value %i", *(UA_UInt32 *) handle);
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "read value %i", *(UA_UInt32 *)myInteger);
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode
-writeInteger(void *handle, const UA_NodeId nodeid,
-             const UA_Variant *data, const UA_NumericRange *range) {
-    if (UA_Variant_isScalar(data) && data->type == &UA_TYPES[UA_TYPES_INT32] && data->data) {
-        *(UA_UInt32 *) handle = *(UA_UInt32 *) data->data;
-    }
+writeInteger(UA_Server *server, const UA_NodeId *sessionId,
+             void *sessionContext, const UA_NodeId *nodeId,
+             void *nodeContext, const UA_NumericRange *range,
+             const UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    if(value->hasValue && UA_Variant_isScalar(&value->value) &&
+       value->value.type == &UA_TYPES[UA_TYPES_INT32] && value->value.data)
+        *myInteger = *(UA_Int32 *)value->value.data;
+
     // we know the nodeid is a string
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node written %.*s",
-                (int)nodeid.identifier.string.length, nodeid.identifier.string.data);
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "written value %i", *(UA_UInt32 *) handle);
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "written value %i", *(UA_UInt32 *)myInteger);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -105,7 +117,6 @@ int main(int argc, char **argv) {
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_DataSource dateDataSource;
-    dateDataSource.handle = &myInteger;
     dateDataSource.read = readInteger;
     dateDataSource.write = writeInteger;
     UA_VariableAttributes attr;
@@ -116,7 +127,8 @@ int main(int argc, char **argv) {
     UA_Server_addDataSourceVariableNode(server, myIntegerNodeId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource, NULL);
+                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource,
+                                        &myInteger, NULL);
 
     // callback which is called when a new server is detected through mDNS
     UA_Server_setServerOnNetworkCallback(server, serverOnNetworkCallback, NULL);

+ 27 - 15
examples/discovery/server_register.c

@@ -22,27 +22,39 @@ static void stopHandler(int sign) {
 }
 
 static UA_StatusCode
-readInteger(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
-            const UA_NumericRange *range, UA_DataValue *dataValue) {
-    dataValue->hasValue = true;
-    UA_Variant_setScalarCopy(&dataValue->value, (UA_UInt32 *) handle, &UA_TYPES[UA_TYPES_INT32]);
+readInteger(UA_Server *server, const UA_NodeId *sessionId,
+            void *sessionContext, const UA_NodeId *nodeId,
+            void *nodeContext, UA_Boolean includeSourceTimeStamp,
+            const UA_NumericRange *range, UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    value->hasValue = true;
+    UA_Variant_setScalarCopy(&value->value, myInteger, &UA_TYPES[UA_TYPES_INT32]);
+
     // we know the nodeid is a string
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node read %.*s",
-                (int)nodeid.identifier.string.length, nodeid.identifier.string.data);
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "read value %i", *(UA_UInt32 *) handle);
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "read value %i", *(UA_UInt32 *)myInteger);
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode
-writeInteger(void *handle, const UA_NodeId nodeid,
-             const UA_Variant *data, const UA_NumericRange *range) {
-    if (UA_Variant_isScalar(data) && data->type == &UA_TYPES[UA_TYPES_INT32] && data->data) {
-        *(UA_UInt32 *) handle = *(UA_UInt32 *) data->data;
-    }
+writeInteger(UA_Server *server, const UA_NodeId *sessionId,
+             void *sessionContext, const UA_NodeId *nodeId,
+             void *nodeContext, const UA_NumericRange *range,
+             const UA_DataValue *value) {
+    UA_Int32 *myInteger = (UA_Int32*)nodeContext;
+    if(value->hasValue && UA_Variant_isScalar(&value->value) &&
+       value->value.type == &UA_TYPES[UA_TYPES_INT32] && value->value.data)
+        *myInteger = *(UA_Int32 *)value->value.data;
+
     // we know the nodeid is a string
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node written %.*s",
-                (int)nodeid.identifier.string.length, nodeid.identifier.string.data);
-    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "written value %i", *(UA_UInt32 *) handle);
+                (int)nodeId->identifier.string.length,
+                nodeId->identifier.string.data);
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND,
+                "written value %i", *(UA_UInt32 *)myInteger);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -67,7 +79,6 @@ int main(int argc, char **argv) {
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_DataSource dateDataSource;
-    dateDataSource.handle = &myInteger;
     dateDataSource.read = readInteger;
     dateDataSource.write = writeInteger;
     UA_VariableAttributes attr;
@@ -78,7 +89,8 @@ int main(int argc, char **argv) {
     UA_Server_addDataSourceVariableNode(server, myIntegerNodeId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource, NULL);
+                                        myIntegerName, UA_NODEID_NULL, attr, dateDataSource,
+                                        &myInteger, NULL);
 
 
     // periodic server register after 10 Minutes, delay first register for 500ms

+ 22 - 19
examples/server.c

@@ -48,7 +48,10 @@ static void stopHandler(int sign) {
 
 /* Datasource Example */
 static UA_StatusCode
-readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
+readTimeData(UA_Server *server,
+             const UA_NodeId *sessionId, void *sessionContext,
+             const UA_NodeId *nodeId, void *nodeContext,
+             UA_Boolean sourceTimeStamp,
              const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = true;
@@ -68,8 +71,10 @@ readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp,
 /* Method Node Example */
 #ifdef UA_ENABLE_METHODCALLS
 static UA_StatusCode
-helloWorld(void *methodHandle, const UA_NodeId *objectId,
-           const UA_NodeId *sessionId, void *sessionHandle,
+helloWorld(UA_Server *server,
+           const UA_NodeId *sessionId, void *sessionContext,
+           const UA_NodeId *methodId, void *methodContext,
+           const UA_NodeId *objectId, void *objectContext,
            size_t inputSize, const UA_Variant *input,
            size_t outputSize, UA_Variant *output) {
     /* input is a scalar string (checked by the server) */
@@ -86,16 +91,20 @@ helloWorld(void *methodHandle, const UA_NodeId *objectId,
 }
 
 static UA_StatusCode
-noargMethod(void *methodHandle, const UA_NodeId *objectId,
-            const UA_NodeId *sessionId, void *sessionHandle,
+noargMethod(UA_Server *server,
+            const UA_NodeId *sessionId, void *sessionContext,
+            const UA_NodeId *methodId, void *methodContext,
+            const UA_NodeId *objectId, void *objectContext,
             size_t inputSize, const UA_Variant *input,
             size_t outputSize, UA_Variant *output) {
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode
-outargMethod(void *methodHandle, const UA_NodeId *objectId,
-            const UA_NodeId *sessionId, void *sessionHandle,
+outargMethod(UA_Server *server,
+             const UA_NodeId *sessionId, void *sessionContext,
+             const UA_NodeId *methodId, void *methodContext,
+             const UA_NodeId *objectId, void *objectContext,
              size_t inputSize, const UA_Variant *input,
              size_t outputSize, UA_Variant *output) {
     UA_Int32 out = 42;
@@ -131,7 +140,6 @@ int main(int argc, char** argv) {
 
     /* add a variable with the datetime data source */
     UA_DataSource dateDataSource;
-    dateDataSource.handle = NULL;
     dateDataSource.read = readTimeData;
     dateDataSource.write = NULL;
     UA_VariableAttributes v_attr;
@@ -143,7 +151,7 @@ int main(int argc, char** argv) {
     UA_NodeId dataSourceId;
     UA_Server_addDataSourceVariableNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,
-                                        UA_NODEID_NULL, v_attr, dateDataSource, &dataSourceId);
+                                        UA_NODEID_NULL, v_attr, dateDataSource, NULL, &dataSourceId);
 
     /* Add HelloWorld method to the server */
 #ifdef UA_ENABLE_METHODCALLS
@@ -174,8 +182,7 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "hello_world"), addmethodattributes,
         &helloWorld, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 1, &outputArguments, NULL);
+        1, &inputArguments, 1, &outputArguments, NULL, NULL);
 #endif
 
     /* Add folders for demo information model */
@@ -328,8 +335,7 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         &noargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        0, NULL, 0, NULL, NULL);
+        0, NULL, 0, NULL, NULL, NULL);
 
     /* Method with in arguments */
     UA_MethodAttributes_init(&addmethodattributes);
@@ -348,8 +354,7 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "noarg"), addmethodattributes,
         &noargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 0, NULL, NULL);
+        1, &inputArguments, 0, NULL, NULL, NULL);
 
     /* Method with out arguments */
     UA_MethodAttributes_init(&addmethodattributes);
@@ -368,8 +373,7 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "outarg"), addmethodattributes,
         &outargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        0, NULL, 1, &outputArguments, NULL);
+        0, NULL, 1, &outputArguments, NULL, NULL);
 
     /* Method with inout arguments */
     UA_MethodAttributes_init(&addmethodattributes);
@@ -382,8 +386,7 @@ int main(int argc, char** argv) {
         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
         UA_QUALIFIEDNAME(1, "inoutarg"), addmethodattributes,
         &outargMethod, /* callback of the method node */
-        NULL, /* handle passed with the callback */
-        1, &inputArguments, 1, &outputArguments, NULL);
+        1, &inputArguments, 1, &outputArguments, NULL, NULL);
 #endif
 
     /* run server */

+ 18 - 12
examples/tutorial_server_datasource.c

@@ -68,9 +68,10 @@ addCurrentTimeVariable(UA_Server *server) {
  * write operation. */
 
 static void
-beforeReadTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
-               const UA_NumericRange *range) {
-    UA_Server *server = (UA_Server*)handle;
+beforeReadTime(UA_Server *server,
+               const UA_NodeId *sessionId, void *sessionContext,
+               const UA_NodeId *nodeid, void *nodeContext, 
+               const UA_NumericRange *range, const UA_DataValue *data) {
     UA_DateTime now = UA_DateTime_now();
     UA_Variant value;
     UA_Variant_setScalar(&value, &now, &UA_TYPES[UA_TYPES_DATETIME]);
@@ -79,8 +80,10 @@ beforeReadTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
 }
 
 static void
-afterWriteTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
-               const UA_NumericRange *range) {
+afterWriteTime(UA_Server *server,
+               const UA_NodeId *sessionId, void *sessionContext,
+               const UA_NodeId *nodeId, void *nodeContext,
+               const UA_NumericRange *range, const UA_DataValue *data) {
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                 "The variable was updated");
 }
@@ -89,7 +92,6 @@ static void
 addValueCallbackToCurrentTimeVariable(UA_Server *server) {
     UA_NodeId currentNodeId = UA_NODEID_STRING(1, "current-time");
     UA_ValueCallback callback ;
-    callback.handle = server;
     callback.onRead = beforeReadTime;
     callback.onWrite = afterWriteTime;
     UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);
@@ -106,8 +108,11 @@ addValueCallbackToCurrentTimeVariable(UA_Server *server) {
  * own memory management. */
 
 static UA_StatusCode
-readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
-                const UA_NumericRange *range, UA_DataValue *dataValue) {
+readCurrentTime(UA_Server *server,
+                const UA_NodeId *sessionId, void *sessionContext,
+                const UA_NodeId *nodeId, void *nodeContext,
+                UA_Boolean sourceTimeStamp, const UA_NumericRange *range,
+                UA_DataValue *dataValue) {
     UA_DateTime now = UA_DateTime_now();
     UA_Variant_setScalarCopy(&dataValue->value, &now,
                              &UA_TYPES[UA_TYPES_DATETIME]);
@@ -116,8 +121,10 @@ readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp
 }
 
 static UA_StatusCode
-writeCurrentTime(void *handle, const UA_NodeId nodeid, const UA_Variant *data,
-                 const UA_NumericRange *range) {
+writeCurrentTime(UA_Server *server,
+                 const UA_NodeId *sessionId, void *sessionContext,
+                 const UA_NodeId *nodeId, void *nodeContext,
+                 const UA_NumericRange *range, const UA_DataValue *data) {
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                 "Changing the system time is not implemented");
     return UA_STATUSCODE_BADINTERNALERROR;
@@ -136,13 +143,12 @@ addCurrentTimeDataSourceVariable(UA_Server *server) {
     UA_NodeId variableTypeNodeId = UA_NODEID_NULL;
 
     UA_DataSource timeDataSource;
-    timeDataSource.handle = NULL;
     timeDataSource.read = readCurrentTime;
     timeDataSource.write = writeCurrentTime;
     UA_Server_addDataSourceVariableNode(server, currentNodeId, parentNodeId,
                                         parentReferenceNodeId, currentName,
                                         variableTypeNodeId, attr,
-                                        timeDataSource, NULL);
+                                        timeDataSource, NULL, NULL);
 }
 
 /** It follows the main server code, making use of the above definitions. */

+ 12 - 7
examples/tutorial_server_method.c

@@ -34,8 +34,10 @@
 #include "open62541.h"
 
 static UA_StatusCode
-helloWorldMethodCallback(void *handle, const UA_NodeId *objectId,
+helloWorldMethodCallback(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionHandle,
+                         const UA_NodeId *methodId, void *methodContext,
+                         const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
     UA_String *inputStr = (UA_String*)input->data;
@@ -76,8 +78,8 @@ addHellWorldMethod(UA_Server *server) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                             UA_QUALIFIEDNAME(1, "hello world"),
-                            helloAttr, &helloWorldMethodCallback, NULL,
-                            1, &inputArgument, 1, &outputArgument, NULL);
+                            helloAttr, &helloWorldMethodCallback,
+                            1, &inputArgument, 1, &outputArgument, NULL, NULL);
 }
 
 /**
@@ -87,8 +89,10 @@ addHellWorldMethod(UA_Server *server) {
  * copy of the array with every entry increased by the scalar. */
 
 static UA_StatusCode
-IncInt32ArrayMethodCallback(void *handle, const UA_NodeId *objectId,
-                            const UA_NodeId *sessionId, void *sessionHandle,
+IncInt32ArrayMethodCallback(UA_Server *server,
+                            const UA_NodeId *sessionId, void *sessionContext,
+                            const UA_NodeId *methodId, void *methodContext,
+                            const UA_NodeId *objectId, void *objectContext,
                             size_t inputSize, const UA_Variant *input,
                             size_t outputSize, UA_Variant *output) {
     UA_Int32 *inputArray = (UA_Int32*)input[0].data;
@@ -148,8 +152,9 @@ addIncInt32ArrayMethod(UA_Server *server) {
                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                             UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                             UA_QUALIFIEDNAME(1, "IncInt32ArrayValues"),
-                            incAttr, &IncInt32ArrayMethodCallback, NULL,
-                            2, inputArguments, 1, &outputArgument, NULL);
+                            incAttr, &IncInt32ArrayMethodCallback,
+                            2, inputArguments, 1, &outputArgument,
+                            NULL, NULL);
 }
 
 /** It follows the main server code, making use of the above definitions. */

+ 16 - 16
examples/tutorial_server_object.c

@@ -256,11 +256,11 @@ addPumpObjectInstance(UA_Server *server, char *name) {
  * pump status to on.
  */
 
-UA_Server *s = NULL; /* required to get the server pointer into the constructor
-                        function (will change for v0.3) */
-
-static void *
-pumpTypeConstructor(const UA_NodeId instance) {
+static UA_StatusCode
+pumpTypeConstructor(UA_Server *server,
+                    const UA_NodeId *sessionId, void *sessionContext,
+                    const UA_NodeId *typeId, void *typeContext,
+                    const UA_NodeId *nodeId, void **nodeContext) {
     UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New pump created");
 
     /* Find the NodeId of the status child variable */
@@ -273,33 +273,34 @@ pumpTypeConstructor(const UA_NodeId instance) {
     
     UA_BrowsePath bp;
     UA_BrowsePath_init(&bp);
-    bp.startingNode = instance;
+    bp.startingNode = *nodeId;
     bp.relativePath.elementsSize = 1;
     bp.relativePath.elements = &rpe;
     
     UA_BrowsePathResult bpr =
-        UA_Server_translateBrowsePathToNodeIds(s, &bp);
+        UA_Server_translateBrowsePathToNodeIds(server, &bp);
     if(bpr.statusCode != UA_STATUSCODE_GOOD ||
        bpr.targetsSize < 1)
-        return NULL;
+        return bpr.statusCode;
 
     /* Set the status value */
     UA_Boolean status = true;
     UA_Variant value;
     UA_Variant_setScalar(&value, &status, &UA_TYPES[UA_TYPES_BOOLEAN]);
-    UA_Server_writeValue(s, bpr.targets[0].targetId.nodeId, value);
+    UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
     UA_BrowsePathResult_deleteMembers(&bpr);
 
-    /* The return pointer of the constructor is attached to the ObjectNode */
-    return NULL;
+    /* At this point we could replace the node context .. */
+
+    return UA_STATUSCODE_GOOD;
 }
 
 static void
 addPumpTypeConstructor(UA_Server *server) {
-    UA_ObjectLifecycleManagement olm;
-    olm.constructor = pumpTypeConstructor;
-    olm.destructor = NULL;
-    UA_Server_setObjectTypeNode_lifecycleManagement(server, pumpTypeId, olm);
+    UA_NodeTypeLifecycle lifecycle;
+    lifecycle.constructor = pumpTypeConstructor;
+    lifecycle.destructor = NULL;
+    UA_Server_setNodeTypeLifecycle(server, pumpTypeId, lifecycle);
 }
 
 /** It follows the main server code, making use of the above definitions. */
@@ -316,7 +317,6 @@ int main(void) {
 
     UA_ServerConfig *config = UA_ServerConfig_new_default();
     UA_Server *server = UA_Server_new(config);
-    s = server; /* required for the constructor */
 
     manuallyDefinePump(server);
     defineObjectTypes(server);

+ 16 - 24
include/ua_plugin_access_control.h

@@ -23,55 +23,47 @@ typedef struct {
     UA_Boolean enableAnonymousLogin;
     UA_Boolean enableUsernamePasswordLogin;
 
-    /* Authenticate a session. The session handle is attached to the session and
+    /* Authenticate a session. The session context is attached to the session and
      * later passed into the node-based access control callbacks. */
     UA_StatusCode (*activateSession)(const UA_NodeId *sessionId,
                                      const UA_ExtensionObject *userIdentityToken,
-                                     void **sessionHandle);
+                                     void **sessionContext);
 
     /* Deauthenticate a session and cleanup */
-    void (*closeSession)(const UA_NodeId *sessionId, void *sessionHandle);
+    void (*closeSession)(const UA_NodeId *sessionId, void *sessionContext);
 
     /* Access control for all nodes*/
-    UA_UInt32 (*getUserRightsMask)(const UA_NodeId *sessionId,
-                                   void *sessionHandle,
-                                   const UA_NodeId *nodeId);
+    UA_UInt32 (*getUserRightsMask)(const UA_NodeId *sessionId, void *sessionContext,
+                                   const UA_NodeId *nodeId, void *nodeContext);
 
     /* Additional access control for variable nodes */
-    UA_Byte (*getUserAccessLevel)(const UA_NodeId *sessionId,
-                                  void *sessionHandle,
-                                  const UA_NodeId *nodeId);
+    UA_Byte (*getUserAccessLevel)(const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *nodeId, void *nodeContext);
 
     /* Additional access control for method nodes */
-    UA_Boolean (*getUserExecutable)(const UA_NodeId *sessionId,
-                                    void *sessionHandle,
-                                    const UA_NodeId *methodId);
+    UA_Boolean (*getUserExecutable)(const UA_NodeId *sessionId, void *sessionContext,
+                                    const UA_NodeId *methodId, void *methodContext);
 
     /* Additional access control for calling a method node in the context of a
      * specific object */
-    UA_Boolean (*getUserExecutableOnObject)(const UA_NodeId *sessionId,
-                                            void *sessionHandle,
-                                            const UA_NodeId *methodId,
-                                            const UA_NodeId *objectId);
+    UA_Boolean (*getUserExecutableOnObject)(const UA_NodeId *sessionId, void *sessionContext,
+                                            const UA_NodeId *methodId, void *methodContext,
+                                            const UA_NodeId *objectId, void *objectContext);
 
     /* Allow adding a node */
-    UA_Boolean (*allowAddNode)(const UA_NodeId *sessionId,
-                               void *sessionHandle,
+    UA_Boolean (*allowAddNode)(const UA_NodeId *sessionId, void *sessionContext,
                                const UA_AddNodesItem *item);
 
     /* Allow adding a reference */
-    UA_Boolean (*allowAddReference)(const UA_NodeId *sessionId,
-                                    void *sessionHandle,
+    UA_Boolean (*allowAddReference)(const UA_NodeId *sessionId, void *sessionContext,
                                     const UA_AddReferencesItem *item);
 
     /* Allow deleting a node */
-    UA_Boolean (*allowDeleteNode)(const UA_NodeId *sessionId,
-                                  void *sessionHandle,
+    UA_Boolean (*allowDeleteNode)(const UA_NodeId *sessionId, void *sessionContext,
                                   const UA_DeleteNodesItem *item);
 
     /* Allow deleting a reference */
-    UA_Boolean (*allowDeleteReference)(const UA_NodeId *sessionId,
-                                       void *sessionHandle,
+    UA_Boolean (*allowDeleteReference)(const UA_NodeId *sessionId, void *sessionContext,
                                        const UA_DeleteReferencesItem *item);
 } UA_AccessControl;
 

+ 106 - 76
include/ua_server.h

@@ -279,6 +279,7 @@ UA_Server_readExecutable(UA_Server *server, const UA_NodeId nodeId,
  * - UserExecutable
  *
  * Historizing is currently unsupported */
+
 /* Overwrite an attribute of a node. The specialized functions below provide a
  * more concise syntax.
  *
@@ -532,23 +533,35 @@ UA_Server_setServerOnNetworkCallback(UA_Server *server,
 #endif /* UA_ENABLE_DISCOVERY */
 
 /**
- * Information Model
- * -----------------
- *
- * Every node has a context pointer. Initially, the node context is set to
- * user-defined data (can be NULL). During instantiation, when all mandatory
- * node children have been created, constructor callbacks are executed on the
- * node that may replace the context pointer. When the ``AddNodes`` service is
- * used over the network, the context pointer of the new node is initially set
- * to NULL.
- *
- * The server-wide global constructor and destructor callbacks are executed on
- * all created and deleted nodes. The node-type constructors and destructors are
- * only defined for ObjectTypes and VariableTypes. In the hierarchy of
- * ObjectTypes and VariableTypes, only the lowest type constructor is executed.
- * Every Object and Variable can have only one type with a ``isTypeOf``
- * reference. Issues of multiple inheritance need to be solved by the user in
- * the constructor/destructor.
+ * Information Model Callbacks
+ * ---------------------------
+ *
+ * There are three places where a callback from an information model to
+ * user-defined code can happen.
+ *
+ * - Custom node constructors and destructors
+ * - Linking VariableNodes with an external data source
+ * - MethodNode callbacks
+ *
+ * .. _node-lifecycle:
+ *
+ * Node Lifecycle: Constructors, Destructors and Node Contexts
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ * To finalize the instantiation of a node, a (user-defined) constructor
+ * callback is executed. There can be both a global constructor for all nodes
+ * and node-type constructor specific to the TypeDefinition of the new node
+ * (attached to an ObjectTypeNode or VariableTypeNode).
+ *
+ * In the hierarchy of ObjectTypes and VariableTypes, only the constructor of
+ * the (lowest) type defined for the new node is executed. Note that every
+ * Object and Variable can have only one ``isTypeOf`` reference. But type-nodes
+ * can technically have several ``hasSubType`` references to implement multiple
+ * inheritance. Issues of (multiple) inheritance in the constructor need to be
+ * solved by the user.
+ *
+ * When a node is destroyed, the node-type destructor is called before the
+ * global destructor. So the overall node lifecycle is as follows:
  *
  * 1. Global Constructor (set in the server config)
  * 2. Node-Type Constructor (for VariableType or ObjectTypes)
@@ -556,31 +569,43 @@ UA_Server_setServerOnNetworkCallback(UA_Server *server,
  * 4. Node-Type Destructor
  * 5. Global Destructor
  *
- * The constructor and destructor callbacks can be set to NULL and are not used
- * in that case. If the node-type constructor fails, the global destructor will
- * be called on the node before removing it. The destructors are assumed to
- * never fail. */
+ * The constructor and destructor callbacks can be set to ``NULL`` and are not
+ * used in that case. If the node-type constructor fails, the global destructor
+ * will be called before removing the node. The destructors are assumed to never
+ * fail.
+ *
+ * Every node carries a user-context and a constructor-context pointer. The
+ * user-context is used to attach custom data to a node. But the (user-defined)
+ * constructors and destructors may replace the user-context pointer if they
+ * wish to do so. The initial value for the constructor-context is ``NULL``.
+ * When the ``AddNodes`` service is used over the network, the user-context
+ * pointer of the new node is also initially set to ``NULL``. */
 
 /* To be set in the server config. */
 typedef struct {
     /* Can be NULL. May replace the nodeContext */
-    UA_StatusCode (*constructor)(UA_Server *server, void *userSessionContext,
+    UA_StatusCode (*constructor)(UA_Server *server,
+                                 const UA_NodeId *sessionId, void *sessionContext,
                                  const UA_NodeId *nodeId, void **nodeContext);
 
-    /* Can be NULL. */
-    void (*destructor)(UA_Server *server, const UA_NodeId *nodeId,
-                       void *nodeContext);
+    /* Can be NULL. The context cannot be replaced since the node is destroyed
+     * immediately afterwards anyway. */
+    void (*destructor)(UA_Server *server,
+                       const UA_NodeId *sessionId, void *sessionContext,
+                       const UA_NodeId *nodeId, void *nodeContext);
 } UA_GlobalNodeLifecycle;
 
 typedef struct {
     /* Can be NULL. May replace the nodeContext */
-    UA_StatusCode (*constructor)(UA_Server *server, void *userSessionContext,
-                                 const UA_NodeId *typeId, void *typeContext,
+    UA_StatusCode (*constructor)(UA_Server *server,
+                                 const UA_NodeId *sessionId, void *sessionContext,
+                                 const UA_NodeId *typeNodeId, void *typeNodeContext,
                                  const UA_NodeId *nodeId, void **nodeContext);
 
     /* Can be NULL. May replace the nodeContext. */
     void (*destructor)(UA_Server *server,
-                       const UA_NodeId *typeId, void *typeContext,
+                       const UA_NodeId *sessionId, void *sessionContext,
+                       const UA_NodeId *typeNodeId, void *typeNodeContext,
                        const UA_NodeId *nodeId, void **nodeContext);
 } UA_NodeTypeLifecycle;
 
@@ -589,25 +614,19 @@ UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                                UA_NodeTypeLifecycle lifecycle);
 
 UA_StatusCode UA_EXPORT
-UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId, void **context);
+UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void **nodeContext);
 
-/* Careful! The context pointer might have been replaced by a constructor.
- * The user has to ensure that the destructor callbacks still work. */
+/* Careful! The user has to ensure that the destructor callbacks still work. */
 UA_StatusCode UA_EXPORT
-UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId, void *context);
+UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void *nodeContext);
 
 /**
- * Variable Value Storage
- * ^^^^^^^^^^^^^^^^^^^^^^
- * - Datasources for variable nodes, where the variable content is managed
- *   externally
- * - Value-callbacks for variable nodes, where userspace is notified when a
- *   read/write occurs
- *
  * .. _datasource:
  *
  * Data Source Callback
- * ~~~~~~~~~~~~~~~~~~~~
+ * ^^^^^^^^^^^^^^^^^^^^
  *
  * The server has a unique way of dealing with the content of variables. Instead
  * of storing a variant attached to the variable node, the node can point to a
@@ -635,8 +654,9 @@ typedef struct {
      * @return Returns a status code for logging. Error codes intended for the
      *         original caller are set in the value. If an error is returned,
      *         then no releasing of the value is done. */
-    UA_StatusCode (*read)(const UA_NodeId *nodeId, void *nodeContext,
-                          UA_Boolean includeSourceTimeStamp,
+    UA_StatusCode (*read)(UA_Server *server, const UA_NodeId *sessionId,
+                          void *sessionContext, const UA_NodeId *nodeId,
+                          void *nodeContext, UA_Boolean includeSourceTimeStamp,
                           const UA_NumericRange *range, UA_DataValue *value);
 
     /* Write into a data source. The write member of UA_DataSource can be empty
@@ -649,8 +669,10 @@ typedef struct {
      * @param range An optional data range. If the data source is scalar or does
      *        not support writing of ranges, then an error code is returned.
      * @return Returns a status code that is returned to the user */
-    UA_StatusCode (*write)(const UA_NodeId *nodeId, void *nodeContext,
-                           const UA_Variant *data, const UA_NumericRange *range);
+    UA_StatusCode (*write)(UA_Server *server, const UA_NodeId *sessionId,
+                           void *sessionContext, const UA_NodeId *nodeId,
+                           void *nodeContext, const UA_NumericRange *range,
+                           const UA_DataValue *value);
 } UA_DataSource;
 
 UA_StatusCode UA_EXPORT
@@ -661,9 +683,9 @@ UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
  * .. _value-callback:
  *
  * Value Callback
- * ~~~~~~~~~~~~~~
+ * ^^^^^^^^^^^^^^
  * Value Callbacks can be attached to variable and variable type nodes. If
- * not-null, they are called before reading and after writing respectively. */
+ * not ``NULL``, they are called before reading and after writing respectively. */
 typedef struct {
     /* Called before the value attribute is read. It is possible to write into the
      * value attribute during onRead (using the write service). The node is
@@ -675,19 +697,29 @@ typedef struct {
      * @param data Points to the current node value.
      * @param range Points to the numeric range the client wants to read from
      *        (or NULL). */
-    void (*onRead)(const UA_NodeId *nodeid, void *nodeContext, 
-                   const UA_Variant *data, const UA_NumericRange *range);
+    void (*onRead)(UA_Server *server, const UA_NodeId *sessionId,
+                   void *sessionContext, const UA_NodeId *nodeid,
+                   void *nodeContext, const UA_NumericRange *range,
+                   const UA_DataValue *value);
 
     /* Called after writing the value attribute. The node is re-opened after
      * writing so that the new value is visible in the callback.
      *
-     * @param handle Points to user-provided data for the callback.
+     * @param server The server executing the callback
+     * @sessionId The identifier of the session
+     * @sessionContext Additional data attached to the session
+     *                 in the access control layer
      * @param nodeid The identifier of the node.
-     * @param data Points to the current node value (after writing).
+     * @param nodeUserContext Additional data attached to the node by
+     *        the user.
+     * @param nodeConstructorContext Additional data attached to the node
+     *        by the type constructor(s).
      * @param range Points to the numeric range the client wants to write to (or
      *        NULL). */
-    void (*onWrite)(const UA_NodeId *nodeId, void *nodeContext,
-                    const UA_Variant *data, const UA_NumericRange *range);
+    void (*onWrite)(UA_Server *server, const UA_NodeId *sessionId,
+                    void *sessionContext, const UA_NodeId *nodeId,
+                    void *nodeContext, const UA_NumericRange *range,
+                    const UA_DataValue *data);
 } UA_ValueCallback;
 
 UA_StatusCode UA_EXPORT
@@ -697,13 +729,19 @@ UA_Server_setVariableNode_valueCallback(UA_Server *server,
 
 /**
  * Method Callbacks
- * ~~~~~~~~~~~~~~~~ */
+ * ^^^^^^^^^^^^^^^^
+ * Method callbacks are set to `NULL` (not executable) when a method node is added
+ * over the network. In theory, it is possible to add a callback via
+ * ``UA_Server_setMethodNode_callback`` within the global constructor when adding
+ * methods over the network is really wanted. */
+
 typedef UA_StatusCode
-(*UA_MethodCallback)(const UA_NodeId *methodId, void *methodContext,
-                     const UA_NodeId *objectId, void *objectContext,
-                     const UA_NodeId *sessionId, void *sessionContext,
-                     size_t inputSize, const UA_Variant *input,
-                     size_t outputSize, UA_Variant *output);
+(*UA_MethodCallback)(UA_Server *server, const UA_NodeId *sessionId,
+                     void *sessionContext, const UA_NodeId *methodId,
+                     void *methodContext, const UA_NodeId *objectId,
+                     void *objectContext, size_t inputSize,
+                     const UA_Variant *input, size_t outputSize,
+                     UA_Variant *output);
 
 #ifdef UA_ENABLE_METHODCALLS
 
@@ -720,25 +758,26 @@ UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request);
  * .. _addnodes:
  *
  * Node Addition and Deletion
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * --------------------------
  * When creating dynamic node instances at runtime, chances are that you will
  * not care about the specific NodeId of the new node, as long as you can
  * reference it later. When passing numeric NodeIds with a numeric identifier 0,
  * the stack evaluates this as "select a random unassigned numeric NodeId in
  * that namespace". To find out which NodeId was actually assigned to the new
  * node, you may pass a pointer `outNewNodeId`, which will (after a successfull
- * node insertion) contain the nodeId of the new node. You may also pass NULL
- * pointer if this result is not relevant. The namespace index for nodes you
- * create should never be 0, as that index is reserved for OPC UA's
- * self-description (namespace * 0).
+ * node insertion) contain the nodeId of the new node. You may also pass a
+ * ``NULL`` pointer if this result is not needed.
+ *
+ * See the Section :ref:`node-lifecycle` on constructors and on attaching
+ * user-defined data to nodes.
  *
  * The methods for node addition and deletion take mostly const arguments that
  * are not modified. When creating a node, a deep copy of the node identifier,
  * node attributes, etc. is created. Therefore, it is possible to call for
- * example `UA_Server_addVariablenode` with a value attribute (a :ref:`variant`)
- * pointing to a memory location on the stack. If you need changes to a variable
- * value to manifest at a specific memory location, please use a
- * :ref:`datasource` or a :ref:`value-callback`. */
+ * example ``UA_Server_addVariablenode`` with a value attribute (a
+ * :ref:`variant`) pointing to a memory location on the stack. If you need
+ * changes to a variable value to manifest at a specific memory location, please
+ * use a :ref:`datasource` or a :ref:`value-callback`. */
 
 /* Protect against redundant definitions for server/client */
 #ifndef UA_DEFAULT_ATTRIBUTES_DEFINED
@@ -757,15 +796,6 @@ UA_EXPORT extern const UA_DataTypeAttributes UA_DataTypeAttributes_default;
 UA_EXPORT extern const UA_ViewAttributes UA_ViewAttributes_default;
 #endif
 
-/* 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_StatusCode (*method)(const UA_NodeId objectId,
-                          const UA_NodeId typeDefinitionId, void *handle);
-  void *handle;
-} UA_InstantiationCallback;
-
 /* Don't use this function. There are typed versions as inline functions. */
 UA_StatusCode UA_EXPORT
 __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,

+ 1 - 1
include/ua_server_config.h

@@ -46,7 +46,7 @@ struct UA_ServerConfig {
 
     /* Custom DataTypes */
     size_t customDataTypesSize;
-    const UA_DataType *customDataTypes;
+    UA_DataType *customDataTypes;
 
     /* Networking */
     size_t networkLayersSize;

+ 18 - 27
plugins/ua_accesscontrol_default.c

@@ -28,7 +28,7 @@ UA_UsernamePasswordLogin usernamePasswords[2] = {
 UA_StatusCode
 activateSession_default(const UA_NodeId *sessionId,
                         const UA_ExtensionObject *userIdentityToken,
-                        void **sessionHandle) {
+                        void **sessionContext) {
     /* Could the token be decoded? */
     if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED)
         return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
@@ -47,7 +47,7 @@ activateSession_default(const UA_NodeId *sessionId,
             return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
 
         /* No userdata atm */
-        *sessionHandle = NULL;
+        *sessionContext = NULL;
         return UA_STATUSCODE_GOOD;
     }
 
@@ -78,7 +78,7 @@ activateSession_default(const UA_NodeId *sessionId,
             return UA_STATUSCODE_BADUSERACCESSDENIED;
 
         /* No userdata atm */
-        *sessionHandle = NULL;
+        *sessionContext = NULL;
         return UA_STATUSCODE_GOOD;
     }
 
@@ -87,64 +87,55 @@ activateSession_default(const UA_NodeId *sessionId,
 }
 
 void
-closeSession_default(const UA_NodeId *sessionId,
-                     void *sessionHandle) {
-    /* no handle to clean up */
+closeSession_default(const UA_NodeId *sessionId, void *sessionContext) {
+    /* no context to clean up */
 }
 
 UA_UInt32
-getUserRightsMask_default(const UA_NodeId *sessionId,
-                          void *sessionHandle,
-                          const UA_NodeId *nodeId) {
+getUserRightsMask_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *nodeId, void *nodeContext) {
     return 0xFFFFFFFF;
 }
 
 UA_Byte
-getUserAccessLevel_default(const UA_NodeId *sessionId,
-                           void *sessionHandle,
-                           const UA_NodeId *nodeId) {
+getUserAccessLevel_default(const UA_NodeId *sessionId, void *sessionContext,
+                           const UA_NodeId *nodeId, void *nodeContext) {
     return 0xFF;
 }
 
 UA_Boolean
-getUserExecutable_default(const UA_NodeId *sessionId,
-                          void *sessionHandle,
-                          const UA_NodeId *nodeId) {
+getUserExecutable_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *methodId, void *methodContext) {
     return true;
 }
 
 UA_Boolean
-getUserExecutableOnObject_default(const UA_NodeId *sessionId,
-                                  void *sessionHandle,
-                                  const UA_NodeId *methodId,
-                                  const UA_NodeId *objectId) {
+getUserExecutableOnObject_default(const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *methodId, void *methodContext,
+                                  const UA_NodeId *objectId, void *objectContext) {
     return true;
 }
 
 UA_Boolean
-allowAddNode_default(const UA_NodeId *sessionId,
-                     void *sessionHandle,
+allowAddNode_default(const UA_NodeId *sessionId, void *sessionContext,
                      const UA_AddNodesItem *item) {
     return true;
 }
 
 UA_Boolean
-allowAddReference_default(const UA_NodeId *sessionId,
-                          void *sessionHandle,
+allowAddReference_default(const UA_NodeId *sessionId, void *sessionContext,
                           const UA_AddReferencesItem *item) {
     return true;
 }
 
 UA_Boolean
-allowDeleteNode_default(const UA_NodeId *sessionId,
-                        void *sessionHandle,
+allowDeleteNode_default(const UA_NodeId *sessionId, void *sessionContext,
                         const UA_DeleteNodesItem *item) {
     return true;
 }
       
 UA_Boolean
-allowDeleteReference_default(const UA_NodeId *sessionId,
-                             void *sessionHandle,
+allowDeleteReference_default(const UA_NodeId *sessionId, void *sessionContext,
                              const UA_DeleteReferencesItem *item) {
     return true;
 }

+ 15 - 16
plugins/ua_accesscontrol_default.h

@@ -13,43 +13,42 @@ extern "C" {
 UA_StatusCode UA_EXPORT
 activateSession_default(const UA_NodeId *sessionId,
                         const UA_ExtensionObject *userIdentityToken,
-                        void **sessionHandle);
+                        void **sessionContext);
 
 void UA_EXPORT
-closeSession_default(const UA_NodeId *sessionId, void *sessionHandle);
+closeSession_default(const UA_NodeId *sessionId, void *sessionContext);
 
 UA_UInt32 UA_EXPORT
-getUserRightsMask_default(const UA_NodeId *sessionId, void *sessionHandle,
-                          const UA_NodeId *nodeId);
+getUserRightsMask_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *nodeId, void *nodeContext);
 
 UA_Byte UA_EXPORT
-getUserAccessLevel_default(const UA_NodeId *sessionId, void *sessionHandle,
-                           const UA_NodeId *nodeId);
+getUserAccessLevel_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *nodeId, void *nodeContext);
 
 UA_Boolean UA_EXPORT
-getUserExecutable_default(const UA_NodeId *sessionId, void *sessionHandle,
-                          const UA_NodeId *nodeId);
+getUserExecutable_default(const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *methodId, void *methodContext);
 
 UA_Boolean UA_EXPORT
-getUserExecutableOnObject_default(const UA_NodeId *sessionId,
-                                  void *sessionHandle,
-                                  const UA_NodeId *methodId,
-                                  const UA_NodeId *objectId);
+getUserExecutableOnObject_default(const UA_NodeId *sessionId, void *sessionContext,
+                                  const UA_NodeId *methodId, void *methodContext,
+                                  const UA_NodeId *objectId, void *objectContext);
 
 UA_Boolean UA_EXPORT
-allowAddNode_default(const UA_NodeId *sessionId, void *sessionHandle,
+allowAddNode_default(const UA_NodeId *sessionId, void *sessionContext,
                      const UA_AddNodesItem *item);
 
 UA_Boolean UA_EXPORT
-allowAddReference_default(const UA_NodeId *sessionId, void *sessionHandle,
+allowAddReference_default(const UA_NodeId *sessionId, void *sessionContext,
                           const UA_AddReferencesItem *item);
 
 UA_Boolean UA_EXPORT
-allowDeleteNode_default(const UA_NodeId *sessionId, void *sessionHandle,
+allowDeleteNode_default(const UA_NodeId *sessionId, void *sessionContext,
                         const UA_DeleteNodesItem *item);
 
 UA_Boolean UA_EXPORT
-allowDeleteReference_default(const UA_NodeId *sessionId, void *sessionHandle,
+allowDeleteReference_default(const UA_NodeId *sessionId, void *sessionContext,
                              const UA_DeleteReferencesItem *item);
 
 #ifdef __cplusplus

+ 4 - 0
plugins/ua_config_standard.c

@@ -142,6 +142,10 @@ UA_ServerConfig_new_minimal(UA_UInt16 portNumber,
     /* Endpoints */
     /* conf->endpoints = {0, NULL}; */
 
+    /* Global Node Lifecycle */
+    conf->nodeLifecycle.constructor = NULL;
+    conf->nodeLifecycle.destructor = NULL;
+
     /* Access Control */
     conf->accessControl.enableAnonymousLogin = true;
     conf->accessControl.enableUsernamePasswordLogin = true;

+ 1 - 0
plugins/ua_config_standard.h

@@ -9,6 +9,7 @@ extern "C" {
 #endif
 
 #include "ua_server.h"
+#include "ua_server_config.h"
 #include "ua_client.h"
 #include "ua_client_highlevel.h"
 

+ 308 - 14
src/server/ua_nodes.c

@@ -5,19 +5,8 @@
 #include "ua_server_internal.h"
 #include "ua_nodes.h"
 
-void UA_Node_deleteReferences(UA_Node *node) {
-    for(size_t i = 0; i < node->referencesSize; ++i) {
-        UA_NodeReferenceKind *refs = &node->references[i];
-        for(size_t j = 0; j < refs->targetIdsSize; ++j)
-            UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j]);
-        UA_free(refs->targetIds);
-        UA_NodeId_deleteMembers(&refs->referenceTypeId);
-    }
-    if(node->references)
-        UA_free(node->references);
-    node->references = NULL;
-    node->referencesSize = 0;
-}
+/* There is no UA_Node_new() method here. Creating nodes is part of the
+ * NodeStore layer */
 
 void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
     /* Delete standard content */
@@ -157,7 +146,7 @@ UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst) {
     retval |= UA_LocalizedText_copy(&src->description, &dst->description);
     dst->writeMask = src->writeMask;
     dst->context = src->context;
-    dst->lifecycleState = src->lifecycleState;
+    dst->constructed = src->constructed;
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Node_deleteMembersAnyNodeClass(dst);
         return retval;
@@ -230,3 +219,308 @@ UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst) {
 
     return retval;
 }
+
+/******************************/
+/* Copy Attributes into Nodes */
+/******************************/
+
+static UA_StatusCode
+copyStandardAttributes(UA_Node *node, const UA_AddNodesItem *item,
+                       const UA_NodeAttributes *attr) {
+    UA_StatusCode retval;
+    retval  = UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId);
+    retval |= UA_QualifiedName_copy(&item->browseName, &node->browseName);
+    retval |= UA_LocalizedText_copy(&attr->displayName, &node->displayName);
+    retval |= UA_LocalizedText_copy(&attr->description, &node->description);
+    node->writeMask = attr->writeMask;
+    return retval;
+}
+
+static UA_StatusCode
+copyCommonVariableAttributes(UA_VariableNode *node,
+                             const UA_VariableAttributes *attr) {
+    /* Copy the array dimensions */
+    UA_StatusCode retval =
+        UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
+                      (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    node->arrayDimensionsSize = attr->arrayDimensionsSize;
+
+    /* Data type and value rank */
+    retval |= UA_NodeId_copy(&attr->dataType, &node->dataType);
+    node->valueRank = attr->valueRank;
+
+    /* Copy the value */
+    node->valueSource = UA_VALUESOURCE_DATA;
+    retval |= UA_Variant_copy(&attr->value, &node->value.data.value.value);
+    node->value.data.value.hasValue = true;
+
+    return retval;
+}
+
+static UA_StatusCode
+copyVariableNodeAttributes(UA_VariableNode *vnode,
+                           const UA_VariableAttributes *attr) {
+    vnode->accessLevel = attr->accessLevel;
+    vnode->historizing = attr->historizing;
+    vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
+    return copyCommonVariableAttributes(vnode, attr);
+}
+
+static UA_StatusCode
+copyVariableTypeNodeAttributes(UA_VariableTypeNode *vtnode,
+                               const UA_VariableTypeAttributes *attr) {
+    vtnode->isAbstract = attr->isAbstract;
+    return copyCommonVariableAttributes((UA_VariableNode*)vtnode,
+                                        (const UA_VariableAttributes*)attr);
+}
+
+static UA_StatusCode
+copyObjectNodeAttributes(UA_ObjectNode *onode, const UA_ObjectAttributes *attr) {
+    onode->eventNotifier = attr->eventNotifier;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+copyReferenceTypeNodeAttributes(UA_ReferenceTypeNode *rtnode,
+                                const UA_ReferenceTypeAttributes *attr) {
+    rtnode->isAbstract = attr->isAbstract;
+    rtnode->symmetric = attr->symmetric;
+    return UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
+}
+
+static UA_StatusCode
+copyObjectTypeNodeAttributes(UA_ObjectTypeNode *otnode,
+                             const UA_ObjectTypeAttributes *attr) {
+    otnode->isAbstract = attr->isAbstract;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+copyViewNodeAttributes(UA_ViewNode *vnode, const UA_ViewAttributes *attr) {
+    vnode->containsNoLoops = attr->containsNoLoops;
+    vnode->eventNotifier = attr->eventNotifier;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+copyDataTypeNodeAttributes(UA_DataTypeNode *dtnode,
+                           const UA_DataTypeAttributes *attr) {
+    dtnode->isAbstract = attr->isAbstract;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+copyMethodNodeAttributes(UA_MethodNode *mnode,
+                         const UA_MethodAttributes *attr) {
+    mnode->executable = attr->executable;
+    return UA_STATUSCODE_GOOD;
+}
+
+#define CHECK_ATTRIBUTES(TYPE)                                          \
+    if(item->nodeAttributes.content.decoded.type != &UA_TYPES[UA_TYPES_##TYPE]) { \
+        retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;                \
+        break;                                                          \
+    }
+
+/* Copy the attributes into a new node. On success, newNode points to the
+ * created node */
+UA_StatusCode
+UA_Node_createFromAttributes(const UA_AddNodesItem *item, UA_Node **newNode) {
+    /* Check that we can read the attributes */
+    if(item->nodeAttributes.encoding < UA_EXTENSIONOBJECT_DECODED ||
+       !item->nodeAttributes.content.decoded.type)
+        return UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+
+    /* Create the node */
+    // todo: error case where the nodeclass is faulty should return a different
+    // status code
+    UA_Node *node = UA_NodeStore_newNode(item->nodeClass);
+    if(!node)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    /* Copy the attributes into the node */
+    void *data = item->nodeAttributes.content.decoded.data;
+    UA_StatusCode retval = copyStandardAttributes(node, item,
+                                                  (const UA_NodeAttributes*)data);
+    switch(item->nodeClass) {
+    case UA_NODECLASS_OBJECT:
+        CHECK_ATTRIBUTES(OBJECTATTRIBUTES);
+        retval |= copyObjectNodeAttributes((UA_ObjectNode*)node,
+                                           (const UA_ObjectAttributes*)data);
+        break;
+    case UA_NODECLASS_VARIABLE:
+        CHECK_ATTRIBUTES(VARIABLEATTRIBUTES);
+        retval |= copyVariableNodeAttributes((UA_VariableNode*)node,
+                                             (const UA_VariableAttributes*)data);
+        break;
+    case UA_NODECLASS_OBJECTTYPE:
+        CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES);
+        retval |= copyObjectTypeNodeAttributes((UA_ObjectTypeNode*)node,
+                                               (const UA_ObjectTypeAttributes*)data);
+        break;
+    case UA_NODECLASS_VARIABLETYPE:
+        CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES);
+        retval |= copyVariableTypeNodeAttributes((UA_VariableTypeNode*)node,
+                                                 (const UA_VariableTypeAttributes*)data);
+        break;
+    case UA_NODECLASS_REFERENCETYPE:
+        CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES);
+        retval |= copyReferenceTypeNodeAttributes((UA_ReferenceTypeNode*)node,
+                                                  (const UA_ReferenceTypeAttributes*)data);
+        break;
+    case UA_NODECLASS_DATATYPE:
+        CHECK_ATTRIBUTES(DATATYPEATTRIBUTES);
+        retval |= copyDataTypeNodeAttributes((UA_DataTypeNode*)node,
+                                             (const UA_DataTypeAttributes*)data);
+        break;
+    case UA_NODECLASS_VIEW:
+        CHECK_ATTRIBUTES(VIEWATTRIBUTES);
+        retval |= copyViewNodeAttributes((UA_ViewNode*)node,
+                                         (const UA_ViewAttributes*)data);
+        break;
+    case UA_NODECLASS_METHOD:
+        CHECK_ATTRIBUTES(METHODATTRIBUTES);
+        retval |= copyMethodNodeAttributes((UA_MethodNode*)node,
+                                           (const UA_MethodAttributes*)data);
+        break;
+    case UA_NODECLASS_UNSPECIFIED:
+    default:
+        retval = UA_STATUSCODE_BADNODECLASSINVALID;
+    }
+
+    if(retval == UA_STATUSCODE_GOOD)
+        *newNode = (UA_Node*)node;
+    else
+        UA_NodeStore_deleteNode(node);
+
+    return retval;
+}
+
+/*********************/
+/* Manage References */
+/*********************/
+
+static UA_StatusCode
+addReferenceTarget(UA_NodeReferenceKind *refs, const UA_ExpandedNodeId *target) {
+    UA_ExpandedNodeId *targets =
+        (UA_ExpandedNodeId*) UA_realloc(refs->targetIds,
+                                        sizeof(UA_ExpandedNodeId) * (refs->targetIdsSize+1));
+    if(!targets)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    refs->targetIds = targets;
+    UA_StatusCode retval =
+        UA_ExpandedNodeId_copy(target, &refs->targetIds[refs->targetIdsSize]);
+
+    if(retval == UA_STATUSCODE_GOOD) {
+        refs->targetIdsSize++;
+    } else if(refs->targetIdsSize == 0) {
+        /* We had zero references before (realloc was a malloc) */
+        UA_free(refs->targetIds);
+        refs->targetIds = NULL;
+    }
+    return retval;
+}
+
+static UA_StatusCode
+addReferenceKind(UA_Node *node, const UA_AddReferencesItem *item) {
+    UA_NodeReferenceKind *refs =
+        (UA_NodeReferenceKind*)UA_realloc(node->references,
+                                          sizeof(UA_NodeReferenceKind) * (node->referencesSize+1));
+    if(!refs)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+    node->references = refs;
+    UA_NodeReferenceKind *newRef = &refs[node->referencesSize];
+    memset(newRef, 0, sizeof(UA_NodeReferenceKind));
+
+    newRef->isInverse = !item->isForward;
+    UA_StatusCode retval = UA_NodeId_copy(&item->referenceTypeId, &newRef->referenceTypeId);
+    retval |= addReferenceTarget(newRef, &item->targetNodeId);
+
+    if(retval == UA_STATUSCODE_GOOD) {
+        node->referencesSize++;
+    } else {
+        UA_NodeId_deleteMembers(&newRef->referenceTypeId);
+        if(node->referencesSize == 0) {
+            UA_free(node->references);
+            node->references = NULL;
+        }
+    }
+    return retval;
+}
+
+UA_StatusCode
+UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item) {
+    for(size_t i = 0; i < node->referencesSize; ++i) {
+        UA_NodeReferenceKind *refs = &node->references[i];
+        if(refs->isInverse == item->isForward)
+            continue;
+        if(!UA_NodeId_equal(&refs->referenceTypeId, &item->referenceTypeId))
+            continue;
+        return addReferenceTarget(refs, &item->targetNodeId);
+    }
+    return addReferenceKind(node, item);
+}
+
+UA_StatusCode
+UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item) {
+    for(size_t i = node->referencesSize; i > 0; --i) {
+        UA_NodeReferenceKind *refs = &node->references[i-1];
+        if(item->isForward == refs->isInverse)
+            continue;
+        if(!UA_NodeId_equal(&item->referenceTypeId, &refs->referenceTypeId))
+            continue;
+
+        for(size_t j = refs->targetIdsSize; j > 0; --j) {
+            if(!UA_NodeId_equal(&item->targetNodeId.nodeId, &refs->targetIds[j-1].nodeId))
+                continue;
+
+            /* Ok, delete the reference */
+            UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j-1]);
+            refs->targetIdsSize--;
+
+            /* One matching target remaining */
+            if(refs->targetIdsSize > 0) {
+                if(j-1 != refs->targetIdsSize) // avoid valgrind error: Source
+                                               // and destination overlap in
+                                               // memcpy
+                    refs->targetIds[j-1] = refs->targetIds[refs->targetIdsSize];
+                return UA_STATUSCODE_GOOD;
+            }
+
+            /* Remove refs */
+            UA_free(refs->targetIds);
+            UA_NodeId_deleteMembers(&refs->referenceTypeId);
+            node->referencesSize--;
+            if(node->referencesSize > 0) {
+                if(i-1 != node->referencesSize) // avoid valgrind error: Source
+                                                // and destination overlap in
+                                                // memcpy
+                    node->references[i-1] = node->references[node->referencesSize];
+                return UA_STATUSCODE_GOOD;
+            }
+
+            /* Remove the node references */
+            UA_free(node->references);
+            node->references = NULL;
+            return UA_STATUSCODE_GOOD;
+        }
+    }
+    return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
+}
+
+void UA_Node_deleteReferences(UA_Node *node) {
+    for(size_t i = 0; i < node->referencesSize; ++i) {
+        UA_NodeReferenceKind *refs = &node->references[i];
+        for(size_t j = 0; j < refs->targetIdsSize; ++j)
+            UA_ExpandedNodeId_deleteMembers(&refs->targetIds[j]);
+        UA_free(refs->targetIds);
+        UA_NodeId_deleteMembers(&refs->referenceTypeId);
+    }
+    if(node->references)
+        UA_free(node->references);
+    node->references = NULL;
+    node->referencesSize = 0;
+}

+ 1 - 8
src/server/ua_nodes.h

@@ -57,13 +57,6 @@ typedef struct {
     UA_ExpandedNodeId *targetIds;
 } UA_NodeReferenceKind;
 
-/* Which constructors were run on the node? */
-typedef enum {
-    UA_NODELIFECYCLE_FRESH,
-    UA_NODELIFECYCLE_CONSTRUCTOR_GLOBAL,
-    UA_NODELIFECYCLE_CONSTRUCTOR_NODETYPE
-} UA_NodeLifecycleState;
-
 #define UA_NODE_BASEATTRIBUTES                  \
     UA_NodeId nodeId;                           \
     UA_NodeClass nodeClass;                     \
@@ -76,7 +69,7 @@ typedef enum {
                                                 \
     /* Members specific to open62541 */         \
     void *context;                              \
-    UA_NodeLifecycleState lifecycleState;
+    UA_Boolean constructed; /* don't run the constructors twice on a node */
 
 typedef struct {
     UA_NODE_BASEATTRIBUTES

+ 2 - 2
src/server/ua_server_binary.c

@@ -475,8 +475,8 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
     /* Find the matching session */
     session = UA_SecureChannel_getSession(channel, &requestHeader->authenticationToken);
     if(!session)
-        session = UA_SessionManager_getSession(&server->sessionManager,
-                                               &requestHeader->authenticationToken);
+        session = UA_SessionManager_getSessionByToken(&server->sessionManager,
+                                                      &requestHeader->authenticationToken);
 
     if(requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST]) {
         if(!session) {

+ 43 - 39
src/server/ua_server_internal.h

@@ -11,6 +11,7 @@ extern "C" {
 
 #include "ua_util.h"
 #include "ua_server.h"
+#include "ua_server_config.h"
 #include "ua_timer.h"
 #include "ua_connection_internal.h"
 #include "ua_session_manager.h"
@@ -60,11 +61,6 @@ struct UA_Worker;
 typedef struct UA_Worker UA_Worker;
 #endif
 
-#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
-/* Internally used context to a session 'context' of the current mehtod call */
-extern UA_THREAD_LOCAL UA_Session* methodCallSession;
-#endif
-
 #ifdef UA_ENABLE_DISCOVERY
 
 typedef struct registeredServer_list_entry {
@@ -110,9 +106,6 @@ struct UA_Server {
     /* Address Space */
     UA_NodeStore *nodestore;
 
-    /* Global Node Lifecycle */
-    UA_NodeLifecycle nodeLifecycle;
-
 #ifdef UA_ENABLE_DISCOVERY
     /* Discovery */
     LIST_HEAD(registeredServer_list, registeredServer_list_entry) registeredServers; // doubly-linked list of registered servers
@@ -170,9 +163,15 @@ struct UA_Server {
 /* Node Handling */
 /*****************/
 
+UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst);
 void UA_Node_deleteMembersAnyNodeClass(UA_Node *node);
+
+UA_StatusCode UA_Node_addReference(UA_Node *node, const UA_AddReferencesItem *item);
+UA_StatusCode UA_Node_deleteReference(UA_Node *node, const UA_DeleteReferencesItem *item);
 void UA_Node_deleteReferences(UA_Node *node);
-UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst);
+
+UA_StatusCode
+UA_Node_createFromAttributes(const UA_AddNodesItem *item, UA_Node **newNode);
 
 /* Calls callback on the node. In the multithreaded case, the node is copied before and replaced in
    the nodestore. */
@@ -219,7 +218,7 @@ isNodeInTree(UA_NodeStore *ns, const UA_NodeId *leafNode,
 /* Returns an array with the hierarchy of type nodes. The returned array starts
  * at the leaf and continues "upwards" in the hierarchy based on the
  * ``hasSubType`` references. Since multiple-inheritance is possible in general,
- * duplicate entries are avoided. */
+ * duplicate entries are removed. */
 UA_StatusCode
 getTypeHierarchy(UA_NodeStore *ns, const UA_NodeId *leafType,
                  UA_NodeId **typeHierarchy, size_t *typeHierarchySize);
@@ -244,7 +243,8 @@ UA_Server_processServiceOperations(UA_Server *server, UA_Session *session,
 /***************************************/
 
 UA_StatusCode
-readValueAttribute(UA_Server *server, const UA_VariableNode *vn, UA_DataValue *v);
+readValueAttribute(UA_Server *server, UA_Session *session,
+                   const UA_VariableNode *vn, UA_DataValue *v);
 
 UA_StatusCode
 typeCheckValue(UA_Server *server, const UA_NodeId *targetDataTypeId,
@@ -266,8 +266,9 @@ compatibleDataType(UA_Server *server, const UA_NodeId *dataType,
                    const UA_NodeId *constraintDataType);
 
 UA_StatusCode
-writeValueRankAttribute(UA_Server *server, UA_VariableNode *node,
-                        UA_Int32 valueRank, UA_Int32 constraintValueRank);
+writeValueRankAttribute(UA_Server *server, UA_Session *session,
+                        UA_VariableNode *node, UA_Int32 valueRank,
+                        UA_Int32 constraintValueRank);
 
 UA_StatusCode
 compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank);
@@ -341,7 +342,7 @@ __UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
                           const UA_QualifiedName *browseName,
                           const UA_NodeAttributes *attr,
                           const UA_DataType *attributeType,
-                          UA_NodeId *outNewNodeId);
+                          void *nodeContext, UA_NodeId *outNewNodeId);
 
 /* The inline function UA_Server_addNode_finish might be more convenient to
  * pass NodeIds in-situ (e.g. UA_NODEID_NUMERIC(0, 5)) */
@@ -349,19 +350,18 @@ UA_StatusCode UA_EXPORT
 UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
                          const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId,
-                         const UA_NodeId typeDefinition,
-                         void *nodeContext);
+                         const UA_NodeId typeDefinition);
 
 static UA_INLINE UA_StatusCode
 UA_Server_addReferenceTypeNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                      const UA_QualifiedName browseName,
                                      const UA_ReferenceTypeAttributes attr,
-                                     UA_NodeId *outNewNodeId) {
+                                     void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,
                                      &requestedNewNodeId,
                                      &browseName, (const UA_NodeAttributes*)&attr,
                                      &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
-                                     outNewNodeId);
+                                     nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -369,48 +369,48 @@ UA_Server_addDataTypeNode_begin(UA_Server *server,
                                 const UA_NodeId requestedNewNodeId,
                                 const UA_QualifiedName browseName,
                                 const UA_DataTypeAttributes attr,
-                                UA_NodeId *outNewNodeId) {
+                                void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,
                                      &requestedNewNodeId,
                                      &browseName, (const UA_NodeAttributes*)&attr,
                                      &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
-                                     outNewNodeId);
+                                     nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                 const UA_QualifiedName browseName,
                                 const UA_VariableAttributes attr,
-                                UA_NodeId *outNewNodeId) {
+                                void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,
                                      &requestedNewNodeId, &browseName,
                                      (const UA_NodeAttributes*)&attr,
                                      &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
-                                     outNewNodeId);
+                                     nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addVariableTypeNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                     const UA_QualifiedName browseName,
                                     const UA_VariableTypeAttributes attr,
-                                    UA_NodeId *outNewNodeId) {
+                                    void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,
                                      &requestedNewNodeId, &browseName,
                                      (const UA_NodeAttributes*)&attr,
                                      &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
-                                     outNewNodeId);
+                                     nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
 UA_Server_addObjectNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_QualifiedName browseName,
                               const UA_ObjectAttributes attr,
-                              UA_NodeId *outNewNodeId) {
+                              void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,
                                      &requestedNewNodeId,
                                      &browseName, (const UA_NodeAttributes*)&attr,
                                      &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
-                                     outNewNodeId);
+                                     nodeContext, outNewNodeId);
 }
 
 static UA_INLINE UA_StatusCode
@@ -418,30 +418,34 @@ UA_Server_addObjectTypeNode_begin(UA_Server *server,
                                   const UA_NodeId requestedNewNodeId,
                                   const UA_QualifiedName browseName,
                                   const UA_ObjectTypeAttributes attr,
-                                  UA_NodeId *outNewNodeId) {
+                                  void *nodeContext, UA_NodeId *outNewNodeId) {
     return __UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,
                                      &requestedNewNodeId,
                                      &browseName, (const UA_NodeAttributes*)&attr,
                                      &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
-                                     outNewNodeId);
+                                     nodeContext, outNewNodeId);
 }
 
-#ifdef UA_ENABLE_METHODCALLS
-UA_StatusCode
+static UA_INLINE UA_StatusCode
 UA_Server_addMethodNode_begin(UA_Server *server, const UA_NodeId requestedNewNodeId,
                               const UA_QualifiedName browseName,
-                              const UA_MethodAttributes attr, UA_MethodCallback method,
-                              UA_NodeId *outNewNodeId);
+                              const UA_MethodAttributes attr,
+                              void *nodeContext, UA_NodeId *outNewNodeId) {
+    return __UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,
+                                     &requestedNewNodeId,
+                                     &browseName, (const UA_NodeAttributes*)&attr,
+                                     &UA_TYPES[UA_TYPES_METHODATTRIBUTES],
+                                     nodeContext, outNewNodeId);
+}
+
+#ifdef UA_ENABLE_METHODCALLS
 
 UA_StatusCode
 UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
-                               const UA_NodeId parentNodeId,
-                               const UA_NodeId referenceTypeId,
-                               size_t inputArgumentsSize,
-                               const UA_Argument* inputArguments,
-                               size_t outputArgumentsSize,
-                               const UA_Argument* outputArguments,
-                               void *nodeContext);
+                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                               UA_MethodCallback method, 
+                               size_t inputArgumentsSize, const UA_Argument* inputArguments,
+                               size_t outputArgumentsSize, const UA_Argument* outputArguments);
 #endif
 
 /**********************/

+ 54 - 53
src/server/ua_server_ns0.c

@@ -12,10 +12,6 @@
 #include "ua_subscription.h"
 #endif
 
-#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
-UA_THREAD_LOCAL UA_Session* methodCallSession = NULL;
-#endif
-
 #ifndef UA_ENABLE_GENERATE_NAMESPACE0
 
 /****************/
@@ -23,8 +19,9 @@ UA_THREAD_LOCAL UA_Session* methodCallSession = NULL;
 /****************/
 
 static UA_StatusCode
-readStatus(const UA_NodeId *nodeid, void *nodeContext,
-           UA_Boolean sourceTimestamp,
+readStatus(UA_Server *server, const UA_NodeId *sessionId,
+           void *sessionContext, const UA_NodeId *nodeId,
+           void *nodeContext, UA_Boolean sourceTimestamp,
            const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = true;
@@ -32,7 +29,6 @@ readStatus(const UA_NodeId *nodeid, void *nodeContext,
         return UA_STATUSCODE_GOOD;
     }
 
-    UA_Server *server = (UA_Server*)nodeContext;
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
     status->startTime = server->startTime;
     status->currentTime = UA_DateTime_now();
@@ -54,22 +50,23 @@ readStatus(const UA_NodeId *nodeid, void *nodeContext,
 }
 
 static UA_StatusCode
-readNamespaces(const UA_NodeId *nodeid, void *nodeContext,
-               UA_Boolean sourceTimestamp,
-               const UA_NumericRange *range, UA_DataValue *value) {
+readNamespaces(UA_Server *server, const UA_NodeId *sessionId,
+               void *sessionContext, const UA_NodeId *nodeid,
+               void *nodeContext, UA_Boolean includeSourceTimeStamp,
+               const UA_NumericRange *range,
+               UA_DataValue *value) {
     if(range) {
         value->hasStatus = true;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_GOOD;
     }
-    UA_Server *server = (UA_Server*)nodeContext;
     UA_StatusCode retval;
     retval = UA_Variant_setArrayCopy(&value->value, server->namespaces,
                                      server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     value->hasValue = true;
-    if(sourceTimestamp) {
+    if(includeSourceTimeStamp) {
         value->hasSourceTimestamp = true;
         value->sourceTimestamp = UA_DateTime_now();
     }
@@ -77,24 +74,25 @@ readNamespaces(const UA_NodeId *nodeid, void *nodeContext,
 }
 
 static UA_StatusCode
-writeNamespaces(const UA_NodeId *nodeid, void *nodeContext,
-                const UA_Variant *data, const UA_NumericRange *range) {
-    UA_Server *server = (UA_Server*)nodeContext;
-
+writeNamespaces(UA_Server *server, const UA_NodeId *sessionId,
+                void *sessionContext, const UA_NodeId *nodeid,
+                void *nodeContext, const UA_NumericRange *range,
+                const UA_DataValue *value) {
     /* Check the data type */
-    if(data->type != &UA_TYPES[UA_TYPES_STRING])
+    if(!value->hasValue ||
+       value->value.type != &UA_TYPES[UA_TYPES_STRING])
         return UA_STATUSCODE_BADTYPEMISMATCH;
 
     /* Check that the variant is not empty */
-    if(!data->data)
+    if(!value->value.data)
         return UA_STATUSCODE_BADTYPEMISMATCH;
 
     /* TODO: Writing with a range is not implemented */
     if(range)
         return UA_STATUSCODE_BADINTERNALERROR;
 
-    UA_String *newNamespaces = (UA_String*)data->data;
-    size_t newNamespacesSize = data->arrayLength;
+    UA_String *newNamespaces = (UA_String*)value->value.data;
+    size_t newNamespacesSize = value->value.arrayLength;
 
     /* Test if we append to the existing namespaces */
     if(newNamespacesSize <= server->namespacesSize)
@@ -113,8 +111,9 @@ writeNamespaces(const UA_NodeId *nodeid, void *nodeContext,
 }
 
 static UA_StatusCode
-readCurrentTime(const UA_NodeId *nodeid, void *nodeContext,
-                UA_Boolean sourceTimeStamp,
+readCurrentTime(UA_Server *server, const UA_NodeId *sessionId,
+                void *sessionContext, const UA_NodeId *nodeid,
+                void *nodeContext, UA_Boolean sourceTimeStamp,
                 const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = true;
@@ -136,13 +135,16 @@ readCurrentTime(const UA_NodeId *nodeid, void *nodeContext,
 
 #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
 static UA_StatusCode
-readMonitoredItems(const UA_NodeId *methodId, void *methodContext,
-                   const UA_NodeId *objectId, void *objectContext,
-                   const UA_NodeId *sessionId, void *sessionHandle,
-                   size_t inputSize, const UA_Variant *input,
-                   size_t outputSize, UA_Variant *output) {
+readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId,
+                   void *sessionContext, const UA_NodeId *methodId,
+                   void *methodContext, const UA_NodeId *objectId,
+                   void *objectContext, size_t inputSize,
+                   const UA_Variant *input, size_t outputSize,
+                   UA_Variant *output) {
+    UA_Session *session = UA_SessionManager_getSessionById(&server->sessionManager, sessionId);
+    if(!session)
+        return UA_STATUSCODE_BADINTERNALERROR;
     UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data));
-    UA_Session* session = methodCallSession;
     UA_Subscription* subscription = UA_Session_getSubscriptionByID(session, subscriptionId);
     if(!subscription)
         return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
@@ -267,15 +269,15 @@ addVariableNode(UA_Server *server, UA_UInt32 nodeid, char* name, UA_Int32 valueR
 
 static void
 addDataSourceVariableNode(UA_Server *server, UA_UInt32 nodeid, char* name, UA_Int32 valueRank,
-                const UA_NodeId *dataType, UA_DataSource *dataSource, UA_UInt32 parentid,
-                UA_UInt32 referenceid, UA_UInt32 type_id) {
+                          const UA_NodeId *dataType, UA_DataSource *dataSource, void *nodeContext,
+                          UA_UInt32 parentid,UA_UInt32 referenceid, UA_UInt32 type_id) {
     UA_VariableAttributes attr = UA_VariableAttributes_default;
     attr.displayName = UA_LOCALIZEDTEXT("en_US", name);
     attr.valueRank = valueRank;
     attr.dataType = *dataType;
     UA_Server_addDataSourceVariableNode(server, UA_NODEID_NUMERIC(0, nodeid), UA_NODEID_NUMERIC(0, parentid),
                                         UA_NODEID_NUMERIC(0, referenceid), UA_QUALIFIEDNAME(0, name),
-                                        UA_NODEID_NUMERIC(0, type_id), attr, *dataSource, NULL);
+                                        UA_NODEID_NUMERIC(0, type_id), attr, *dataSource, nodeContext, NULL);
 }
 
 /**********************/
@@ -295,7 +297,7 @@ void UA_Server_createNS0(UA_Server *server) {
     references_attr.symmetric = true;
     references_attr.inverseName = UA_LOCALIZEDTEXT("en_US", "References");
     UA_Server_addReferenceTypeNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCES),
-                                         UA_QUALIFIEDNAME(0, "References"), references_attr, NULL);
+                                         UA_QUALIFIEDNAME(0, "References"), references_attr, NULL, NULL);
 
     UA_ReferenceTypeAttributes hassubtype_attr = UA_ReferenceTypeAttributes_default;
     hassubtype_attr.displayName = UA_LOCALIZEDTEXT("en_US", "HasSubtype");
@@ -303,7 +305,7 @@ void UA_Server_createNS0(UA_Server *server) {
     hassubtype_attr.symmetric = false;
     hassubtype_attr.inverseName = UA_LOCALIZEDTEXT("en_US", "SubtypeOf");
     UA_Server_addReferenceTypeNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                                         UA_QUALIFIEDNAME(0, "HasSubtype"), hassubtype_attr, NULL);
+                                         UA_QUALIFIEDNAME(0, "HasSubtype"), hassubtype_attr, NULL, NULL);
 
     addReferenceTypeNode(server, "HierarchicalReferences", NULL,
                          UA_NS0ID_HIERARCHICALREFERENCES,
@@ -365,7 +367,7 @@ void UA_Server_createNS0(UA_Server *server) {
     basedatatype_attr.displayName = UA_LOCALIZEDTEXT("en_US", "BaseDataType");
     basedatatype_attr.isAbstract = true;
     UA_Server_addDataTypeNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE),
-                                    UA_QUALIFIEDNAME(0, "BaseDataType"), basedatatype_attr, NULL);
+                                    UA_QUALIFIEDNAME(0, "BaseDataType"), basedatatype_attr, NULL, NULL);
 
     addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, false, UA_NS0ID_BASEDATATYPE);
     addDataTypeNode(server, "Number", UA_NS0ID_NUMBER, true, UA_NS0ID_BASEDATATYPE);
@@ -411,7 +413,7 @@ void UA_Server_createNS0(UA_Server *server) {
     basevar_attr.valueRank = -2;
     basevar_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
     UA_Server_addVariableTypeNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE),
-                                        UA_QUALIFIEDNAME(0, "BaseVariableType"), basevar_attr, NULL);
+                                        UA_QUALIFIEDNAME(0, "BaseVariableType"), basevar_attr, NULL, NULL);
 
     addVariableTypeNode(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
                         false, -2, UA_NS0ID_BASEDATATYPE, NULL, UA_NS0ID_BASEVARIABLETYPE);
@@ -435,7 +437,7 @@ void UA_Server_createNS0(UA_Server *server) {
     UA_ObjectTypeAttributes baseobj_attr = UA_ObjectTypeAttributes_default;
     baseobj_attr.displayName = UA_LOCALIZEDTEXT("en_US", "BaseObjectType");
     UA_Server_addObjectTypeNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
-                                      UA_QUALIFIEDNAME(0, "BaseObjectType"), baseobj_attr, NULL);
+                                      UA_QUALIFIEDNAME(0, "BaseObjectType"), baseobj_attr, NULL, NULL);
 
     addObjectTypeNode(server, "ModellingRuleType", UA_NS0ID_MODELLINGRULETYPE,
                       false, UA_NS0ID_BASEOBJECTTYPE);
@@ -459,7 +461,7 @@ void UA_Server_createNS0(UA_Server *server) {
     UA_ObjectAttributes root_attr = UA_ObjectAttributes_default;
     root_attr.displayName = UA_LOCALIZEDTEXT("en_US", "Root");
     UA_Server_addObjectNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER),
-                                  UA_QUALIFIEDNAME(0, "Root"), root_attr, NULL);
+                                  UA_QUALIFIEDNAME(0, "Root"), root_attr, NULL, NULL);
     addReferenceInternal(server, UA_NS0ID_ROOTFOLDER, UA_NS0ID_HASTYPEDEFINITION,
                          UA_NS0ID_FOLDERTYPE, true);
 
@@ -516,7 +518,7 @@ void UA_Server_createNS0(UA_Server *server) {
     UA_ObjectAttributes server_attr = UA_ObjectAttributes_default;
     server_attr.displayName = UA_LOCALIZEDTEXT("en_US", "Server");
     UA_Server_addObjectNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                                  UA_QUALIFIEDNAME(0, "Server"), server_attr, NULL);
+                                  UA_QUALIFIEDNAME(0, "Server"), server_attr, NULL, NULL);
 
     /* ServerArray */
     UA_Variant_setArray(&var, &server->config.applicationDescription.applicationUri,
@@ -533,20 +535,20 @@ void UA_Server_createNS0(UA_Server *server) {
     nsarray_attr.dataType = UA_TYPES[UA_TYPES_STRING].typeId;
     nsarray_attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
     UA_Server_addVariableNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
-                                    UA_QUALIFIEDNAME(0, "NamespaceArray"), nsarray_attr, NULL);
+                                    UA_QUALIFIEDNAME(0, "NamespaceArray"), nsarray_attr, NULL, NULL);
     UA_DataSource nsarray_datasource =  {readNamespaces, writeNamespaces};
     UA_Server_setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                                          nsarray_datasource);
     UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
-                             UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), server /* context for datasource*/);
+                             UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE));
 
     /* Begin ServerCapabilities */
     UA_ObjectAttributes servercap_attr = UA_ObjectAttributes_default;
     servercap_attr.displayName = UA_LOCALIZEDTEXT("en_US", "ServerCapabilities");
     UA_Server_addObjectNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
-                                  UA_QUALIFIEDNAME(0, "ServerCapabilities"), servercap_attr, NULL);
+                                  UA_QUALIFIEDNAME(0, "ServerCapabilities"), servercap_attr, NULL, NULL);
     
     UA_String enLocale = UA_STRING("en");
     UA_Variant_setArray(&var, &enLocale, 1, &UA_TYPES[UA_TYPES_STRING]);
@@ -615,13 +617,13 @@ void UA_Server_createNS0(UA_Server *server) {
     UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                             UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE), NULL);
+                             UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE));
 
     /* Begin ServerDiagnostics */
     UA_ObjectAttributes serverdiag_attr = UA_ObjectAttributes_default;
     serverdiag_attr.displayName = UA_LOCALIZEDTEXT("en_US", "ServerDiagnostics");
     UA_Server_addObjectNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
-                                  UA_QUALIFIEDNAME(0, "ServerDiagnostics"), serverdiag_attr, NULL);
+                                  UA_QUALIFIEDNAME(0, "ServerDiagnostics"), serverdiag_attr, NULL, NULL);
     
     UA_Boolean enabledFlag = false;
     UA_Variant_setScalar(&var, &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]);
@@ -633,11 +635,11 @@ void UA_Server_createNS0(UA_Server *server) {
     UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                             UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE), NULL);
+                             UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE));
 
-    UA_DataSource statusDS = {server, readStatus, NULL};
+    UA_DataSource statusDS = {readStatus, NULL};
     addDataSourceVariableNode(server, UA_NS0ID_SERVER_SERVERSTATUS, "ServerStatus", -1,
-                              &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE].typeId, &statusDS,
+                              &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE].typeId, &statusDS, server,
                               UA_NS0ID_SERVER, UA_NS0ID_HASCOMPONENT, UA_NS0ID_BASEDATAVARIABLETYPE);
 
     UA_Variant_setScalar(&var, &server->startTime, &UA_TYPES[UA_TYPES_DATETIME]);
@@ -645,9 +647,9 @@ void UA_Server_createNS0(UA_Server *server) {
                     &UA_TYPES[UA_TYPES_DATETIME].typeId, &var, UA_NS0ID_SERVER_SERVERSTATUS,
                     UA_NS0ID_HASCOMPONENT, UA_NS0ID_BASEDATAVARIABLETYPE);
 
-    UA_DataSource currentDS = {NULL, readCurrentTime, NULL};
+    UA_DataSource currentDS = {readCurrentTime, NULL};
     addDataSourceVariableNode(server, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME, "CurrentTime", -1,
-                              &UA_TYPES[UA_TYPES_DATETIME].typeId, &currentDS,
+                              &UA_TYPES[UA_TYPES_DATETIME].typeId, &currentDS, NULL,
                               UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                               UA_NS0ID_BASEDATAVARIABLETYPE);
 
@@ -742,9 +744,7 @@ void UA_Server_createNS0(UA_Server *server) {
     addmethodattributes.userExecutable = true;
     UA_Server_addMethodNode_begin(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS),
                                   UA_QUALIFIEDNAME(0, "GetMonitoredItems"),
-                                  addmethodattributes,
-                                  readMonitoredItems, /* callback of the method node */
-                                  NULL);
+                                  addmethodattributes, NULL, NULL);
 
     /* Add the arguments manually to get the nodeids right */
     UA_Argument inputArguments;
@@ -777,14 +777,15 @@ void UA_Server_createNS0(UA_Server *server) {
     UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                                   0, NULL, 0, NULL, NULL);
+                                   readMonitoredItems, /* callback of the method node */
+                                   0, NULL, 0, NULL);
 #endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */
 
     /* Finish adding the server object */
     UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
-                             UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE), NULL);
+                             UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE));
 }
 
 #endif /* UA_ENABLE_GENERATE_NAMESPACE0 */

+ 55 - 51
src/server/ua_services_attribute.c

@@ -24,9 +24,8 @@ getUserWriteMask(UA_Server *server, const UA_Session *session,
     if(session == &adminSession)
         return 0xFFFFFFFF; /* the local admin user has all rights */
     return node->writeMask &
-        server->config.accessControl.getUserRightsMask(&session->sessionId,
-                                                       session->sessionHandle,
-                                                       &node->nodeId);
+        server->config.accessControl.getUserRightsMask(&session->sessionId, session->sessionHandle,
+                                                       &node->nodeId, node->context);
 }
 
 static UA_Byte
@@ -35,9 +34,8 @@ getUserAccessLevel(UA_Server *server, const UA_Session *session,
     if(session == &adminSession)
         return 0xFF; /* the local admin user has all rights */
     return node->accessLevel &
-        server->config.accessControl.getUserAccessLevel(&session->sessionId,
-                                                        session->sessionHandle,
-                                                        &node->nodeId);
+        server->config.accessControl.getUserAccessLevel(&session->sessionId, session->sessionHandle,
+                                                        &node->nodeId, node->context);
 }
 
 static UA_Boolean
@@ -46,9 +44,8 @@ getUserExecutable(UA_Server *server, const UA_Session *session,
     if(session == &adminSession)
         return true; /* the local admin user has all rights */
     return node->executable &
-        server->config.accessControl.getUserExecutable(&session->sessionId,
-                                                       session->sessionHandle,
-                                                       &node->nodeId);
+        server->config.accessControl.getUserExecutable(&session->sessionId, session->sessionHandle,
+                                                       &node->nodeId, node->context);
 }
 
 /*****************/
@@ -297,8 +294,8 @@ readArrayDimensionsAttribute(const UA_VariableNode *vn, UA_DataValue *v) {
 }
 
 static UA_StatusCode
-writeArrayDimensionsAttribute(UA_Server *server, UA_VariableNode *node,
-                              size_t arrayDimensionsSize,
+writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session,
+                              UA_VariableNode *node, size_t arrayDimensionsSize,
                               UA_UInt32 *arrayDimensions) {
     /* If this is a variabletype, there must be no instances or subtypes of it
      * when we do the change */
@@ -335,7 +332,7 @@ writeArrayDimensionsAttribute(UA_Server *server, UA_VariableNode *node,
     /* Check if the current value is compatible with the array dimensions */
     UA_DataValue value;
     UA_DataValue_init(&value);
-    retval = readValueAttribute(server, node, &value);
+    retval = readValueAttribute(server, session, node, &value);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     if(value.hasValue) {
@@ -367,17 +364,19 @@ writeArrayDimensionsAttribute(UA_Server *server, UA_VariableNode *node,
 /***********************/
 
 static UA_StatusCode
-writeValueRankAttributeWithVT(UA_Server *server, UA_VariableNode *node,
-                              UA_Int32 valueRank) {
+writeValueRankAttributeWithVT(UA_Server *server, UA_Session *session,
+                              UA_VariableNode *node, UA_Int32 valueRank) {
     const UA_VariableTypeNode *vt = getVariableNodeType(server, node);
     if(!vt)
         return UA_STATUSCODE_BADINTERNALERROR;
-    return writeValueRankAttribute(server, node, valueRank, vt->valueRank);
+    return writeValueRankAttribute(server, session, node,
+                                   valueRank, vt->valueRank);
 }
 
 UA_StatusCode
-writeValueRankAttribute(UA_Server *server, UA_VariableNode *node,
-                        UA_Int32 valueRank, UA_Int32 constraintValueRank) {
+writeValueRankAttribute(UA_Server *server, UA_Session *session,
+                        UA_VariableNode *node, UA_Int32 valueRank,
+                        UA_Int32 constraintValueRank) {
     /* If this is a variabletype, there must be no instances or subtypes of it
        when we do the change */
     if(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
@@ -397,7 +396,7 @@ writeValueRankAttribute(UA_Server *server, UA_VariableNode *node,
            dimensions zero indicate a scalar for compatibleValueRankArrayDimensions. */
         UA_DataValue value;
         UA_DataValue_init(&value);
-        retval = readValueAttribute(server, node, &value);
+        retval = readValueAttribute(server, session, node, &value);
         if(retval != UA_STATUSCODE_GOOD)
             return retval;
         if(!value.hasValue || !value.value.type) {
@@ -423,8 +422,8 @@ writeValueRankAttribute(UA_Server *server, UA_VariableNode *node,
 /**********************/
 
 static UA_StatusCode
-writeDataTypeAttribute(UA_Server *server, UA_VariableNode *node,
-                       const UA_NodeId *dataType,
+writeDataTypeAttribute(UA_Server *server, UA_Session *session,
+                       UA_VariableNode *node, const UA_NodeId *dataType,
                        const UA_NodeId *constraintDataType) {
     /* If this is a variabletype, there must be no instances or subtypes of it
        when we do the change */
@@ -439,7 +438,7 @@ writeDataTypeAttribute(UA_Server *server, UA_VariableNode *node,
     /* Check if the current value would match the new type */
     UA_DataValue value;
     UA_DataValue_init(&value);
-    UA_StatusCode retval = readValueAttribute(server, node, &value);
+    UA_StatusCode retval = readValueAttribute(server, session, node, &value);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     if(value.hasValue) {
@@ -466,12 +465,12 @@ writeDataTypeAttribute(UA_Server *server, UA_VariableNode *node,
 }
 
 static UA_StatusCode
-writeDataTypeAttributeWithVT(UA_Server *server, UA_VariableNode *node,
-                             const UA_NodeId *dataType) {
+writeDataTypeAttributeWithVT(UA_Server *server, UA_Session *session,
+                             UA_VariableNode *node, const UA_NodeId *dataType) {
     const UA_VariableTypeNode *vt = getVariableNodeType(server, node);
     if(!vt)
         return UA_STATUSCODE_BADINTERNALERROR;
-    return writeDataTypeAttribute(server, node, dataType, &vt->dataType);
+    return writeDataTypeAttribute(server, session, node, dataType, &vt->dataType);
 }
 
 /*******************/
@@ -479,12 +478,14 @@ writeDataTypeAttributeWithVT(UA_Server *server, UA_VariableNode *node,
 /*******************/
 
 static UA_StatusCode
-readValueAttributeFromNode(UA_Server *server, const UA_VariableNode *vn,
-                           UA_DataValue *v, UA_NumericRange *rangeptr) {
+readValueAttributeFromNode(UA_Server *server, UA_Session *session,
+                           const UA_VariableNode *vn, UA_DataValue *v,
+                           UA_NumericRange *rangeptr) {
     if(vn->value.data.callback.onRead) {
         UA_RCU_UNLOCK();
-        vn->value.data.callback.onRead(&vn->nodeId, vn->context,
-                                       &vn->value.data.value.value, rangeptr);
+        vn->value.data.callback.onRead(server, &session->sessionId,
+                                       session->sessionHandle, &vn->nodeId,
+                                       vn->context, rangeptr, &vn->value.data.value);
         UA_RCU_LOCK();
 #ifdef UA_ENABLE_MULTITHREADING
         /* Reopen the node to see the changes (multithreading only) */
@@ -499,7 +500,8 @@ readValueAttributeFromNode(UA_Server *server, const UA_VariableNode *vn,
 }
 
 static UA_StatusCode
-readValueAttributeFromDataSource(const UA_VariableNode *vn, UA_DataValue *v,
+readValueAttributeFromDataSource(UA_Server *server, UA_Session *session,
+                                 const UA_VariableNode *vn, UA_DataValue *v,
                                  UA_TimestampsToReturn timestamps,
                                  UA_NumericRange *rangeptr) {
     if(!vn->value.dataSource.read)
@@ -508,17 +510,16 @@ readValueAttributeFromDataSource(const UA_VariableNode *vn, UA_DataValue *v,
                                   timestamps == UA_TIMESTAMPSTORETURN_BOTH);
     UA_RCU_UNLOCK();
     UA_StatusCode retval =
-        vn->value.dataSource.read(&vn->nodeId, vn->context,
-                                  sourceTimeStamp, rangeptr, v);
+        vn->value.dataSource.read(server, &session->sessionId, session->sessionHandle,
+                                  &vn->nodeId, vn->context, sourceTimeStamp, rangeptr, v);
     UA_RCU_LOCK();
     return retval;
 }
 
 static UA_StatusCode
-readValueAttributeComplete(UA_Server *server, const UA_VariableNode *vn,
-                           UA_TimestampsToReturn timestamps,
-                           const UA_String *indexRange,
-                           UA_DataValue *v) {
+readValueAttributeComplete(UA_Server *server, UA_Session *session,
+                           const UA_VariableNode *vn, UA_TimestampsToReturn timestamps,
+                           const UA_String *indexRange, UA_DataValue *v) {
     /* Compute the index range */
     UA_NumericRange range;
     UA_NumericRange *rangeptr = NULL;
@@ -532,9 +533,9 @@ readValueAttributeComplete(UA_Server *server, const UA_VariableNode *vn,
 
     /* Read the value */
     if(vn->valueSource == UA_VALUESOURCE_DATA)
-        retval = readValueAttributeFromNode(server, vn, v, rangeptr);
+        retval = readValueAttributeFromNode(server, session, vn, v, rangeptr);
     else
-        retval = readValueAttributeFromDataSource(vn, v, timestamps, rangeptr);
+        retval = readValueAttributeFromDataSource(server, session, vn, v, timestamps, rangeptr);
 
     /* Clean up */
     if(rangeptr)
@@ -543,10 +544,10 @@ readValueAttributeComplete(UA_Server *server, const UA_VariableNode *vn,
 }
 
 UA_StatusCode
-readValueAttribute(UA_Server *server, const UA_VariableNode *vn,
-                   UA_DataValue *v) {
-    return readValueAttributeComplete(server, vn, UA_TIMESTAMPSTORETURN_NEITHER,
-                                      NULL, v);
+readValueAttribute(UA_Server *server, UA_Session *session,
+                   const UA_VariableNode *vn, UA_DataValue *v) {
+    return readValueAttributeComplete(server, session, vn,
+                                      UA_TIMESTAMPSTORETURN_NEITHER, NULL, v);
 }
 
 static UA_StatusCode
@@ -594,7 +595,7 @@ writeValueAttributeWithRange(UA_VariableNode *node, const UA_DataValue *value,
 }
 
 static UA_StatusCode
-writeValueAttribute(UA_Server *server, UA_VariableNode *node,
+writeValueAttribute(UA_Server *server, UA_Session *session, UA_VariableNode *node,
                     const UA_DataValue *value, const UA_String *indexRange) {
     /* Parse the range */
     UA_NumericRange range;
@@ -649,15 +650,18 @@ writeValueAttribute(UA_Server *server, UA_VariableNode *node,
                                    change with the nodestore plugin approach) */
 #endif
             UA_RCU_UNLOCK();
-            writtenNode->value.data.callback.onWrite(&writtenNode->nodeId, writtenNode->context,
-                                                     &writtenNode->value.data.value.value, rangeptr);
+            writtenNode->value.data.callback.onWrite(server, &session->sessionId,
+                                                     session->sessionHandle, &writtenNode->nodeId,
+                                                     writtenNode->context, rangeptr,
+                                                     &writtenNode->value.data.value);
             UA_RCU_LOCK();
         }
     } else {
         if(node->value.dataSource.write) {
             UA_RCU_UNLOCK();
-            retval = node->value.dataSource.write(&node->nodeId, node->context,
-                                                  &editableValue.value, rangeptr);
+            retval = node->value.dataSource.write(server, &session->sessionId,
+                                                  session->sessionHandle, &node->nodeId,
+                                                  node->context, rangeptr, &editableValue);
             UA_RCU_LOCK();
         } else {
             retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
@@ -819,7 +823,7 @@ Operation_Read(UA_Server *server, UA_Session *session,
             retval = UA_STATUSCODE_BADUSERACCESSDENIED;
             break;
         }
-        retval = readValueAttributeComplete(server, (const UA_VariableNode*)node,
+        retval = readValueAttributeComplete(server, session, (const UA_VariableNode*)node,
                                             op_timestampsToReturn, &id->indexRange, v);
         break;
     }
@@ -1153,28 +1157,28 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session,
         } else { /* UA_NODECLASS_VARIABLETYPE */
             CHECK_USERWRITEMASK(UA_WRITEMASK_VALUEFORVARIABLETYPE);
         }
-        retval = writeValueAttribute(server, (UA_VariableNode*)node,
+        retval = writeValueAttribute(server, session, (UA_VariableNode*)node,
                                      &wvalue->value, &wvalue->indexRange);
         break;
     case UA_ATTRIBUTEID_DATATYPE:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_USERWRITEMASK(UA_WRITEMASK_DATATYPE);
         CHECK_DATATYPE_SCALAR(NODEID);
-        retval = writeDataTypeAttributeWithVT(server, (UA_VariableNode*)node,
+        retval = writeDataTypeAttributeWithVT(server, session, (UA_VariableNode*)node,
                                               (const UA_NodeId*)value);
         break;
     case UA_ATTRIBUTEID_VALUERANK:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_USERWRITEMASK(UA_WRITEMASK_VALUERANK);
         CHECK_DATATYPE_SCALAR(INT32);
-        retval = writeValueRankAttributeWithVT(server, (UA_VariableNode*)node,
+        retval = writeValueRankAttributeWithVT(server, session, (UA_VariableNode*)node,
                                                *(const UA_Int32*)value);
         break;
     case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
         CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
         CHECK_USERWRITEMASK(UA_WRITEMASK_ARRRAYDIMENSIONS);
         CHECK_DATATYPE_ARRAY(UINT32);
-        retval = writeArrayDimensionsAttribute(server, (UA_VariableNode*)node,
+        retval = writeArrayDimensionsAttribute(server, session, (UA_VariableNode*)node,
                                                wvalue->value.value.arrayLength,
                                                (UA_UInt32 *)wvalue->value.value.data);
         break;

+ 4 - 10
src/server/ua_services_call.c

@@ -91,7 +91,8 @@ Operation_CallMethod(UA_Server *server, UA_Session *session,
     if(session != &adminSession)
         executable = executable &&
             server->config.accessControl.getUserExecutableOnObject(&session->sessionId,
-                                 session->sessionHandle, &request->objectId, &request->methodId);
+                           session->sessionHandle, &request->methodId, methodCalled->context,
+                           &request->objectId, object->context);
     if(!executable) {
         result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
         return;
@@ -153,19 +154,12 @@ Operation_CallMethod(UA_Server *server, UA_Session *session,
     }
 
     /* Call the method */
-#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
-    methodCallSession = session;
-#endif
     result->statusCode =
-        methodCalled->method(&methodCalled->nodeId, (void*)(uintptr_t)methodCalled->context,
+        methodCalled->method(server, &session->sessionId, session->sessionHandle,
+                             &methodCalled->nodeId, (void*)(uintptr_t)methodCalled->context,
                              &object->nodeId, (void*)(uintptr_t)&object->context,
-                             &session->sessionId, session->sessionHandle,
                              request->inputArgumentsSize, request->inputArguments,
                              result->outputArgumentsSize, result->outputArguments);
-#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
-    methodCallSession = NULL;
-#endif
-
     /* TODO: Verify Output matches the argument definition */
 }
 

File diff suppressed because it is too large
+ 531 - 816
src/server/ua_services_nodemanagement.c


+ 27 - 1
src/server/ua_session_manager.c

@@ -68,7 +68,7 @@ UA_SessionManager_cleanupTimedOut(UA_SessionManager *sm,
 }
 
 UA_Session *
-UA_SessionManager_getSession(UA_SessionManager *sm, const UA_NodeId *token) {
+UA_SessionManager_getSessionByToken(UA_SessionManager *sm, const UA_NodeId *token) {
     session_list_entry *current = NULL;
     LIST_FOREACH(current, &sm->sessions, pointers) {
         /* Token does not match */
@@ -93,6 +93,32 @@ UA_SessionManager_getSession(UA_SessionManager *sm, const UA_NodeId *token) {
     return NULL;
 }
 
+UA_Session *
+UA_SessionManager_getSessionById(UA_SessionManager *sm, const UA_NodeId *sessionId) {
+    session_list_entry *current = NULL;
+    LIST_FOREACH(current, &sm->sessions, pointers) {
+        /* Token does not match */
+        if(!UA_NodeId_equal(&current->session.sessionId, sessionId))
+            continue;
+
+        /* Session has timed out */
+        if(UA_DateTime_nowMonotonic() > current->session.validTill) {
+            UA_LOG_INFO_SESSION(sm->server->config.logger, &current->session,
+                                "Client tries to use a session that has timed out");
+            return NULL;
+        }
+
+        /* Ok, return */
+        return &current->session;
+    }
+
+    /* Session not found */
+    UA_LOG_INFO(sm->server->config.logger, UA_LOGCATEGORY_SESSION,
+                "Try to use Session with identifier " UA_PRINTF_GUID_FORMAT " but is not found",
+                UA_PRINTF_GUID_DATA(sessionId->identifier.guid));
+    return NULL;
+}
+
 /* Creates and adds a session. But it is not yet attached to a secure channel. */
 UA_StatusCode
 UA_SessionManager_createSession(UA_SessionManager *sm, UA_SecureChannel *channel,

+ 4 - 1
src/server/ua_session_manager.h

@@ -45,7 +45,10 @@ UA_StatusCode
 UA_SessionManager_removeSession(UA_SessionManager *sm, const UA_NodeId *token);
 
 UA_Session *
-UA_SessionManager_getSession(UA_SessionManager *sm, const UA_NodeId *token);
+UA_SessionManager_getSessionByToken(UA_SessionManager *sm, const UA_NodeId *token);
+
+UA_Session *
+UA_SessionManager_getSessionById(UA_SessionManager *sm, const UA_NodeId *sessionId);
 
 #ifdef __cplusplus
 } // extern "C"

+ 2 - 1
tests/check_client.c

@@ -39,7 +39,8 @@ addVariable(size_t size) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
-                              UA_NODEID_NULL, attr, NULL, NULL);
+                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                              attr, NULL, NULL);
 
     UA_free(array);
 }

+ 13 - 27
tests/check_client_highlevel.c

@@ -91,8 +91,7 @@ START_TEST(Node_Add) {
 
     // Create custom reference type 'HasSubSubType' as child of HasSubtype
     {
-        UA_ReferenceTypeAttributes attr;
-        UA_ReferenceTypeAttributes_init(&attr);
+        UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Some HasSubSubType");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "HasSubSubType");
         retval = UA_Client_addReferenceTypeNode(client, UA_NODEID_NULL,
@@ -105,8 +104,7 @@ START_TEST(Node_Add) {
 
     // Create TestObjectType SubType within BaseObjectType
     {
-        UA_ObjectTypeAttributes attr;
-        UA_ObjectTypeAttributes_init(&attr);
+        UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Some TestObjectType");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "TestObjectType");
         retval = UA_Client_addObjectTypeNode(client, UA_NODEID_NULL,
@@ -119,8 +117,7 @@ START_TEST(Node_Add) {
 
     // Create Int128 DataType within Integer Datatype
     {
-        UA_DataTypeAttributes attr;
-        UA_DataTypeAttributes_init(&attr);
+        UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Some Int128");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "Int128");
         retval = UA_Client_addDataTypeNode(client, UA_NODEID_NULL,
@@ -133,8 +130,7 @@ START_TEST(Node_Add) {
 
     // Create PointType VariableType within BaseDataVariableType
     {
-        UA_VariableTypeAttributes attr;
-        UA_VariableTypeAttributes_init(&attr);
+        UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
         attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
         attr.valueRank = 1; /* array with one dimension */
         UA_UInt32 arrayDims[1] = {2};
@@ -154,8 +150,7 @@ START_TEST(Node_Add) {
 
     // create Coordinates Object within ObjectsFolder
     {
-        UA_ObjectAttributes attr;
-        UA_ObjectAttributes_init(&attr);
+        UA_ObjectAttributes attr = UA_ObjectAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Some Coordinates");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "Coordinates");
         retval = UA_Client_addObjectNode(client, UA_NODEID_NULL,
@@ -169,8 +164,7 @@ START_TEST(Node_Add) {
 
     // create Variable 'Top' within Coordinates Object
     {
-        UA_VariableAttributes attr;
-        UA_VariableAttributes_init(&attr);
+        UA_VariableAttributes attr = UA_VariableAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Top Coordinate");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "Top");
         UA_Int32 values[2] = {10, 20};
@@ -188,12 +182,9 @@ START_TEST(Node_Add) {
         ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
     }
 
-    // create Method 'Dummy' within Coordinates Object. Fails with BADNODECLASSINVALID
+    // create Method 'Dummy' within Coordinates Object.
     {
-        // creating a method from a client does not yet make much sense since the corresponding
-        // action code can not be set from the client side
-        UA_MethodAttributes attr;
-        UA_MethodAttributes_init(&attr);
+        UA_MethodAttributes attr = UA_MethodAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Dummy method");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "Dummy");
         attr.executable = true;
@@ -203,13 +194,12 @@ START_TEST(Node_Add) {
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                                          UA_QUALIFIEDNAME(1, "Dummy"),
                                          attr, &newMethodId);
-        ck_assert_uint_eq(retval, UA_STATUSCODE_BADNODECLASSINVALID);
+        ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
     }
 
     // create View 'AllTopCoordinates' whithin Views Folder
     {
-        UA_ViewAttributes attr;
-        UA_ViewAttributes_init(&attr);
+        UA_ViewAttributes attr = UA_ViewAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "List of all top coordinates");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "AllTopCoordinates");
         retval = UA_Client_addViewNode(client, UA_NODEID_NULL,
@@ -220,7 +210,6 @@ START_TEST(Node_Add) {
         ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
     }
 
-
     // Add 'Top' to view
     retval = UA_Client_addReference(client, newViewId, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                     UA_TRUE, UA_STRING_NULL,
@@ -268,8 +257,7 @@ START_TEST(Node_ReadWrite) {
 
     // create Coordinates Object within ObjectsFolder
     {
-        UA_ObjectAttributes attr;
-        UA_ObjectAttributes_init(&attr);
+        UA_ObjectAttributes attr = UA_ObjectAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "UnitTest");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "UnitTest");
         retval = UA_Client_addObjectNode(client, UA_NODEID_NULL,
@@ -282,8 +270,7 @@ START_TEST(Node_ReadWrite) {
 
     // create Variable 'Top' within UnitTest Object
     {
-        UA_VariableAttributes attr;
-        UA_VariableAttributes_init(&attr);
+        UA_VariableAttributes attr = UA_VariableAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Array");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "Array");
         attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
@@ -310,8 +297,7 @@ START_TEST(Node_ReadWrite) {
 
     // create Variable 'Bottom' within UnitTest Object
     {
-        UA_VariableAttributes attr;
-        UA_VariableAttributes_init(&attr);
+        UA_VariableAttributes attr = UA_VariableAttributes_default;
         attr.description = UA_LOCALIZEDTEXT("en_US", "Int");
         attr.displayName = UA_LOCALIZEDTEXT("en_US", "Int");
         attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;

+ 23 - 19
tests/check_services_attributes.c

@@ -24,8 +24,11 @@ static UA_Server *server = NULL;
 static UA_ServerConfig *config = NULL;
 
 static UA_StatusCode
-readCPUTemperature(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
-                   const UA_NumericRange *range, UA_DataValue *dataValue) {
+readCPUTemperature(UA_Server *server_,
+                   const UA_NodeId *sessionId, void *sessionContext,
+                   const UA_NodeId *nodeId, void *nodeContext,
+                   UA_Boolean sourceTimeStamp, const UA_NumericRange *range,
+                   UA_DataValue *dataValue) {
     UA_Float temp = 20.5f;
     UA_Variant_setScalarCopy(&dataValue->value, &temp, &UA_TYPES[UA_TYPES_FLOAT]);
     dataValue->hasValue = true;
@@ -43,8 +46,7 @@ static void setup(void) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
 
     /* VariableNode */
-    UA_VariableAttributes vattr;
-    UA_VariableAttributes_init(&vattr);
+    UA_VariableAttributes vattr = UA_VariableAttributes_default;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalar(&vattr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     vattr.description = UA_LOCALIZEDTEXT("locale","the answer");
@@ -56,24 +58,28 @@ static void setup(void) {
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     retval = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                                        parentReferenceNodeId, myIntegerName,
-                                       UA_NODEID_NULL, vattr, NULL, NULL);
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                       vattr, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     /* DataSource VariableNode */
-    UA_VariableAttributes_init(&vattr);
-    UA_DataSource temperatureDataSource =
-        (UA_DataSource) {.handle = NULL, .read = readCPUTemperature, .write = NULL};
+    vattr = UA_VariableAttributes_default;
+    UA_DataSource temperatureDataSource;
+    temperatureDataSource.read = readCPUTemperature;
+    temperatureDataSource.write = NULL;
     vattr.description = UA_LOCALIZEDTEXT("en_US","temperature");
     vattr.displayName = UA_LOCALIZEDTEXT("en_US","temperature");
     retval = UA_Server_addDataSourceVariableNode(server, UA_NODEID_STRING(1, "cpu.temperature"),
                                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                                                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                                                  UA_QUALIFIEDNAME(1, "cpu temperature"),
-                                                 UA_NODEID_NULL, vattr, temperatureDataSource, NULL);
+                                                 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                                 vattr, temperatureDataSource,
+                                                 NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     /* VariableNode with array */
-    UA_VariableAttributes_init(&vattr);
+    vattr = UA_VariableAttributes_default;
     UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
     UA_Variant_setArray(&vattr.value, &myIntegerArray, 9, &UA_TYPES[UA_TYPES_INT32]);
     vattr.valueRank = -2;
@@ -87,12 +93,12 @@ static void setup(void) {
     parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
     retval = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
                                        parentReferenceNodeId, myIntegerName,
-                                       UA_NODEID_NULL, vattr, NULL, NULL);
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                       vattr, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     /* ObjectNode */
-    UA_ObjectAttributes obj_attr;
-    UA_ObjectAttributes_init(&obj_attr);
+    UA_ObjectAttributes obj_attr = UA_ObjectAttributes_default;
     obj_attr.description = UA_LOCALIZEDTEXT("en_US","Demo");
     obj_attr.displayName = UA_LOCALIZEDTEXT("en_US","Demo");
     retval = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 50),
@@ -104,8 +110,7 @@ static void setup(void) {
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     /* ViewNode */
-    UA_ViewAttributes view_attr;
-    UA_ViewAttributes_init(&view_attr);
+    UA_ViewAttributes view_attr = UA_ViewAttributes_default;
     view_attr.description = UA_LOCALIZEDTEXT("en_US", "Viewtest");
     view_attr.displayName = UA_LOCALIZEDTEXT("en_US", "Viewtest");
     retval = UA_Server_addViewNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWNODE),
@@ -116,15 +121,14 @@ static void setup(void) {
 
 #ifdef UA_ENABLE_METHODCALLS
     /* MethodNode */
-    UA_MethodAttributes ma;
-    UA_MethodAttributes_init(&ma);
+    UA_MethodAttributes ma = UA_MethodAttributes_default;
     ma.description = UA_LOCALIZEDTEXT("en_US", "Methodtest");
     ma.displayName = UA_LOCALIZEDTEXT("en_US", "Methodtest");
     retval = UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_METHODNODE),
                                      UA_NODEID_NUMERIC(0, 3),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                      UA_QUALIFIEDNAME(0, "Methodtest"), ma,
-                                     NULL, NULL, 0, NULL, 0, NULL, NULL);
+                                     NULL, 0, NULL, 0, NULL, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 #endif
 }
@@ -491,7 +495,7 @@ START_TEST(ReadSingleAttributeExecutableWithoutTimestamp) {
     ck_assert_int_eq(true, resp.hasValue);
     ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BOOLEAN], resp.value.type);
-    ck_assert(*(UA_Boolean*)resp.value.data==false);
+    ck_assert(*(UA_Boolean*)resp.value.data==true);
     UA_DataValue_deleteMembers(&resp);
 #endif
 } END_TEST

+ 119 - 90
tests/check_services_nodemanagement.c

@@ -21,9 +21,22 @@
 
 static UA_Server *server = NULL;
 static UA_ServerConfig *config = NULL;
+static UA_Int32 handleCalled = 0;
+
+static UA_StatusCode
+globalInstantiationMethod(UA_Server *server_,
+                          const UA_NodeId *sessionId, void *sessionContext,
+                          const UA_NodeId *nodeId, void **nodeContext) {
+    handleCalled++;
+    return UA_STATUSCODE_GOOD;
+}
 
 static void setup(void) {
     config = UA_ServerConfig_new_default();
+    UA_GlobalNodeLifecycle lifecycle;
+    lifecycle.constructor = globalInstantiationMethod;
+    lifecycle.destructor = NULL;
+    config->nodeLifecycle = lifecycle;
     server = UA_Server_new(config);
 }
 
@@ -32,15 +45,9 @@ static void teardown(void) {
     UA_ServerConfig_delete(config);
 }
 
-static UA_StatusCode
-instantiationMethod(UA_NodeId newNodeId, UA_NodeId templateId, void *handle ) {
-  *((UA_Int32 *) handle) += 1;
-  return UA_STATUSCODE_GOOD;
-}
 START_TEST(AddVariableNode) {
     /* add a variable node to the address space */
-    UA_VariableAttributes attr;
-    UA_VariableAttributes_init(&attr);
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
@@ -49,36 +56,36 @@ START_TEST(AddVariableNode) {
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                                  myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
+    UA_StatusCode res =
+        UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                                  parentReferenceNodeId, myIntegerName,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                  attr, NULL, NULL);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
 } END_TEST
 
 START_TEST(AddComplexTypeWithInheritance) {
-  /* add a variable node to the address space */
-  UA_ObjectAttributes attr;
-  UA_ObjectAttributes_init(&attr);
-  attr.description = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
-  attr.displayName = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
+    /* add a variable node to the address space */
+    UA_ObjectAttributes attr = UA_ObjectAttributes_default;
+    attr.description = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
+    attr.displayName = UA_LOCALIZEDTEXT("en_US","fakeServerStruct");
   
-  UA_NodeId myObjectNodeId = UA_NODEID_STRING(1, "the.fake.Server.Struct");
-  UA_QualifiedName myObjectName = UA_QUALIFIEDNAME(1, "the.fake.Server.Struct");
-  UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
-  UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-  UA_Int32 handleCalled = 0;
-  UA_InstantiationCallback iCallback = {.method=instantiationMethod, .handle = (void *) &handleCalled};
-    
-  UA_StatusCode res = UA_Server_addObjectNode(server, myObjectNodeId, parentNodeId, parentReferenceNodeId,
-                                              myObjectName, UA_NODEID_NUMERIC(0, 2004),
-                                              attr, &iCallback, NULL);
-  ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
-  ck_assert_int_gt(handleCalled, 0); // Should be 58, but may depend on NS0 XML detail
+    UA_NodeId myObjectNodeId = UA_NODEID_STRING(1, "the.fake.Server.Struct");
+    UA_QualifiedName myObjectName = UA_QUALIFIEDNAME(1, "the.fake.Server.Struct");
+    UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_StatusCode res =
+        UA_Server_addObjectNode(server, myObjectNodeId, parentNodeId,
+                                parentReferenceNodeId, myObjectName,
+                                UA_NODEID_NUMERIC(0, 2004), attr,
+                                &handleCalled, NULL);
+    ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
+    ck_assert_int_gt(handleCalled, 0); // Should be 58, but may depend on NS0 XML detail
 } END_TEST
 
 START_TEST(AddNodeTwiceGivesError) {
     /* add a variable node to the address space */
-    UA_VariableAttributes attr;
-    UA_VariableAttributes_init(&attr);
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
     UA_Int32 myInteger = 42;
     UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     attr.description = UA_LOCALIZEDTEXT("en_US","the answer");
@@ -87,45 +94,58 @@ START_TEST(AddNodeTwiceGivesError) {
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_StatusCode res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                                  myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
+    UA_StatusCode res =
+        UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                                  parentReferenceNodeId, myIntegerName,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                  attr, NULL, NULL);
     ck_assert_int_eq(UA_STATUSCODE_GOOD, res);
-    res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId, parentReferenceNodeId,
-                                    myIntegerName, UA_NODEID_NULL, attr, NULL, NULL);
+    res = UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                                    parentReferenceNodeId, myIntegerName,
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                    attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_BADNODEIDEXISTS);
 } END_TEST
 
 static UA_Boolean constructorCalled = false;
 
-static void * objectConstructor(const UA_NodeId instance) {
+static UA_StatusCode
+objectConstructor(UA_Server *server_,
+                  const UA_NodeId *sessionId, void *sessionContext,
+                  const UA_NodeId *typeId, void *typeContext,
+                  const UA_NodeId *nodeId, void **nodeContext) {
     constructorCalled = true;
-    return NULL;
+    return UA_STATUSCODE_GOOD;
 }
 
 START_TEST(AddObjectWithConstructor) {
     /* Add an object type */
     UA_NodeId objecttypeid = UA_NODEID_NUMERIC(0, 13371337);
-    UA_ObjectTypeAttributes attr;
-    UA_ObjectTypeAttributes_init(&attr);
+    UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
     attr.displayName = UA_LOCALIZEDTEXT("en_US","my objecttype");
-    UA_StatusCode res = UA_Server_addObjectTypeNode(server, objecttypeid,
-                                                    UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
-                                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                                                    UA_QUALIFIEDNAME(0, "myobjecttype"), attr, NULL, NULL);
+    UA_StatusCode res =
+        UA_Server_addObjectTypeNode(server, objecttypeid,
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                    UA_QUALIFIEDNAME(0, "myobjecttype"), attr,
+                                    NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Add a constructor to the object type */
-    UA_ObjectLifecycleManagement olm = {objectConstructor, NULL};
-    res = UA_Server_setObjectTypeNode_lifecycleManagement(server, objecttypeid, olm);
+    UA_NodeTypeLifecycle lifecycle;
+    lifecycle.constructor = objectConstructor;
+    lifecycle.destructor = NULL;
+    res = UA_Server_setNodeTypeLifecycle(server, objecttypeid, lifecycle);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Add an object of the type */
-    UA_ObjectAttributes attr2;
-    UA_ObjectAttributes_init(&attr2);
+    UA_ObjectAttributes attr2 = UA_ObjectAttributes_default;
     attr2.displayName = UA_LOCALIZEDTEXT("en_US","my object");
-    res = UA_Server_addObjectNode(server, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(0, ""),
-                                  objecttypeid, attr2, NULL, NULL);
+    res = UA_Server_addObjectNode(server, UA_NODEID_NULL,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                  UA_QUALIFIEDNAME(0, ""), objecttypeid,
+                                  attr2, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Verify that the constructor was called */
@@ -134,35 +154,42 @@ START_TEST(AddObjectWithConstructor) {
 
 static UA_Boolean destructorCalled = false;
 
-static void objectDestructor(const UA_NodeId instance, void *handle) {
+static void
+objectDestructor(UA_Server *server_,
+                 const UA_NodeId *sessionId, void *sessionContext,
+                 const UA_NodeId *typeId, void *typeContext,
+                 const UA_NodeId *nodeId, void **nodeContext) {
     destructorCalled = true;
 }
 
 START_TEST(DeleteObjectWithDestructor) {
     /* Add an object type */
     UA_NodeId objecttypeid = UA_NODEID_NUMERIC(0, 13371337);
-    UA_ObjectTypeAttributes attr;
-    UA_ObjectTypeAttributes_init(&attr);
+    UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
     attr.displayName = UA_LOCALIZEDTEXT("en_US","my objecttype");
-    UA_StatusCode res = UA_Server_addObjectTypeNode(server, objecttypeid,
-                                                    UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
-                                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
-                                                    UA_QUALIFIEDNAME(0, "myobjecttype"), attr, NULL, NULL);
+    UA_StatusCode res =
+        UA_Server_addObjectTypeNode(server, objecttypeid,
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                    UA_QUALIFIEDNAME(0, "myobjecttype"), attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Add a constructor to the object type */
-    UA_ObjectLifecycleManagement olm = {NULL, objectDestructor};
-    res = UA_Server_setObjectTypeNode_lifecycleManagement(server, objecttypeid, olm);
+    UA_NodeTypeLifecycle lifecycle;
+    lifecycle.constructor = NULL;
+    lifecycle.destructor = objectDestructor;
+    res = UA_Server_setNodeTypeLifecycle(server, objecttypeid, lifecycle);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Add an object of the type */
     UA_NodeId objectid = UA_NODEID_NUMERIC(0, 23372337);
-    UA_ObjectAttributes attr2;
-    UA_ObjectAttributes_init(&attr2);
+    UA_ObjectAttributes attr2 = UA_ObjectAttributes_default;
     attr2.displayName = UA_LOCALIZEDTEXT("en_US","my object");
-    res = UA_Server_addObjectNode(server, objectid, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(0, ""),
-                                  objecttypeid, attr2, NULL, NULL);
+    res = UA_Server_addObjectNode(server, objectid,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                  UA_QUALIFIEDNAME(0, ""), objecttypeid,
+                                  attr2, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Delete the object */
@@ -174,14 +201,16 @@ START_TEST(DeleteObjectWithDestructor) {
 
 START_TEST(DeleteObjectAndReferences) {
     /* Add an object of the type */
-    UA_ObjectAttributes attr;
-    UA_ObjectAttributes_init(&attr);
+    UA_ObjectAttributes attr = UA_ObjectAttributes_default;
     attr.displayName = UA_LOCALIZEDTEXT("en_US","my object");
     UA_NodeId objectid = UA_NODEID_NUMERIC(0, 23372337);
     UA_StatusCode res;
-    res = UA_Server_addObjectNode(server, objectid, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(0, ""),
-                                  UA_NODEID_NULL, attr, NULL, NULL);
+    res = UA_Server_addObjectNode(server, objectid,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                  UA_QUALIFIEDNAME(0, ""),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                  attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Verify that we have a reference to the node from the objects folder */
@@ -216,12 +245,15 @@ START_TEST(DeleteObjectAndReferences) {
     UA_BrowseResult_deleteMembers(&br);
 
     /* Add an object the second time */
-    UA_ObjectAttributes_init(&attr);
+    attr = UA_ObjectAttributes_default;
     attr.displayName = UA_LOCALIZEDTEXT("en_US","my object");
     objectid = UA_NODEID_NUMERIC(0, 23372337);
-    res = UA_Server_addObjectNode(server, objectid, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), UA_QUALIFIEDNAME(0, ""),
-                                  UA_NODEID_NULL, attr, NULL, NULL);
+    res = UA_Server_addObjectNode(server, objectid,
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                  UA_QUALIFIEDNAME(0, ""),
+                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                  attr, NULL, NULL);
     ck_assert_int_eq(res, UA_STATUSCODE_GOOD);
 
     /* Browse again, this time we expect that a single reference to the node is found */
@@ -246,8 +278,7 @@ START_TEST(InstantiateObjectType) {
 
     /* Define the object type for "Device" */
     UA_NodeId deviceTypeId; /* get the nodeid assigned by the server */
-    UA_ObjectTypeAttributes dtAttr;
-    UA_ObjectTypeAttributes_init(&dtAttr);
+    UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default;
     dtAttr.displayName = UA_LOCALIZEDTEXT("en_US", "DeviceType");
     retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
@@ -256,14 +287,14 @@ START_TEST(InstantiateObjectType) {
                                          NULL, &deviceTypeId);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
-    UA_VariableAttributes mnAttr;
-    UA_VariableAttributes_init(&mnAttr);
+    UA_VariableAttributes mnAttr = UA_VariableAttributes_default;
     mnAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ManufacturerName");
     UA_NodeId manufacturerNameId;
     retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
                                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                        UA_QUALIFIEDNAME(1, "ManufacturerName"),
-                                       UA_NODEID_NULL, mnAttr, NULL, &manufacturerNameId);
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                       mnAttr, NULL, &manufacturerNameId);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
     /* Make the manufacturer name mandatory */
     retval = UA_Server_addReference(server, manufacturerNameId,
@@ -271,34 +302,33 @@ START_TEST(InstantiateObjectType) {
                                     UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
-    UA_VariableAttributes modelAttr;
-    UA_VariableAttributes_init(&modelAttr);
+    UA_VariableAttributes modelAttr = UA_VariableAttributes_default;
     modelAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ModelName");
     retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
                                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                        UA_QUALIFIEDNAME(1, "ModelName"),
-                                       UA_NODEID_NULL, modelAttr, NULL, NULL);
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                       modelAttr, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     /* Define the object type for "Pump" */
-    UA_ObjectTypeAttributes ptAttr;
-    UA_ObjectTypeAttributes_init(&ptAttr);
+    UA_ObjectTypeAttributes ptAttr = UA_ObjectTypeAttributes_default;
     ptAttr.displayName = UA_LOCALIZEDTEXT("en_US", "PumpType");
-    retval = UA_Server_addObjectTypeNode(server, pumpTypeId,
-                                         deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+    retval = UA_Server_addObjectTypeNode(server, pumpTypeId, deviceTypeId,
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
                                          UA_QUALIFIEDNAME(1, "PumpType"), ptAttr,
                                          NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
-    UA_VariableAttributes statusAttr;
-    UA_VariableAttributes_init(&statusAttr);
+    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;
     statusAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Status");
     statusAttr.valueRank = -1;
     UA_NodeId statusId;
     retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
                                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                        UA_QUALIFIEDNAME(1, "Status"),
-                                       UA_NODEID_NULL, statusAttr, NULL, &statusId);
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                       statusAttr, NULL, &statusId);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     /* Make the status variable mandatory */
@@ -307,19 +337,18 @@ START_TEST(InstantiateObjectType) {
                                     UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
-    UA_VariableAttributes rpmAttr;
-    UA_VariableAttributes_init(&rpmAttr);
+    UA_VariableAttributes rpmAttr = UA_VariableAttributes_default;
     rpmAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MotorRPM");
     rpmAttr.valueRank = -1;
     retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
                                        UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                        UA_QUALIFIEDNAME(1, "MotorRPMs"),
-                                       UA_NODEID_NULL, rpmAttr, NULL, NULL);
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                       rpmAttr, NULL, NULL);
     ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
 
     /* Instantiate the variable */
-    UA_ObjectAttributes oAttr;
-    UA_ObjectAttributes_init(&oAttr);
+    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
     oAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MyPump");
     retval = UA_Server_addObjectNode(server, UA_NODEID_NULL,
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),

+ 1 - 1
tests/testing_networklayers.h

@@ -5,7 +5,7 @@
 #ifndef TESTING_NETWORKLAYERS_H_
 #define TESTING_NETWORKLAYERS_H_
 
-#include "ua_server.h"
+#include "ua_server_config.h"
 
 #ifdef __cplusplus
 extern "C" {