Browse Source

high-level api for the client; aligned with the server api

Julius Pfrommer 9 years ago
parent
commit
c9ae4288d8

+ 5 - 2
CMakeLists.txt

@@ -87,6 +87,7 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_log.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server.h
                      ${PROJECT_SOURCE_DIR}/include/ua_client.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_client_highlevel.h
                      ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.h
                      ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h)
 set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
@@ -125,6 +126,7 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_nodemanagement.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
+                ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel.c
                 ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c
                 ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
                 ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
@@ -146,11 +148,12 @@ if(ENABLE_SUBSCRIPTIONS)
   set(ENABLE_SUBSCRIPTIONS ON) #to propagate it to the config file
   list(APPEND lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_services_subscription.c
                           ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.c
-                          ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.c)
+                          ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.c
+                          ${PROJECT_SOURCE_DIR}/src/client/ua_client_highlevel_subscriptions.c)
   ##append subscription headers at before ua_session.
   list(FIND internal_headers "${PROJECT_SOURCE_DIR}/src/ua_session.h" UaSessionPos)
   list(INSERT internal_headers  ${UaSessionPos} ${PROJECT_SOURCE_DIR}/src/server/ua_subscription.h
-                          ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.h)
+                                                ${PROJECT_SOURCE_DIR}/src/server/ua_subscription_manager.h)
 
   add_custom_command(OUTPUT ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.c
                             ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h

+ 17 - 17
examples/client.c

@@ -1,6 +1,7 @@
 #ifdef UA_NO_AMALGAMATION
 # include "ua_types.h"
 # include "ua_client.h"
+# include "ua_client_highlevel.h"
 # include "ua_nodeids.h"
 # include "networklayer_tcp.h"
 # include "logger_stdout.h"
@@ -39,7 +40,7 @@ int main(int argc, char *argv[]) {
     bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); //browse objects folder
     bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything
 
-    UA_BrowseResponse bResp = UA_Client_browse(client, &bReq);
+    UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
     printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
     for (int i = 0; i < bResp.resultsSize; ++i) {
         for (int j = 0; j < bResp.results[i].referencesSize; ++j) {
@@ -62,23 +63,24 @@ int main(int argc, char *argv[]) {
     
 #ifdef ENABLE_SUBSCRIPTIONS
     // Create a subscription with interval 0 (immediate)...
-    UA_Int32 subId = UA_Client_newSubscription(client, 0);
-    if (subId)
+    UA_UInt32 subId;
+    UA_Client_Subscriptions_new(client, UA_SubscriptionSettings_standard, &subId);
+    if(subId)
         printf("Create subscription succeeded, id %u\n", subId);
     
     // .. and monitor TheAnswer
-    UA_NodeId monitorThis;
-    monitorThis = UA_NODEID_STRING_ALLOC(1, "the.answer");
-    UA_UInt32 monId = UA_Client_monitorItemChanges(client, subId, monitorThis, UA_ATTRIBUTEID_VALUE, &handler_TheAnswerChanged );
+    UA_NodeId monitorThis = UA_NODEID_STRING(1, "the.answer");
+    UA_UInt32 monId;
+    UA_Client_Subscriptions_addMonitoredItem(client, subId, monitorThis,
+                                             UA_ATTRIBUTEID_VALUE, &handler_TheAnswerChanged, &monId);
     if (monId)
         printf("Monitoring 'the.answer', id %u\n", subId);
-    UA_NodeId_deleteMembers(&monitorThis);
     
     // First Publish always generates data (current value) and call out handler.
-    UA_Client_doPublish(client);
+    UA_Client_Subscriptions_manuallySendPublishRequest(client);
     
     // This should not generate anything
-    UA_Client_doPublish(client);
+    UA_Client_Subscriptions_manuallySendPublishRequest(client);
 #endif
     
     UA_Int32 value = 0;
@@ -91,7 +93,7 @@ int main(int argc, char *argv[]) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer"); /* assume this node exists */
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
 
-    UA_ReadResponse rResp = UA_Client_read(client, &rReq);
+    UA_ReadResponse rResp = UA_Client_Service_read(client, rReq);
     if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
        rResp.resultsSize > 0 && rResp.results[0].hasValue &&
        UA_Variant_isScalar(&rResp.results[0].value) &&
@@ -117,7 +119,7 @@ int main(int argc, char *argv[]) {
     wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; //do not free the integer on deletion
     wReq.nodesToWrite[0].value.value.data = &value;
     
-    UA_WriteResponse wResp = UA_Client_write(client, &wReq);
+    UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
     if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
             printf("the new value is: %i\n", value);
     UA_WriteRequest_deleteMembers(&wReq);
@@ -125,10 +127,10 @@ int main(int argc, char *argv[]) {
 
 #ifdef ENABLE_SUBSCRIPTIONS
     // Take another look at the.answer... this should call the handler.
-    UA_Client_doPublish(client);
+    UA_Client_Subscriptions_manuallySendPublishRequest(client);
     
     // Delete our subscription (which also unmonitors all items)
-    if(!UA_Client_removeSubscription(client, subId))
+    if(!UA_Client_Subscriptions_remove(client, subId))
         printf("Subscription removed\n");
 #endif
     
@@ -137,16 +139,14 @@ int main(int argc, char *argv[]) {
        FIXME: Provide a namespace 0 independant example on the server side
      */
     UA_Variant input;
-    
     UA_String argString = UA_STRING("Hello Server");
     UA_Variant_init(&input);
     UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
     
     UA_Int32 outputSize;
     UA_Variant *output;
-    
-    retval = UA_Client_CallServerMethod(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                                        UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
+    retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                            UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
     if(retval == UA_STATUSCODE_GOOD) {
         printf("Method call was successfull, and %i returned values available.\n", outputSize);
         UA_Array_delete(output, &UA_TYPES[UA_TYPES_VARIANT], outputSize);

+ 1 - 1
examples/client_firstSteps.c

@@ -31,7 +31,7 @@ int main(void) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_NUMERIC(0, 2258);
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
 
-    UA_ReadResponse rResp = UA_Client_read(client, &rReq);
+    UA_ReadResponse rResp = UA_Client_Service_read(client, rReq);
     if(rResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD &&
             rResp.resultsSize > 0 && rResp.results[0].hasValue &&
             UA_Variant_isScalar(&rResp.results[0].value) &&

+ 1 - 8
examples/server.c

@@ -238,13 +238,6 @@ int main(int argc, char** argv) {
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), dateName,
                                         UA_NODEID_NULL, v_attr, dateDataSource, &dataSourceId);
 
-    // Get and reattach the datasource
-    UA_DataSource dataSourceCopy;
-    UA_Server_getNodeAttribute_value_dataSource(server, dataSourceId, &dataSourceCopy);
-    if (dataSourceCopy.read != dateDataSource.read)
-        UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND, "The returned dataSource is not the same as we set?");
-    else
-        UA_Server_setNodeAttribute_value_dataSource(server, dataSourceId, dataSourceCopy);
 #ifndef _WIN32
     /* cpu temperature monitoring for linux machines */
     if((temperatureFile = fopen("/sys/class/thermal/thermal_zone0/temp", "r"))) {
@@ -429,7 +422,7 @@ int main(int argc, char** argv) {
   
     // Some easy localization
     UA_LocalizedText objectsName = UA_LOCALIZEDTEXT("de_DE", "Objekte");
-    UA_Server_setNodeAttribute_displayName(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
+    UA_Server_writeDisplayNameAttribute(server, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), objectsName);
   
     //start server
     UA_StatusCode retval = UA_Server_run(server, 1, &running); //blocks until running=false

+ 1 - 1
examples/server_variable.c

@@ -58,7 +58,7 @@ int main(int argc, char** argv) {
                               UA_NODEID_NULL, attr, NULL);
 
     UA_ValueCallback callback = {(void*)7, onRead, onWrite};
-    UA_Server_setNodeAttribute_value_callback(server, myIntegerNodeId, callback);
+    UA_Server_setVariableNode_valueCallback(server, myIntegerNodeId, callback);
 
     UA_StatusCode retval = UA_Server_run(server, 1, &running);
     UA_Server_delete(server);

+ 158 - 140
include/ua_client.h

@@ -14,13 +14,6 @@ extern "C" {
 struct UA_Client;
 typedef struct UA_Client UA_Client;
 
-/**
- * The client networklayer is defined by a single function that fills a UA_Connection struct after
- * successfully connecting.
- */
-typedef UA_Connection (*UA_ConnectClientConnection)(UA_ConnectionConfig localConf, char *endpointUrl,
-                                                    UA_Logger logger);
-
 typedef struct UA_ClientConfig {
     UA_Int32 timeout; //sync response timeout
     UA_Int32 secureChannelLifeTime; // lifetime in ms (then the channel needs to be renewed)
@@ -32,156 +25,181 @@ extern UA_EXPORT const UA_ClientConfig UA_ClientConfig_standard;
 
 UA_Client UA_EXPORT * UA_Client_new(UA_ClientConfig config, UA_Logger logger);
 
-UA_EXPORT void UA_Client_reset(UA_Client* client);
+void UA_EXPORT UA_Client_reset(UA_Client* client);
 
-UA_EXPORT void UA_Client_init(UA_Client* client, UA_ClientConfig config, UA_Logger logger);
+void UA_EXPORT UA_Client_delete(UA_Client* client);
 
-UA_EXPORT void UA_Client_deleteMembers(UA_Client* client);
+/*************************/
+/* Manage the Connection */
+/*************************/
 
-UA_EXPORT void UA_Client_delete(UA_Client* client);
+typedef UA_Connection (*UA_ConnectClientConnection)(UA_ConnectionConfig localConf, char *endpointUrl,
+                                                    UA_Logger logger);
 
 UA_StatusCode UA_EXPORT
 UA_Client_connect(UA_Client *client, UA_ConnectClientConnection connFunc, char *endpointUrl);
 
 UA_StatusCode UA_EXPORT UA_Client_disconnect(UA_Client *client);
 
-UA_StatusCode UA_EXPORT UA_Client_renewSecureChannel(UA_Client *client);
-
-/* Attribute Service Set */
-UA_ReadResponse UA_EXPORT UA_Client_read(UA_Client *client, UA_ReadRequest *request);
-
-UA_WriteResponse UA_EXPORT UA_Client_write(UA_Client *client, UA_WriteRequest *request);
-
-/* View Service Set */    
-UA_BrowseResponse UA_EXPORT UA_Client_browse(UA_Client *client, UA_BrowseRequest *request);
-
-UA_BrowseNextResponse UA_EXPORT UA_Client_browseNext(UA_Client *client, UA_BrowseNextRequest *request);
+UA_StatusCode UA_EXPORT UA_Client_manuallyRenewSecureChannel(UA_Client *client);
 
-UA_TranslateBrowsePathsToNodeIdsResponse UA_EXPORT
-UA_Client_translateTranslateBrowsePathsToNodeIds(UA_Client *client,
-                                                 UA_TranslateBrowsePathsToNodeIdsRequest *request);
+/****************/
+/* Raw Services */
+/****************/
 
-/**
- * Get the namespace-index of a namespace-URI
- *
- * @param client The UA_Client struct for this connection
- * @param namespaceUri The interested namespace URI
- * @param namespaceIndex The namespace index of the URI. The value is unchanged in case of an error
- * @return Indicates whether the operation succeeded or returns an error code
- */
-UA_StatusCode UA_EXPORT UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt16 *namespaceIndex);
+/* Don't use this function. There are typed versions. */
+void UA_EXPORT
+__UA_Client_Service(UA_Client *client, const void *request, const UA_DataType *requestType,
+                    void *response, const UA_DataType *responseType);
 
 /* NodeManagement Service Set */
-UA_AddNodesResponse UA_EXPORT UA_Client_addNodes(UA_Client *client, UA_AddNodesRequest *request);
-
-UA_AddReferencesResponse UA_EXPORT
-UA_Client_addReferences(UA_Client *client, UA_AddReferencesRequest *request);
-
-UA_DeleteNodesResponse UA_EXPORT UA_Client_deleteNodes(UA_Client *client, UA_DeleteNodesRequest *request);
-
-UA_DeleteReferencesResponse UA_EXPORT
-UA_Client_deleteReferences(UA_Client *client, UA_DeleteReferencesRequest *request);
-
+static UA_INLINE UA_AddNodesResponse
+UA_Client_Service_addNodes(UA_Client *client, const UA_AddNodesRequest request) {
+    UA_AddNodesResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_AddReferencesResponse
+UA_Client_Service_addReferences(UA_Client *client, const UA_AddReferencesRequest request) {
+    UA_AddReferencesResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_ADDNODESREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_DeleteNodesResponse
+UA_Client_Service_deleteNodes(UA_Client *client, const UA_DeleteNodesRequest request) {
+    UA_DeleteNodesResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_DeleteReferencesResponse
+UA_Client_Service_deleteReferences(UA_Client *client, const UA_DeleteReferencesRequest request) {
+    UA_DeleteReferencesResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETENODESREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]);
+    return response; }
 
-/* Client-Side Macro/Procy functions */
-#ifdef ENABLE_METHODCALLS
-UA_CallResponse UA_EXPORT UA_Client_call(UA_Client *client, UA_CallRequest *request);
+/* View Service Set */    
+static UA_INLINE UA_BrowseResponse
+UA_Client_Service_browse(UA_Client *client, const UA_BrowseRequest request) {
+    UA_BrowseResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_BROWSEREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_BROWSERESPONSE]);
+    return response; }
+
+static UA_INLINE UA_BrowseNextResponse
+UA_Client_Service_browseNext(UA_Client *client, const UA_BrowseNextRequest request) {
+    UA_BrowseNextResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_TranslateBrowsePathsToNodeIdsResponse
+UA_Client_Service_translateBrowsePathsToNodeIds(UA_Client *client,
+                                                const UA_TranslateBrowsePathsToNodeIdsRequest request) {
+    UA_TranslateBrowsePathsToNodeIdsResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_RegisterNodesResponse
+UA_Client_Service_registerNodes(UA_Client *client, const UA_RegisterNodesRequest request) {
+    UA_RegisterNodesResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_UnregisterNodesResponse
+UA_Client_Service_unregisterNodes(UA_Client *client, const UA_UnregisterNodesRequest request) {
+    UA_UnregisterNodesResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]);
+    return response; }
+
+/* Query Service Set */
+static UA_INLINE UA_QueryFirstResponse
+UA_Client_Service_queryFirst(UA_Client *client, const UA_QueryFirstRequest request) {
+    UA_QueryFirstResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_QueryNextResponse
+UA_Client_Service_queryNext(UA_Client *client, const UA_QueryNextRequest request) {
+    UA_QueryNextResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_QUERYFIRSTREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_QUERYFIRSTRESPONSE]);
+    return response; }
 
-UA_StatusCode UA_EXPORT
-UA_Client_CallServerMethod(UA_Client *client, UA_NodeId objectNodeId, UA_NodeId methodNodeId,
-                           UA_Int32 inputSize, const UA_Variant *input,
-                           UA_Int32 *outputSize, UA_Variant **output);
-#endif
+/* Attribute Service Set */
+static UA_INLINE UA_ReadResponse
+UA_Client_Service_read(UA_Client *client, const UA_ReadRequest request) {
+    UA_ReadResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_READRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_WriteResponse
+UA_Client_Service_write(UA_Client *client, const UA_WriteRequest request) {
+    UA_WriteResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_WRITEREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_WRITERESPONSE]);
+    return response; }
+
+/* Method Service Set */
+static UA_INLINE UA_CallResponse
+UA_Client_Service_call(UA_Client *client, const UA_CallRequest request) {
+    UA_CallResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CALLREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_CALLRESPONSE]);
+    return response; }
 
-/* Don't call this function, use the typed versions */
-UA_StatusCode UA_EXPORT
-__UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
-                    const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
-                    const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
-                    const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
-                    const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
-
-static UA_INLINE UA_StatusCode
-UA_Client_addVariableNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
-                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                          const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                          const UA_VariableAttributes attr, UA_NodeId *outNewNodeId) {
-    return __UA_Client_addNode(client, UA_NODECLASS_VARIABLE, requestedNewNodeId,
-                               parentNodeId, referenceTypeId, browseName, typeDefinition,
-                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
-                               outNewNodeId); }
-
-static UA_INLINE UA_StatusCode
-UA_Client_addVariableTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
-                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                              const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
-                              UA_NodeId *outNewNodeId) {
-    return __UA_Client_addNode(client, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId,
-                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
-                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
-                               outNewNodeId); }
-
-static UA_INLINE UA_StatusCode
-UA_Client_addObjectNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
-                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
-                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
-    return __UA_Client_addNode(client, UA_NODECLASS_OBJECT, requestedNewNodeId,
-                               parentNodeId, referenceTypeId, browseName, typeDefinition,
-                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
-                               outNewNodeId); }
-
-static UA_INLINE UA_StatusCode
-UA_Client_addObjectTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
-                            const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                            const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
-                            UA_NodeId *outNewNodeId) {
-    return __UA_Client_addNode(client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId,
-                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
-                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
-                               outNewNodeId); }
-
-static UA_INLINE UA_StatusCode
-UA_Client_addViewNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
-                      const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                      const UA_QualifiedName browseName, const UA_ViewAttributes attr,
-                      UA_NodeId *outNewNodeId) {
-    return __UA_Client_addNode(client, UA_NODECLASS_VIEW, requestedNewNodeId,
-                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
-                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VIEWATTRIBUTES],
-                               outNewNodeId); }
-
-static UA_INLINE UA_StatusCode
-UA_Client_addReferenceTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
-                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                               const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
-                               UA_NodeId *outNewNodeId) {
-    return __UA_Client_addNode(client, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId,
-                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
-                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
-                               outNewNodeId); }
-
-static UA_INLINE UA_StatusCode
-UA_Client_addDataTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
-                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
-                          const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
-                          UA_NodeId *outNewNodeId) {
-    return __UA_Client_addNode(client, UA_NODECLASS_DATATYPE, requestedNewNodeId,
-                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
-                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
-                               outNewNodeId); }
-    
 #ifdef ENABLE_SUBSCRIPTIONS
-UA_Int32      UA_EXPORT UA_Client_newSubscription(UA_Client *client, UA_Int32 publishInterval);
-UA_StatusCode UA_EXPORT UA_Client_removeSubscription(UA_Client *client, UA_UInt32 subscriptionId);
-//void UA_EXPORT UA_Client_modifySubscription(UA_Client *client);
-void UA_EXPORT UA_Client_doPublish(UA_Client *client);
-
-UA_UInt32     UA_EXPORT UA_Client_monitorItemChanges(UA_Client *client, UA_UInt32 subscriptionId,
-                                                     UA_NodeId nodeId, UA_UInt32 attributeID,
-                                                     void *handlingFunction);
-UA_StatusCode UA_EXPORT UA_Client_unMonitorItemChanges(UA_Client *client, UA_UInt32 subscriptionId,
-                                                       UA_UInt32 monitoredItemId );
+/* MonitoredItem Service Set */
+static UA_INLINE UA_CreateMonitoredItemsResponse
+UA_Client_Service_createMonitoredItems(UA_Client *client, const UA_CreateMonitoredItemsRequest request) {
+    UA_CreateMonitoredItemsResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_DeleteMonitoredItemsResponse
+UA_Client_Service_deleteMonitoredItems(UA_Client *client, const UA_DeleteMonitoredItemsRequest request) {
+    UA_DeleteMonitoredItemsResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]);
+    return response; }
+
+/* Subscription Service Set */
+static UA_INLINE UA_CreateSubscriptionResponse
+UA_Client_Service_createSubscription(UA_Client *client, const UA_CreateSubscriptionRequest request) {
+    UA_CreateSubscriptionResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_ModifySubscriptionResponse
+UA_Client_Service_modifySubscription(UA_Client *client, const UA_ModifySubscriptionRequest request) {
+    UA_ModifySubscriptionResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_DeleteSubscriptionsResponse
+UA_Client_Service_deleteSubscriptions(UA_Client *client, const UA_DeleteSubscriptionsRequest request) {
+    UA_DeleteSubscriptionsResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]);
+    return response; }
+
+static UA_INLINE UA_PublishResponse
+UA_Client_Service_publish(UA_Client *client, const UA_PublishRequest request) {
+    UA_PublishResponse response;
+    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
+                        &response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
+    return response; }
 #endif
 
 #ifdef __cplusplus

+ 294 - 0
include/ua_client_highlevel.h

@@ -0,0 +1,294 @@
+#ifndef UA_CLIENT_HIGHLEVEL_H_
+#define UA_CLIENT_HIGHLEVEL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_client.h"
+
+/**
+ * Get the namespace-index of a namespace-URI
+ *
+ * @param client The UA_Client struct for this connection
+ * @param namespaceUri The interested namespace URI
+ * @param namespaceIndex The namespace index of the URI. The value is unchanged in case of an error
+ * @return Indicates whether the operation succeeded or returns an error code
+ */
+UA_StatusCode UA_EXPORT UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt16 *namespaceIndex);
+
+/*******************/
+/* Node Management */
+/*******************/
+
+UA_StatusCode UA_EXPORT
+UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
+                       UA_Boolean isForward, const UA_String targetServerUri,
+                       const UA_ExpandedNodeId targetNodeId, UA_NodeClass targetNodeClass);
+
+UA_StatusCode UA_EXPORT
+UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
+                          UA_Boolean isForward, const UA_ExpandedNodeId targetNodeId,
+                          UA_Boolean deleteBidirectional);
+
+UA_StatusCode UA_EXPORT
+UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId, UA_Boolean deleteTargetReferences);
+    
+/* Don't call this function, use the typed versions */
+UA_StatusCode UA_EXPORT
+__UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
+                    const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
+                    const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
+                    const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
+                    const UA_DataType *attributeType, UA_NodeId *outNewNodeId);
+
+static UA_INLINE UA_StatusCode
+UA_Client_addVariableNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+                          const UA_VariableAttributes attr, UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_VARIABLE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, typeDefinition,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
+                               outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_addVariableTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                              const UA_QualifiedName browseName, const UA_VariableTypeAttributes attr,
+                              UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_VARIABLETYPE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
+                               outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_addObjectNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
+                        const UA_ObjectAttributes attr, UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_OBJECT, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, typeDefinition,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
+                               outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_addObjectTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                            const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                            const UA_QualifiedName browseName, const UA_ObjectTypeAttributes attr,
+                            UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_OBJECTTYPE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],
+                               outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_addViewNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                      const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                      const UA_QualifiedName browseName, const UA_ViewAttributes attr,
+                      UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_VIEW, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VIEWATTRIBUTES],
+                               outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_addReferenceTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                               const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                               const UA_QualifiedName browseName, const UA_ReferenceTypeAttributes attr,
+                               UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_REFERENCETYPE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],
+                               outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_addDataTypeNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName, const UA_DataTypeAttributes attr,
+                          UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_DATATYPE, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],
+                               outNewNodeId); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_addMethodNode(UA_Client *client, const UA_NodeId requestedNewNodeId,
+                          const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
+                          const UA_QualifiedName browseName, const UA_MethodAttributes attr,
+                          UA_NodeId *outNewNodeId) {
+    return __UA_Client_addNode(client, UA_NODECLASS_METHOD, requestedNewNodeId,
+                               parentNodeId, referenceTypeId, browseName, UA_NODEID_NULL,
+                               (const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],
+                               outNewNodeId); }
+
+/*************************/
+/* Attribute Service Set */
+/*************************/
+
+/* Don't use this function. There are typed versions for every supported attribute. */
+UA_StatusCode UA_EXPORT
+__UA_Client_readAttribute(UA_Client *client, UA_NodeId nodeId, UA_AttributeId attributeId,
+                          void *out, const UA_DataType *outDataType);
+  
+static UA_INLINE UA_StatusCode
+UA_Client_readNodeIdAttribute(UA_Client *client, UA_NodeId nodeId, UA_NodeId *outNodeId) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_NODEID,
+                                     outNodeId, &UA_TYPES[UA_TYPES_NODEID]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readNodeClassAttribute(UA_Client *client, UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_NODECLASS,
+                                     outNodeClass, &UA_TYPES[UA_TYPES_NODECLASS]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readBrowseNameAttribute(UA_Client *client, UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_BROWSENAME,
+                                     outBrowseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readDisplayNameAttribute(UA_Client *client, UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
+                                     outDisplayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readDescriptionAttribute(UA_Client *client, UA_NodeId nodeId, UA_LocalizedText *outDescription) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_DESCRIPTION,
+                                     outDescription, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readWriteMaskAttribute(UA_Client *client, UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_WRITEMASK,
+                                     outWriteMask, &UA_TYPES[UA_TYPES_UINT32]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readUserWriteMaskAttribute(UA_Client *client, UA_NodeId nodeId, UA_UInt32 *outUserWriteMask) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_USERWRITEMASK,
+                                     outUserWriteMask, &UA_TYPES[UA_TYPES_UINT32]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readIsAbstractAttribute(UA_Client *client, UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_ISABSTRACT,
+                                     outIsAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readSymmetricAttribute(UA_Client *client, UA_NodeId nodeId, UA_Boolean *outSymmetric) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_SYMMETRIC,
+                                     outSymmetric, &UA_TYPES[UA_TYPES_BOOLEAN]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readInverseNameAttribute(UA_Client *client, UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_INVERSENAME,
+                                     outInverseName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readContainsNoLoopsAttribute(UA_Client *client, UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
+                                     outContainsNoLoops, &UA_TYPES[UA_TYPES_BOOLEAN]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readEventNotifierAttribute(UA_Client *client, UA_NodeId nodeId, UA_Byte *outEventNotifier) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
+                                     outEventNotifier, &UA_TYPES[UA_TYPES_BYTE]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readValueAttribute(UA_Client *client, UA_NodeId nodeId, UA_Variant *outValue) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_VALUE,
+                                     outValue, &UA_TYPES[UA_TYPES_VARIANT]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readDataTypeAttribute(UA_Client *client, UA_NodeId nodeId, UA_NodeId *outDataType) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_DATATYPE,
+                                     outDataType, &UA_TYPES[UA_TYPES_NODEID]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readValueRankAttribute(UA_Client *client, UA_NodeId nodeId, UA_Int32 *outValueRank) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_VALUERANK,
+                                     outValueRank, &UA_TYPES[UA_TYPES_INT32]); }
+
+// todo: fetch an array
+static UA_INLINE UA_StatusCode
+UA_Client_readArrayDimensionsAttribute(UA_Client *client, UA_NodeId nodeId, UA_Int32 *outArrayDimensions) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
+                                     outArrayDimensions, &UA_TYPES[UA_TYPES_INT32]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readAccessLevelAttribute(UA_Client *client, UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
+                                     outAccessLevel, &UA_TYPES[UA_TYPES_UINT32]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readUserAccessLevelAttribute(UA_Client *client, UA_NodeId nodeId, UA_UInt32 *outUserAccessLevel) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL,
+                                     outUserAccessLevel, &UA_TYPES[UA_TYPES_UINT32]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readMinimumSamplingIntervalAttribute(UA_Client *client, UA_NodeId nodeId,
+                                               UA_Double *outMinimumSamplingInterval) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                                     outMinimumSamplingInterval, &UA_TYPES[UA_TYPES_DOUBLE]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readHistorizingAttribute(UA_Client *client, UA_NodeId nodeId, UA_Boolean *outHistorizing) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_HISTORIZING,
+                                     outHistorizing, &UA_TYPES[UA_TYPES_BOOLEAN]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readExecutableAttribute(UA_Client *client, UA_NodeId nodeId, UA_Boolean *outExecutable) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_EXECUTABLE,
+                                     outExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]); }
+
+static UA_INLINE UA_StatusCode
+UA_Client_readUserExecutableAttribute(UA_Client *client, UA_NodeId nodeId, UA_Boolean *outUserExecutable) {
+    return __UA_Client_readAttribute(client, nodeId, UA_ATTRIBUTEID_USEREXECUTABLE,
+                                     outUserExecutable, &UA_TYPES[UA_TYPES_BOOLEAN]); }
+
+/**********************/
+/* Method Service Set */
+/**********************/
+
+UA_StatusCode UA_EXPORT
+UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId,
+               UA_Int32 inputSize, const UA_Variant *input, UA_Int32 *outputSize, UA_Variant **output);
+
+/**************************/
+/* Subscriptions Handling */
+/**************************/
+
+#ifdef ENABLE_SUBSCRIPTIONS
+
+typedef struct {
+    UA_Double requestedPublishingInterval;
+    UA_UInt32 requestedLifetimeCount;
+    UA_UInt32 requestedMaxKeepAliveCount;
+    UA_UInt32 maxNotificationsPerPublish;
+    UA_Boolean publishingEnabled;
+    UA_Byte priority;
+} UA_SubscriptionSettings;
+
+extern const UA_EXPORT UA_SubscriptionSettings UA_SubscriptionSettings_standard;
+    
+UA_StatusCode UA_EXPORT
+UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
+                            UA_UInt32 *newSubscriptionId);
+    
+UA_StatusCode UA_EXPORT
+UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId);
+
+void UA_EXPORT UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client);
+
+UA_StatusCode UA_EXPORT
+UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
+                                         UA_NodeId nodeId, UA_UInt32 attributeID,
+                                         void *handlingFunction, UA_UInt32 *newMonitoredItemId);
+
+UA_StatusCode UA_EXPORT
+UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
+                                            UA_UInt32 monitoredItemId);
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* UA_CLIENT_HIGHLEVEL_H_ */

+ 153 - 156
include/ua_server.h

@@ -154,9 +154,10 @@ void UA_EXPORT UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLaye
 /** @brief Add a new namespace to the server. Returns the index of the new namespace */
 UA_UInt16 UA_EXPORT UA_Server_addNamespace(UA_Server *server, const char* name);
 
-/***************/
-/* Data Source */
-/***************/
+
+/**********************/
+/* Set Node Callbacks */
+/**********************/
 
 /**
  * Datasources are the interface to local data providers. It is expected that
@@ -194,26 +195,64 @@ typedef struct {
      *        of ranges, then an error code is returned.
      * @return Returns a status code that is returned to the user
      */
-    UA_StatusCode (*write)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
+    UA_StatusCode (*write)(void *handle, const UA_NodeId nodeid,
+                           const UA_Variant *data, const UA_NumericRange *range);
 } UA_DataSource;
 
+UA_StatusCode UA_EXPORT
+UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
+                                     const UA_DataSource dataSource);
+
 /* Value Callbacks can be attach to value and value type nodes. If not-null, they are called before
    reading and after writing respectively */
 typedef struct {
     void *handle;
-    void (*onRead)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
-    void (*onWrite)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
+    void (*onRead)(void *handle, const UA_NodeId nodeid,
+                   const UA_Variant *data, const UA_NumericRange *range);
+    void (*onWrite)(void *handle, const UA_NodeId nodeid,
+                    const UA_Variant *data, const UA_NumericRange *range);
 } UA_ValueCallback;
 
+UA_StatusCode UA_EXPORT
+UA_Server_setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
+                                        const UA_ValueCallback callback);
+
+/* The lifecycle management allows to track the instantiation and deletion of
+   object nodes derived from object types. */
+typedef struct {
+    void * (*constructor)(const UA_NodeId instance); ///< Returns the instance handle attached to the node
+    void (*destructor)(const UA_NodeId instance, void *instanceHandle);
+} UA_ObjectLifecycleManagement;
+
+UA_StatusCode UA_EXPORT
+UA_Server_setObjectTypeNode_instanceLifecycleManagement(UA_Server *server, UA_NodeId nodeId,
+                                                        UA_ObjectLifecycleManagement olm);
+
+/* Iterate over all nodes referenced by parentNodeId by calling the callback
+   function for each child node */
+typedef UA_StatusCode (*UA_NodeIteratorCallback)(UA_NodeId childId, UA_Boolean isInverse,
+                                                 UA_NodeId referenceTypeId, void *handle);
+
+UA_StatusCode UA_EXPORT
+UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
+                               UA_NodeIteratorCallback callback, void *handle);
+
 /*******************/
 /* Node Management */
 /*******************/
 
-/** Add a reference to the server's address space */
 UA_StatusCode UA_EXPORT
 UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId, const UA_NodeId refTypeId,
                        const UA_ExpandedNodeId targetId, UA_Boolean isForward);
 
+UA_StatusCode UA_EXPORT
+UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId, UA_Boolean deleteReferences);
+    
+UA_StatusCode UA_EXPORT
+UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
+                          UA_Boolean isForward, const UA_ExpandedNodeId targetNodeId,
+                          UA_Boolean deleteBidirectional);
+
 /* 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, const UA_NodeId requestedNewNodeId,
@@ -294,6 +333,7 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
 #ifdef ENABLE_METHODCALLS
 typedef UA_StatusCode (*UA_MethodCallback)(const UA_NodeId objectId, const UA_Variant *input,
                                            UA_Variant *output, void *handle);
+
 UA_StatusCode UA_EXPORT
 UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
@@ -304,43 +344,23 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                         UA_NodeId *outNewNodeId);
 #endif
 
-UA_StatusCode UA_EXPORT UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId);
-
-typedef UA_StatusCode (*UA_NodeIteratorCallback) (UA_NodeId childId, UA_Boolean isInverse,
-                                                  UA_NodeId referenceTypeId, void *handle);
-
-/** Iterate over all nodes referenced by parentNodeId by calling the callback function for each
- * child node
- * 
- * @param server The server object.
- *
- * @param parentNodeId The NodeId of the parent whose references are to be iterated over
- *
- * @param callback The function of type UA_NodeIteratorCallback to be called for each referenced child
- *
- * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code otherwise.
- */
-UA_StatusCode UA_EXPORT
-UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
-                               UA_NodeIteratorCallback callback, void *handle);
-
-/***********************/
-/* Set Node Attributes */
-/***********************/
+/*************************/
+/* Write Node Attributes */
+/*************************/
 
 /* The following node attributes cannot be changed once the node is created
    - NodeClass
    - NodeId
    - Symmetric
+   - ContainsNoLoop
    
-   The following attributes will eventually be managed by a userrights layer and are unsupported yet
-   - WriteMask
+   The following attributes cannot be written, as there is no "user" in the server
    - UserWriteMask
-   - AccessLevel
    - UserAccessLevel
    - UserExecutable
 
    The following attributes are currently taken from the value variant:
+   TODO: Handle them independent from the variable, ensure that the implicit constraints hold
    - DataType
    - ValueRank
    - ArrayDimensions
@@ -348,104 +368,87 @@ UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
    - Historizing is currently unsupported
   */
 
-UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttribute_value(UA_Server *server, const UA_NodeId nodeId,
-                                 const UA_Variant value);
-
-/* The value is moved into the node (not copied). The value variant is _inited internally. */
-UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttribute_value_move(UA_Server *server, const UA_NodeId nodeId,
-                                      UA_Variant *value);
-
-/* Succeeds only if the node contains a variant value */
-UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttribute_value_callback(UA_Server *server, const UA_NodeId nodeId,
-                                          const UA_ValueCallback callback);
-
-UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttribute_value_dataSource(UA_Server *server, const UA_NodeId nodeId,
-                                            const UA_DataSource dataSource);
-
 /* Don't use this function. There are typed versions with no additional overhead. */
 UA_StatusCode UA_EXPORT
-__UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId,
-                             const UA_DataType *type, const void *value);
+__UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId, const UA_AttributeId attributeId,
+                           const UA_DataType *type, const void *value);
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_browseName(UA_Server *server, const UA_NodeId nodeId,
-                                      const UA_QualifiedName browseName) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME,
-                                        &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); }
+UA_Server_writeBrowseNameAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                   const UA_QualifiedName browseName) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME,
+                                      &UA_TYPES[UA_TYPES_QUALIFIEDNAME], &browseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_displayName(UA_Server *server, const UA_NodeId nodeId,
-                                       const UA_LocalizedText displayName) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
-                                        &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); }
+UA_Server_writeDisplayNameAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                    const UA_LocalizedText displayName) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &displayName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_description(UA_Server *server, const UA_NodeId nodeId,
-                                       const UA_LocalizedText description) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION,
-                                        &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); }
+UA_Server_writeDescriptionAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                    const UA_LocalizedText description) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &description); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_isAbstract(UA_Server *server, const UA_NodeId nodeId,
-                                      const UA_Boolean isAbstract) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT,
-                                        &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); }
+UA_Server_writeWriteMaskAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                  const UA_UInt32 writeMask) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK,
+                                      &UA_TYPES[UA_TYPES_UINT32], &writeMask); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_inverseName(UA_Server *server, const UA_NodeId nodeId,
-                                       const UA_LocalizedText inverseName) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME,
-                                        &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); }
+UA_Server_writeIsAbstractAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                   const UA_Boolean isAbstract) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT,
+                                      &UA_TYPES[UA_TYPES_BOOLEAN], &isAbstract); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_containtsNoLoops(UA_Server *server, const UA_NodeId nodeId,
-                                            const UA_Boolean containsNoLoops) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
-                                        &UA_TYPES[UA_TYPES_BOOLEAN], &containsNoLoops); }
+UA_Server_writeInverseNameAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                    const UA_LocalizedText inverseName) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME,
+                                      &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], &inverseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_eventNotifier(UA_Server *server, const UA_NodeId nodeId,
-                                         const UA_Byte eventNotifier) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
-                                        &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); }
+UA_Server_writeEventNotifierAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                      const UA_Byte eventNotifier) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
+                                      &UA_TYPES[UA_TYPES_BYTE], &eventNotifier); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_minimumSamplingInterval(UA_Server *server, const UA_NodeId nodeId,
-                                                   const UA_Double miniumSamplingInterval) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
-                                        &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval); }
+UA_Server_writeValueAttribute(UA_Server *server, const UA_NodeId nodeId,
+                              const UA_Variant value) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE,
+                                      &UA_TYPES[UA_TYPES_VARIANT], &value); }
 
-static UA_INLINE UA_StatusCode
-UA_Server_setNodeAttribute_executable(UA_Server *server, const UA_NodeId nodeId,
-                                      const UA_Boolean executable) {
-    return __UA_Server_setNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE,
-                                        &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
-
-#ifdef ENABLE_METHODCALLS
+/* The value content is moved into the node (not copied). The input variant is _inited internally. */
 UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId,
-                                  UA_MethodCallback method, void *handle);
-#endif
+UA_Server_writeValueAttribute_move(UA_Server *server, const UA_NodeId nodeId,
+                                   UA_Variant *value);
 
-typedef struct {
-    void * (*constructor)(const UA_NodeId instance); ///< Returns the instance handle attached to the node
-    void (*destructor)(const UA_NodeId instance, void *instanceHandle);
-} UA_ObjectInstanceManagement;
+static UA_INLINE UA_StatusCode
+UA_Server_writeAccessLevelAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                    const UA_UInt32 accessLevel) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
+                                      &UA_TYPES[UA_TYPES_UINT32], &accessLevel); }
 
-UA_StatusCode UA_EXPORT
-UA_Server_setObjectInstanceManagement(UA_Server *server, UA_NodeId nodeId,
-                                      UA_ObjectInstanceManagement oim);
+static UA_INLINE UA_StatusCode
+UA_Server_writeMinimumSamplingIntervalAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                                const UA_Double miniumSamplingInterval) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                                      &UA_TYPES[UA_TYPES_DOUBLE], &miniumSamplingInterval); }
+
+static UA_INLINE UA_StatusCode
+UA_Server_writeExecutableAttribute(UA_Server *server, const UA_NodeId nodeId,
+                                   const UA_Boolean executable) {
+    return __UA_Server_writeAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE,
+                                      &UA_TYPES[UA_TYPES_BOOLEAN], &executable); }
 
-/***********************/
-/* Get Node Attributes */
-/***********************/
+/************************/
+/* Read Node Attributes */
+/************************/
 
-/* The following attributes cannot be read. They make no sense to read internally since the "admin"
-   user always has all rights.
+/* The following attributes cannot be read, since the "admin" user always has all rights.
    - UserWriteMask
    - UserAccessLevel
    - UserExecutable
@@ -453,95 +456,89 @@ UA_Server_setObjectInstanceManagement(UA_Server *server, UA_NodeId nodeId,
 
 /* Don't use this function. There are typed versions for every supported attribute. */
 UA_StatusCode UA_EXPORT
-UA_Server_getNodeAttribute(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void *v);
+__UA_Server_readAttribute(UA_Server *server, UA_NodeId nodeId, UA_AttributeId attributeId, void *v);
   
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_nodeId(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outNodeId) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
+UA_Server_readNodeIdAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outNodeId) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_NODEID, outNodeId); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_nodeClass(UA_Server *server, UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
+UA_Server_readNodeClassAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeClass *outNodeClass) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_NODECLASS, outNodeClass); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_browseName(UA_Server *server, UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
+UA_Server_readBrowseNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_QualifiedName *outBrowseName) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, outBrowseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_displayName(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
+UA_Server_readDisplayNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDisplayName) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DISPLAYNAME, outDisplayName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_description(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDescription) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
+UA_Server_readDescriptionAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outDescription) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DESCRIPTION, outDescription); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_writeMask(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK, outWriteMask); }
+UA_Server_readWriteMaskAttribute(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outWriteMask) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_WRITEMASK, outWriteMask); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_isAbstract(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
+UA_Server_readIsAbstractAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outIsAbstract) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ISABSTRACT, outIsAbstract); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_symmetric(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outSymmetric) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
+UA_Server_readSymmetricAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outSymmetric) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_SYMMETRIC, outSymmetric); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_inverseName(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
+UA_Server_readInverseNameAttribute(UA_Server *server, UA_NodeId nodeId, UA_LocalizedText *outInverseName) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_INVERSENAME, outInverseName); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_containsNoLoops(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
+UA_Server_readContainsNoLoopAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outContainsNoLoops) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS, outContainsNoLoops); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_eventNotifier(UA_Server *server, UA_NodeId nodeId, UA_Byte *outEventNotifier) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
+UA_Server_readEventNotifierAttribute(UA_Server *server, UA_NodeId nodeId, UA_Byte *outEventNotifier) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER, outEventNotifier); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_value(UA_Server *server, UA_NodeId nodeId, UA_Variant *outValue) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
-
-UA_StatusCode UA_EXPORT
-UA_Server_getNodeAttribute_value_dataSource(UA_Server *server, UA_NodeId nodeId, UA_DataSource *dataSource);
+UA_Server_readValueAttribute(UA_Server *server, UA_NodeId nodeId, UA_Variant *outValue) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_VALUE, outValue); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_dataType(UA_Server *server, UA_NodeId nodeId, UA_Variant *outDataType) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
+UA_Server_readDataTypeAttribute(UA_Server *server, UA_NodeId nodeId, UA_NodeId *outDataType) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_DATATYPE, outDataType); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_valueRank(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outValueRank) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
+UA_Server_readValueRankAttribute(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outValueRank) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_VALUERANK, outValueRank); }
 
+// todo: fetch an array with a length field
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_arrayDimensions(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outArrayDimensions) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
+UA_Server_readArrayDimensionsAttribute(UA_Server *server, UA_NodeId nodeId, UA_Int32 *outArrayDimensions) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS, outArrayDimensions); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_accessLevel(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, outAccessLevel); }
+UA_Server_readAccessLevelAttribute(UA_Server *server, UA_NodeId nodeId, UA_UInt32 *outAccessLevel) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_ACCESSLEVEL, outAccessLevel); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_minimumSamplingInterval(UA_Server *server, UA_NodeId nodeId,
-                                                   UA_Double *outMinimumSamplingInterval) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
-                                      outMinimumSamplingInterval); }
+UA_Server_readMinimumSamplingIntervalAttribute(UA_Server *server, UA_NodeId nodeId,
+                                               UA_Double *outMinimumSamplingInterval) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
+                                     outMinimumSamplingInterval); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_historizing(UA_Server *server, UA_NodeId nodeId, UA_Double *outHistorizing) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
+UA_Server_readHistorizingAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outHistorizing) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_HISTORIZING, outHistorizing); }
 
 static UA_INLINE UA_StatusCode
-UA_Server_getNodeAttribute_executable(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outExecutable) {
-    return UA_Server_getNodeAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE, outExecutable); }
-
-#ifdef ENABLE_METHODCALLS
-UA_StatusCode UA_EXPORT
-UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId methodNodeId, UA_MethodCallback *method);
-#endif
+UA_Server_readExecutableAttribute(UA_Server *server, UA_NodeId nodeId, UA_Boolean *outExecutable) {
+    return __UA_Server_readAttribute(server, nodeId, UA_ATTRIBUTEID_EXECUTABLE, outExecutable); }
 
 #ifdef UA_EXTERNAL_NAMESPACES
+
 /**
  * An external application that manages its own data and data model. To plug in
  * outside data sources, one can use

File diff suppressed because it is too large
+ 145 - 746
src/client/ua_client.c


+ 272 - 0
src/client/ua_client_highlevel.c

@@ -0,0 +1,272 @@
+#include "ua_client.h"
+#include "ua_client_highlevel.h"
+#include "ua_types_encoding_binary.h"
+
+UA_StatusCode UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt16 *namespaceIndex){
+	UA_ReadRequest ReadRequest;
+	UA_ReadResponse ReadResponse;
+	UA_StatusCode retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+
+	UA_ReadRequest_init(&ReadRequest);
+    UA_ReadValueId id;
+	id.attributeId = UA_ATTRIBUTEID_VALUE;
+	id.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY);
+	ReadRequest.nodesToRead = &id;
+	ReadRequest.nodesToReadSize = 1;
+
+	ReadResponse = UA_Client_Service_read(client, ReadRequest);
+
+    if(ReadResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD){
+        retval = ReadResponse.responseHeader.serviceResult;
+        goto cleanup;
+    }
+
+    if(ReadResponse.resultsSize != 1 || !ReadResponse.results[0].hasValue){
+        retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
+        goto cleanup;
+    }
+
+    if(ReadResponse.results[0].value.type != &UA_TYPES[UA_TYPES_STRING]){
+        retval = UA_STATUSCODE_BADTYPEMISMATCH;
+        goto cleanup;
+    }
+
+    retval = UA_STATUSCODE_BADNOTFOUND;
+    for(UA_UInt16 iterator = 0; iterator < ReadResponse.results[0].value.arrayLength; iterator++){
+        if(UA_String_equal(namespaceUri, &((UA_String*)ReadResponse.results[0].value.data)[iterator] )){
+            *namespaceIndex = iterator;
+            retval = UA_STATUSCODE_GOOD;
+            break;
+        }
+    }
+
+cleanup:
+    UA_ReadResponse_deleteMembers(&ReadResponse);
+
+	return retval;
+}
+
+
+/*******************/
+/* Node Management */
+/*******************/
+
+UA_StatusCode UA_EXPORT
+UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
+                       UA_Boolean isForward, const UA_String targetServerUri,
+                       const UA_ExpandedNodeId targetNodeId, UA_NodeClass targetNodeClass) {
+    UA_AddReferencesItem item;
+    UA_AddReferencesItem_init(&item);
+    item.sourceNodeId = sourceNodeId;
+    item.referenceTypeId = referenceTypeId;
+    item.isForward = isForward;
+    item.targetServerUri = targetServerUri;
+    item.targetNodeId = targetNodeId;
+    item.targetNodeClass = targetNodeClass;
+    UA_AddReferencesRequest request;
+    UA_AddReferencesRequest_init(&request);
+    request.referencesToAdd = &item;
+    request.referencesToAddSize = 1;
+    UA_AddReferencesResponse response = UA_Client_Service_addReferences(client, request);
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_AddReferencesResponse_deleteMembers(&response);
+        return retval;
+    }
+    if(response.resultsSize != 1) {
+        UA_AddReferencesResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    retval = response.results[0];
+    UA_AddReferencesResponse_deleteMembers(&response);
+    return retval;
+}
+
+UA_StatusCode UA_EXPORT
+UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
+                          UA_Boolean isForward, const UA_ExpandedNodeId targetNodeId,
+                          UA_Boolean deleteBidirectional) {
+    UA_DeleteReferencesItem item;
+    UA_DeleteReferencesItem_init(&item);
+    item.sourceNodeId = sourceNodeId;
+    item.referenceTypeId = referenceTypeId;
+    item.isForward = isForward;
+    item.targetNodeId = targetNodeId;
+    item.deleteBidirectional = deleteBidirectional;
+    UA_DeleteReferencesRequest request;
+    UA_DeleteReferencesRequest_init(&request);
+    request.referencesToDelete = &item;
+    request.referencesToDeleteSize = 1;
+    UA_DeleteReferencesResponse response = UA_Client_Service_deleteReferences(client, request);
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_DeleteReferencesResponse_deleteMembers(&response);
+        return retval;
+    }
+    if(response.resultsSize != 1) {
+        UA_DeleteReferencesResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    retval = response.results[0];
+    UA_DeleteReferencesResponse_deleteMembers(&response);
+    return retval;
+}
+
+UA_StatusCode UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
+                                   UA_Boolean deleteTargetReferences) {
+    UA_DeleteNodesItem item;
+    UA_DeleteNodesItem_init(&item);
+    item.nodeId = nodeId;
+    item.deleteTargetReferences = deleteTargetReferences;
+    UA_DeleteNodesRequest request;
+    UA_DeleteNodesRequest_init(&request);
+    request.nodesToDelete = &item;
+    request.nodesToDeleteSize = 1;
+    UA_DeleteNodesResponse response = UA_Client_Service_deleteNodes(client, request);
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_DeleteNodesResponse_deleteMembers(&response);
+        return retval;
+    }
+    if(response.resultsSize != 1) {
+        UA_DeleteNodesResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    retval = response.results[0];
+    UA_DeleteNodesResponse_deleteMembers(&response);
+    return retval;
+}
+
+UA_StatusCode __UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
+                                  const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
+                                  const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
+                                  const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
+                                  const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_AddNodesRequest request;
+    UA_AddNodesRequest_init(&request);
+    UA_AddNodesItem item;
+    UA_AddNodesItem_init(&item);
+    item.parentNodeId.nodeId = parentNodeId;
+    item.referenceTypeId = referenceTypeId;
+    item.requestedNewNodeId.nodeId = requestedNewNodeId;
+    item.browseName = browseName;
+    item.nodeClass = nodeClass;
+    item.typeDefinition.nodeId = typeDefinition;
+    size_t attributes_length = UA_calcSizeBinary(attr, attributeType);
+    item.nodeAttributes.typeId = attributeType->typeId;
+    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING;
+    retval = UA_ByteString_newMembers(&item.nodeAttributes.body, attributes_length);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+    size_t offset = 0;
+    retval = UA_encodeBinary(attr, attributeType, &item.nodeAttributes.body, &offset);
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ByteString_deleteMembers(&item.nodeAttributes.body);
+        return retval;
+    }
+    request.nodesToAdd = &item;
+    request.nodesToAddSize = 1;
+    UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);
+    UA_ByteString_deleteMembers(&item.nodeAttributes.body);
+    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
+        retval = response.responseHeader.serviceResult;
+        UA_AddNodesResponse_deleteMembers(&response);
+        return retval;
+    }
+    if(response.resultsSize != 1) {
+        UA_AddNodesResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    if(outNewNodeId && response.results[0].statusCode) {
+        *outNewNodeId = response.results[0].addedNodeId;
+        UA_NodeId_init(&response.results[0].addedNodeId);
+    }
+    return response.results[0].statusCode;
+}
+
+/********/
+/* Call */
+/********/
+
+UA_StatusCode
+UA_Client_call(UA_Client *client, const UA_NodeId objectId, const UA_NodeId methodId,
+               UA_Int32 inputSize, const UA_Variant *input, UA_Int32 *outputSize,
+               UA_Variant **output) {
+    UA_CallRequest request;
+    UA_CallRequest_init(&request);
+    UA_CallMethodRequest item;
+    UA_CallMethodRequest_init(&item);
+    item.methodId = methodId;
+    item.objectId = objectId;
+    item.inputArguments = (void*)(uintptr_t)input; // cast const...
+    item.inputArgumentsSize = inputSize;
+    request.methodsToCall = &item;
+    request.methodsToCallSize = 1;
+    UA_CallResponse response = UA_Client_Service_call(client, request);
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_CallResponse_deleteMembers(&response);
+        return retval;
+    }
+    if(response.resultsSize != 1) {
+        UA_CallResponse_deleteMembers(&response);
+        return UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+    retval = response.results[0].statusCode;
+    if(retval == UA_STATUSCODE_GOOD) {
+        *output = response.results[0].outputArguments;
+        *outputSize = response.results[0].outputArgumentsSize;
+        response.results[0].outputArguments = UA_NULL;
+        response.results[0].outputArgumentsSize = -1;
+    }
+    UA_CallResponse_deleteMembers(&response);
+    return retval;
+}
+
+/**************/
+/* Attributes */
+/**************/
+
+UA_StatusCode 
+__UA_Client_readAttribute(UA_Client *client, UA_NodeId nodeId, UA_AttributeId attributeId,
+                          void *out, const UA_DataType *outDataType) {
+    UA_ReadValueId item;
+    UA_ReadValueId_init(&item);
+    item.nodeId = nodeId;
+    item.attributeId = attributeId;
+    UA_ReadRequest request;
+    UA_ReadRequest_init(&request);
+    request.nodesToRead = &item;
+    request.nodesToReadSize = 1;
+    UA_ReadResponse response = UA_Client_Service_read(client, request);
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
+        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ReadResponse_deleteMembers(&response);
+        return retval;
+    }
+    UA_DataValue *res = response.results;
+    if(res->hasStatus != UA_STATUSCODE_GOOD)
+        retval = res->hasStatus;
+    else if(!res->hasValue || !UA_Variant_isScalar(&res->value))
+        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_ReadResponse_deleteMembers(&response);
+        return retval;
+    }
+    if(attributeId == UA_ATTRIBUTEID_VALUE) {
+        UA_memcpy(out, &res->value, sizeof(UA_Variant));
+        UA_Variant_init(&res->value);
+    }
+    else if(res->value.type != outDataType) {
+        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    } else {
+        UA_memcpy(out, res->value.data, res->value.type->memSize);
+        UA_free(res->value.data);
+        res->value.data = UA_NULL;
+    }
+    UA_ReadResponse_deleteMembers(&response);
+    return retval;
+}

+ 313 - 0
src/client/ua_client_highlevel_subscriptions.c

@@ -0,0 +1,313 @@
+#include "ua_client_highlevel.h"
+#include "ua_client_internal.h"
+#include "ua_util.h"
+#include "ua_types_generated_encoding_binary.h"
+
+const UA_SubscriptionSettings UA_SubscriptionSettings_standard = {
+    .requestedPublishingInterval = 0.0,
+    .requestedLifetimeCount = 100,
+    .requestedMaxKeepAliveCount = 10,
+    .maxNotificationsPerPublish = 10,
+    .publishingEnabled = UA_TRUE,
+    .priority = 0
+};
+
+UA_StatusCode UA_Client_Subscriptions_new(UA_Client *client, UA_SubscriptionSettings settings,
+                                          UA_UInt32 *newSubscriptionId) {
+    UA_CreateSubscriptionRequest request;
+    UA_CreateSubscriptionRequest_init(&request);
+    request.requestedPublishingInterval = settings.requestedPublishingInterval;
+    request.requestedLifetimeCount = settings.requestedLifetimeCount;
+    request.requestedMaxKeepAliveCount = settings.requestedMaxKeepAliveCount;
+    request.maxNotificationsPerPublish = settings.maxNotificationsPerPublish;
+    request.publishingEnabled = settings.publishingEnabled;
+    request.priority = settings.priority;
+    
+    UA_CreateSubscriptionResponse response = UA_Client_Service_createSubscription(client, request);
+    UA_StatusCode retval = response.responseHeader.serviceResult;
+    if(retval == UA_STATUSCODE_GOOD) {
+        UA_Client_Subscription *newSub = UA_malloc(sizeof(UA_Client_Subscription));
+        LIST_INIT(&newSub->MonitoredItems);
+        newSub->LifeTime = response.revisedLifetimeCount;
+        newSub->KeepAliveCount = response.revisedMaxKeepAliveCount;
+        newSub->PublishingInterval = response.revisedPublishingInterval;
+        newSub->SubscriptionID = response.subscriptionId;
+        newSub->NotificationsPerPublish = request.maxNotificationsPerPublish;
+        newSub->Priority = request.priority;
+        if(newSubscriptionId)
+            *newSubscriptionId = newSub->SubscriptionID;
+        LIST_INSERT_HEAD(&client->subscriptions, newSub, listEntry);
+    }
+    
+    UA_CreateSubscriptionResponse_deleteMembers(&response);
+    return retval;
+}
+
+UA_StatusCode UA_Client_Subscriptions_remove(UA_Client *client, UA_UInt32 subscriptionId) {
+    UA_Client_Subscription *sub;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    
+    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
+        if(sub->SubscriptionID == subscriptionId)
+            break;
+    }
+    
+    // Problem? We do not have this subscription registeres. Maybe the server should
+    // be consulted at this point?
+    if(!sub)
+        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
+    
+    UA_DeleteSubscriptionsRequest  request;
+    UA_DeleteSubscriptionsRequest_init(&request);
+    request.subscriptionIdsSize = 1;
+    request.subscriptionIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
+    *request.subscriptionIds = sub->SubscriptionID;
+    
+    UA_Client_MonitoredItem *mon, *tmpmon;
+    LIST_FOREACH_SAFE(mon, &sub->MonitoredItems, listEntry, tmpmon) {
+        retval |= UA_Client_Subscriptions_removeMonitoredItem(client, sub->SubscriptionID,
+                                                              mon->MonitoredItemId);
+    }
+    if(retval != UA_STATUSCODE_GOOD){
+	    UA_DeleteSubscriptionsRequest_deleteMembers(&request);
+        return retval;
+    }
+    
+    UA_DeleteSubscriptionsResponse response = UA_Client_Service_deleteSubscriptions(client, request);
+    if(response.resultsSize > 0)
+        retval = response.results[0];
+    else
+        retval = response.responseHeader.serviceResult;
+    
+    if(retval == UA_STATUSCODE_GOOD) {
+        LIST_REMOVE(sub, listEntry);
+        UA_free(sub);
+    }
+    UA_DeleteSubscriptionsRequest_deleteMembers(&request);
+    UA_DeleteSubscriptionsResponse_deleteMembers(&response);
+    return retval;
+}
+
+UA_StatusCode
+UA_Client_Subscriptions_addMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
+                                         UA_NodeId nodeId, UA_UInt32 attributeID,
+                                         void *handlingFunction, UA_UInt32 *newMonitoredItemId) {
+    UA_Client_Subscription *sub;
+    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
+        if(sub->SubscriptionID == subscriptionId)
+            break;
+    }
+    if(!sub)
+        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
+    
+    UA_CreateMonitoredItemsRequest request;
+    UA_CreateMonitoredItemsRequest_init(&request);
+    request.subscriptionId = subscriptionId;
+    UA_MonitoredItemCreateRequest item;
+    UA_MonitoredItemCreateRequest_init(&item);
+    item.itemToMonitor.nodeId = nodeId;
+    item.itemToMonitor.attributeId = attributeID;
+    item.monitoringMode = UA_MONITORINGMODE_REPORTING;
+    item.requestedParameters.clientHandle = ++(client->monitoredItemHandles);
+    item.requestedParameters.samplingInterval = sub->PublishingInterval;
+    item.requestedParameters.discardOldest = UA_TRUE;
+    item.requestedParameters.queueSize = 1;
+    request.itemsToCreate = &item;
+    request.itemsToCreateSize = 1;
+    // Filter can be left void for now, only changes are supported (UA_Expert does the same with changeItems)
+    
+    UA_CreateMonitoredItemsResponse response = UA_Client_Service_createMonitoredItems(client, request);
+    
+    UA_StatusCode retval;
+    // slight misuse of retval here to check if the deletion was successfull.
+    if(response.resultsSize == 0)
+        retval = response.responseHeader.serviceResult;
+    else
+        retval = response.results[0].statusCode;
+    
+    if(retval == UA_STATUSCODE_GOOD) {
+        UA_Client_MonitoredItem *newMon = UA_malloc(sizeof(UA_Client_MonitoredItem));
+        newMon->MonitoringMode = UA_MONITORINGMODE_REPORTING;
+        UA_NodeId_copy(&nodeId, &newMon->monitoredNodeId); 
+        newMon->AttributeID = attributeID;
+        newMon->ClientHandle = client->monitoredItemHandles;
+        newMon->SamplingInterval = sub->PublishingInterval;
+        newMon->QueueSize = 1;
+        newMon->DiscardOldest = UA_TRUE;
+        newMon->handler = handlingFunction;
+        newMon->MonitoredItemId = response.results[0].monitoredItemId;
+        LIST_INSERT_HEAD(&sub->MonitoredItems, newMon, listEntry);
+        *newMonitoredItemId = newMon->MonitoredItemId;
+    }
+    
+    UA_CreateMonitoredItemsResponse_deleteMembers(&response);
+    return retval;
+}
+
+UA_StatusCode
+UA_Client_Subscriptions_removeMonitoredItem(UA_Client *client, UA_UInt32 subscriptionId,
+                                            UA_UInt32 monitoredItemId) {
+    UA_Client_Subscription *sub;
+    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
+        if(sub->SubscriptionID == subscriptionId)
+            break;
+    }
+    if(!sub)
+        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
+    
+    UA_Client_MonitoredItem *mon;
+    LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
+        if(mon->MonitoredItemId == monitoredItemId)
+            break;
+    }
+    if(!mon)
+        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
+    
+    UA_DeleteMonitoredItemsRequest request;
+    UA_DeleteMonitoredItemsRequest_init(&request);
+    request.subscriptionId = sub->SubscriptionID;
+    request.monitoredItemIdsSize = 1;
+    request.monitoredItemIds = (UA_UInt32 *) UA_malloc(sizeof(UA_UInt32));
+    request.monitoredItemIds[0] = mon->MonitoredItemId;
+    
+    UA_DeleteMonitoredItemsResponse response = UA_Client_Service_deleteMonitoredItems(client, request);
+
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(response.resultsSize > 1)
+        retval = response.results[0];
+    else
+        retval = response.responseHeader.serviceResult;
+    
+    if(retval == UA_STATUSCODE_GOOD) {
+        LIST_REMOVE(mon, listEntry);
+        UA_NodeId_deleteMembers(&mon->monitoredNodeId);
+        UA_free(mon);
+    }
+    
+    UA_DeleteMonitoredItemsRequest_deleteMembers(&request);
+    UA_DeleteMonitoredItemsResponse_deleteMembers(&response);
+    return retval;
+}
+
+static UA_Boolean
+UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
+    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
+        return UA_FALSE;
+    
+    // Check if the server has acknowledged any of our ACKS
+    // Note that a list of serverside status codes may be send without valid publish data, i.e. 
+    // during keepalives or no data availability
+    UA_Client_NotificationsAckNumber *tmpAck = client->pendingNotificationsAcks.lh_first;
+    UA_Client_NotificationsAckNumber *nxtAck = tmpAck;
+    for(int i=0; i<response.resultsSize && nxtAck != NULL; i++) {
+        tmpAck = nxtAck;
+        nxtAck = tmpAck->listEntry.le_next;
+        if(response.results[i] == UA_STATUSCODE_GOOD ||
+            response.results[i] == UA_STATUSCODE_BADSEQUENCENUMBERINVALID) {
+            LIST_REMOVE(tmpAck, listEntry);
+            UA_free(tmpAck);
+        }
+    }
+    
+    if(response.subscriptionId == 0)
+        return UA_FALSE;
+    
+    UA_Client_Subscription *sub;
+    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
+        if(sub->SubscriptionID == response.subscriptionId)
+            break;
+    }
+    if(!sub)
+        return UA_FALSE;
+    
+    UA_NotificationMessage msg = response.notificationMessage;
+    UA_DataChangeNotification dataChangeNotification;
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    UA_Client_MonitoredItem *mon;
+    size_t decodingOffset = 0;
+    for(int k = 0; k < msg.notificationDataSize; k++) {
+        if(msg.notificationData[k].encoding == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
+            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
+                msg.notificationData[k].typeId.identifier.numeric == 811 ) {
+                // This is a dataChangeNotification
+                retval |= UA_DataChangeNotification_decodeBinary(&msg.notificationData[k].body,
+                                                                 &decodingOffset, &dataChangeNotification);
+                UA_MonitoredItemNotification *mitemNot;
+                for(int i = 0; i < dataChangeNotification.monitoredItemsSize; i++) {
+                    mitemNot = &dataChangeNotification.monitoredItems[i];
+                    // find this client handle
+                    LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
+                        if(mon->ClientHandle == mitemNot->clientHandle) {
+                            mon->handler(mitemNot->clientHandle, &mitemNot->value);
+                            break;
+                        }
+                    }
+                }
+                UA_DataChangeNotification_deleteMembers(&dataChangeNotification);
+                continue;
+            }
+
+            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
+               msg.notificationData[k].typeId.identifier.numeric == 820 ) {
+                //FIXME: This is a statusChangeNotification (not supported yet)
+                continue;
+            }
+
+            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
+               msg.notificationData[k].typeId.identifier.numeric == 916 ) {
+                //FIXME: This is an EventNotification
+                continue;
+            }
+        }
+    }
+    
+    /* We processed this message, add it to the list of pending acks (but make
+       sure it's not in the list first) */
+    LIST_FOREACH(tmpAck, &client->pendingNotificationsAcks, listEntry) {
+        if(tmpAck->subAck.sequenceNumber == msg.sequenceNumber &&
+            tmpAck->subAck.subscriptionId == response.subscriptionId)
+            break;
+    }
+
+    if(!tmpAck) {
+        tmpAck = UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
+        tmpAck->subAck.sequenceNumber = msg.sequenceNumber;
+        tmpAck->subAck.subscriptionId = sub->SubscriptionID;
+        tmpAck->listEntry.le_next = UA_NULL;
+        tmpAck->listEntry.le_prev = UA_NULL;
+        LIST_INSERT_HEAD(&client->pendingNotificationsAcks, tmpAck, listEntry);
+    }
+    
+    return response.moreNotifications;
+}
+
+void UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
+    UA_Boolean moreNotifications = UA_TRUE;
+    do {
+        UA_PublishRequest request;
+        UA_PublishRequest_init(&request);
+        request.subscriptionAcknowledgementsSize = 0;
+
+        UA_Client_NotificationsAckNumber *ack;
+        LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
+            request.subscriptionAcknowledgementsSize++;
+        request.subscriptionAcknowledgements = UA_malloc(sizeof(UA_SubscriptionAcknowledgement) *
+                                                         request.subscriptionAcknowledgementsSize);
+        
+        int index = 0 ;
+        LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry) {
+            request.subscriptionAcknowledgements[index].sequenceNumber = ack->subAck.sequenceNumber;
+            request.subscriptionAcknowledgements[index].subscriptionId = ack->subAck.subscriptionId;
+            index++;
+        }
+        
+        UA_PublishResponse response = UA_Client_Service_publish(client, request);
+        if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
+            moreNotifications = UA_Client_processPublishRx(client, response);
+        else
+            moreNotifications = UA_FALSE;
+        
+        UA_PublishResponse_deleteMembers(&response);
+        UA_PublishRequest_deleteMembers(&request);
+    } while(moreNotifications == UA_TRUE);
+}

+ 42 - 7
src/client/ua_client_internal.h

@@ -1,9 +1,15 @@
 #ifndef UA_CLIENT_INTERNAL_H_
 #define UA_CLIENT_INTERNAL_H_
 
+#include "ua_securechannel.h"
 #include "queue.h"
 
+/**************************/
+/* Subscriptions Handling */
+/**************************/
+
 #ifdef ENABLE_SUBSCRIPTIONS
+
 typedef struct UA_Client_NotificationsAckNumber_s {
     UA_SubscriptionAcknowledgement subAck;
     LIST_ENTRY(UA_Client_NotificationsAckNumber_s) listEntry;
@@ -33,15 +39,44 @@ typedef struct UA_Client_Subscription_s {
     LIST_HEAD(UA_ListOfClientMonitoredItems, UA_Client_MonitoredItem_s) MonitoredItems;
 } UA_Client_Subscription;
 
-UA_CreateSubscriptionResponse   UA_Client_createSubscription(UA_Client *client, UA_CreateSubscriptionRequest *request);
-UA_ModifySubscriptionResponse   UA_Client_modifySubscription(UA_Client *client, UA_ModifySubscriptionRequest *request);
-UA_DeleteSubscriptionsResponse  UA_Client_deleteSubscriptions(UA_Client *client, UA_DeleteSubscriptionsRequest *request);
-UA_CreateMonitoredItemsResponse UA_Client_createMonitoredItems(UA_Client *client, UA_CreateMonitoredItemsRequest *request);
-UA_DeleteMonitoredItemsResponse UA_Client_deleteMonitoredItems(UA_Client *client, UA_DeleteMonitoredItemsRequest *request);
-UA_PublishResponse              UA_Client_publish(UA_Client *client, UA_PublishRequest *request);
+#endif
+
+/**********/
+/* Client */
+/**********/
 
+typedef enum {
+    UA_CLIENTSTATE_READY,
+    UA_CLIENTSTATE_CONNECTED,
+    UA_CLIENTSTATE_ERRORED
+} UA_Client_State;
 
-UA_Boolean UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response);
+struct UA_Client {
+    /* State */ //maybe it should be visible to user
+    UA_Client_State state;
+
+    /* Connection */
+    UA_Connection connection;
+    UA_SecureChannel channel;
+    UA_String endpointUrl;
+    UA_UInt32 requestId;
+
+    /* Session */
+    UA_UserTokenPolicy token;
+    UA_NodeId sessionId;
+    UA_NodeId authenticationToken;
+    UA_UInt32 requestHandle;
+    
+#ifdef ENABLE_SUBSCRIPTIONS
+    UA_Int32 monitoredItemHandles;
+    LIST_HEAD(UA_ListOfUnacknowledgedNotificationNumbers, UA_Client_NotificationsAckNumber_s) pendingNotificationsAcks;
+    LIST_HEAD(UA_ListOfClientSubscriptionItems, UA_Client_Subscription_s) subscriptions;
 #endif
+    
+    /* Config */
+    UA_Logger logger;
+    UA_ClientConfig config;
+    UA_DateTime scExpiresAt;
+};
 
 #endif /* UA_CLIENT_INTERNAL_H_ */

+ 3 - 2
src/server/ua_nodes.c

@@ -171,7 +171,8 @@ void UA_ObjectTypeNode_init(UA_ObjectTypeNode *p) {
 	UA_Node_init((UA_Node*)p);
     p->nodeClass = UA_NODECLASS_OBJECTTYPE;
     p->isAbstract = UA_FALSE;
-    p->instanceManagement = (UA_ObjectInstanceManagement){.constructor = UA_NULL, .destructor = UA_NULL};
+    p->lifecycleManagement = (UA_ObjectLifecycleManagement)
+        {.constructor = UA_NULL, .destructor = UA_NULL};
 }
 
 UA_ObjectTypeNode * UA_ObjectTypeNode_new(void) {
@@ -192,7 +193,7 @@ void UA_ObjectTypeNode_delete(UA_ObjectTypeNode *p) {
 
 UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
     dst->isAbstract = src->isAbstract;
-    dst->instanceManagement = src->instanceManagement;
+    dst->lifecycleManagement = src->lifecycleManagement;
 	return UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
 }
 

+ 1 - 1
src/server/ua_nodes.h

@@ -48,7 +48,7 @@ UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectNode)
 typedef struct {
     UA_STANDARD_NODEMEMBERS
     UA_Boolean isAbstract;
-    UA_ObjectInstanceManagement instanceManagement;
+    UA_ObjectLifecycleManagement lifecycleManagement;
 } UA_ObjectTypeNode;
 UA_TYPE_HANDLING_FUNCTIONS(UA_ObjectTypeNode)
 

+ 0 - 1
src/server/ua_nodestore.c

@@ -130,7 +130,6 @@ static UA_StatusCode expand(UA_NodeStore *ns) {
 static void deleteEntry(struct nodeEntry *entry) {
     if(entry->refcount > 0)
         return;
-
     switch(entry->node.nodeClass) {
     case UA_NODECLASS_OBJECT:
         UA_ObjectNode_deleteMembers((UA_ObjectNode*)&entry->node);

+ 303 - 359
src/server/ua_server.c

@@ -102,8 +102,22 @@ UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
     return (UA_UInt16)server->namespacesSize - 1;
 }
 
-UA_StatusCode UA_Server_deleteNode(UA_Server *server, UA_NodeId nodeId) {
-    return Service_DeleteNodes_single(server, &adminSession, &nodeId, UA_TRUE);
+UA_StatusCode UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
+                                   UA_Boolean deleteReferences) {
+    return Service_DeleteNodes_single(server, &adminSession, &nodeId, deleteReferences);
+}
+
+UA_StatusCode
+UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId, const UA_NodeId referenceTypeId,
+                          UA_Boolean isForward, const UA_ExpandedNodeId targetNodeId,
+                          UA_Boolean deleteBidirectional) {
+    UA_DeleteReferencesItem item;
+    item.sourceNodeId = sourceNodeId;
+    item.referenceTypeId = referenceTypeId;
+    item.isForward = isForward;
+    item.targetNodeId = targetNodeId;
+    item.deleteBidirectional = deleteBidirectional;
+    return Service_DeleteReferences_single(server, &adminSession, &item);
 }
 
 UA_StatusCode
@@ -224,7 +238,6 @@ void UA_Server_setLogger(UA_Server *server, UA_Logger logger) {
     server->logger = logger;
 }
 
-
 /**********/
 /* Server */
 /**********/
@@ -299,9 +312,9 @@ readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
     }
     
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
-    status->startTime   = ((const UA_Server*)handle)->startTime;
+    status->startTime = ((const UA_Server*)handle)->startTime;
     status->currentTime = UA_DateTime_now();
-    status->state       = UA_SERVERSTATE_RUNNING;
+    status->state = UA_SERVERSTATE_RUNNING;
     getBulidInfo(((const UA_Server*)handle), &status->buildInfo);
     status->secondsTillShutdown = 0;
 
@@ -533,7 +546,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 
     server->startTime = UA_DateTime_now();
     static struct tm ct;
-    ct.tm_year = (__DATE__[7] - '0') * 1000 +  (__DATE__[8] - '0') * 100 +
+    ct.tm_year = (__DATE__[7] - '0') * 1000 + (__DATE__[8] - '0') * 100 +
         (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0')- 1900;
 
     if(__DATE__[0]=='J' && __DATE__[1]=='a' && __DATE__[2]=='n') ct.tm_mon = 1-1;
@@ -554,13 +567,13 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     // this results in a negative number for tm_mday
 
     if(__DATE__[4] == ' ')
-        ct.tm_mday =  __DATE__[5]-'0';
+        ct.tm_mday = __DATE__[5]-'0';
     else
         ct.tm_mday = (__DATE__[4]-'0')*10 + (__DATE__[5]-'0');
     ct.tm_hour = ((__TIME__[0] - '0') * 10 + __TIME__[1] - '0');
     ct.tm_min = ((__TIME__[3] - '0') * 10 + __TIME__[4] - '0');
     ct.tm_sec = ((__TIME__[6] - '0') * 10 + __TIME__[7] - '0');
-    ct.tm_isdst = -1;  // information is not available.
+    ct.tm_isdst = -1; // information is not available.
 
     //FIXME: next 3 lines are copy-pasted from ua_types.c
 #define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
@@ -577,7 +590,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     copyNames((UA_Node*)references, "References");
     references->nodeId.identifier.numeric = UA_NS0ID_REFERENCES;
     references->isAbstract = UA_TRUE;
-    references->symmetric  = UA_TRUE;
+    references->symmetric = UA_TRUE;
     references->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "References");
     /* The reference to root is later inserted */
     UA_NodeStore_insert(server->nodestore, (UA_Node*)references, UA_NULL);
@@ -587,7 +600,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     hassubtype->inverseName = UA_LOCALIZEDTEXT_ALLOC("en_US", "HasSupertype");
     hassubtype->nodeId.identifier.numeric = UA_NS0ID_HASSUBTYPE;
     hassubtype->isAbstract = UA_FALSE;
-    hassubtype->symmetric  = UA_FALSE;
+    hassubtype->symmetric = UA_FALSE;
     /* The reference to root is later inserted */
     UA_NodeStore_insert(server->nodestore, (UA_Node*)hassubtype, UA_NULL);
 
@@ -888,87 +901,89 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     addDataTypeNode(server, "Enumeration", UA_NS0ID_ENUMERATION, UA_NS0ID_BASEDATATYPE);
         addDataTypeNode(server, "ServerState", UA_NS0ID_SERVERSTATE, UA_NS0ID_ENUMERATION);
 
-   UA_ObjectNode *variabletypes = UA_ObjectNode_new();
-   copyNames((UA_Node*)variabletypes, "VariableTypes");
-   variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
-   addNodeInternal(server, (UA_Node*)variabletypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
-                   nodeIdOrganizes);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER),
-                          nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
-   addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE,
-                                 UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
-   addVariableTypeNode_subtype(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
-                               UA_NS0ID_BASEVARIABLETYPE, UA_FALSE);
-   addVariableTypeNode_subtype(server, "PropertyType", UA_NS0ID_PROPERTYTYPE,
-                               UA_NS0ID_BASEVARIABLETYPE, UA_FALSE);
+    UA_ObjectNode *variabletypes = UA_ObjectNode_new();
+    copyNames((UA_Node*)variabletypes, "VariableTypes");
+    variabletypes->nodeId.identifier.numeric = UA_NS0ID_VARIABLETYPESFOLDER;
+    addNodeInternal(server, (UA_Node*)variabletypes, UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER),
+                    nodeIdOrganizes);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_VARIABLETYPESFOLDER),
+                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), UA_TRUE);
+    addVariableTypeNode_organized(server, "BaseVariableType", UA_NS0ID_BASEVARIABLETYPE,
+                                  UA_NS0ID_VARIABLETYPESFOLDER, UA_TRUE);
+    addVariableTypeNode_subtype(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
+                                UA_NS0ID_BASEVARIABLETYPE, UA_FALSE);
+    addVariableTypeNode_subtype(server, "PropertyType", UA_NS0ID_PROPERTYTYPE,
+                                UA_NS0ID_BASEVARIABLETYPE, UA_FALSE);
 #endif
 
 #ifdef ENABLE_GENERATE_NAMESPACE0
-   //load the generated namespace
-   ua_namespaceinit_generated(server);
+    //load the generated namespace
+    ua_namespaceinit_generated(server);
 #endif
 
-   /*********************/
-   /* The Server Object */
-   /*********************/
-
-   UA_ObjectNode *servernode = UA_ObjectNode_new();
-   copyNames((UA_Node*)servernode, "Server");
-   servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
-   addNodeInternal(server, (UA_Node*)servernode, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
-                   nodeIdOrganizes);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasTypeDefinition,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE), UA_TRUE);
-
-   UA_VariableNode *namespaceArray = UA_VariableNode_new();
-   copyNames((UA_Node*)namespaceArray, "NamespaceArray");
-   namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
-   namespaceArray->valueSource = UA_VALUESOURCE_DATASOURCE;
-   namespaceArray->value.dataSource = (UA_DataSource) {.handle = server, .read = readNamespaces,
-                                                       .write = UA_NULL};
-   namespaceArray->valueRank = 1;
-   namespaceArray->minimumSamplingInterval = 1.0;
-   addNodeInternal(server, (UA_Node*)namespaceArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
-                          nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
-
-   UA_VariableNode *serverArray = UA_VariableNode_new();
-   copyNames((UA_Node*)serverArray, "ServerArray");
-   serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
-   serverArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
-   serverArray->value.variant.value.arrayLength = 1;
-   serverArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-   *(UA_String *)serverArray->value.variant.value.data = UA_STRING_ALLOC(server->config.Application_applicationURI);
-   serverArray->valueRank = 1;
-   serverArray->minimumSamplingInterval = 1.0;
-   addNodeInternal(server, (UA_Node*)serverArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), nodeIdHasTypeDefinition,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
-
-   UA_ObjectNode *servercapablities = UA_ObjectNode_new();
-   copyNames((UA_Node*)servercapablities, "ServerCapabilities");
-   servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
-   addNodeInternal(server, (UA_Node*)servercapablities, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                   nodeIdHasComponent);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
-                          nodeIdHasTypeDefinition,
-                          UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE), UA_TRUE);
-
-   UA_VariableNode *localeIdArray = UA_VariableNode_new();
-   copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
-   localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
-   localeIdArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
-   localeIdArray->value.variant.value.arrayLength = 1;
-   localeIdArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-   *(UA_String *)localeIdArray->value.variant.value.data = UA_STRING_ALLOC("en");
-   localeIdArray->valueRank = 1;
-   localeIdArray->minimumSamplingInterval = 1.0;
-   addNodeInternal(server, (UA_Node*)localeIdArray,
-                   UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
-   UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY),
-                          nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
-
-   UA_VariableNode *maxBrowseContinuationPoints = UA_VariableNode_new();
+    /*********************/
+    /* The Server Object */
+    /*********************/
+
+    UA_ObjectNode *servernode = UA_ObjectNode_new();
+    copyNames((UA_Node*)servernode, "Server");
+    servernode->nodeId.identifier.numeric = UA_NS0ID_SERVER;
+    addNodeInternal(server, (UA_Node*)servernode, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                    nodeIdOrganizes);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasTypeDefinition,
+                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERTYPE), UA_TRUE);
+
+    UA_VariableNode *namespaceArray = UA_VariableNode_new();
+    copyNames((UA_Node*)namespaceArray, "NamespaceArray");
+    namespaceArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_NAMESPACEARRAY;
+    namespaceArray->valueSource = UA_VALUESOURCE_DATASOURCE;
+    namespaceArray->value.dataSource = (UA_DataSource) {.handle = server, .read = readNamespaces,
+                                                        .write = UA_NULL};
+    namespaceArray->valueRank = 1;
+    namespaceArray->minimumSamplingInterval = 1.0;
+    addNodeInternal(server, (UA_Node*)namespaceArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
+                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
+                           UA_TRUE);
+
+    UA_VariableNode *serverArray = UA_VariableNode_new();
+    copyNames((UA_Node*)serverArray, "ServerArray");
+    serverArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERARRAY;
+    serverArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+    serverArray->value.variant.value.arrayLength = 1;
+    serverArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    *(UA_String *)serverArray->value.variant.value.data =
+        UA_STRING_ALLOC(server->config.Application_applicationURI);
+    serverArray->valueRank = 1;
+    serverArray->minimumSamplingInterval = 1.0;
+    addNodeInternal(server, (UA_Node*)serverArray, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasProperty);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), nodeIdHasTypeDefinition,
+                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
+
+    UA_ObjectNode *servercapablities = UA_ObjectNode_new();
+    copyNames((UA_Node*)servercapablities, "ServerCapabilities");
+    servercapablities->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES;
+    addNodeInternal(server, (UA_Node*)servercapablities, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
+                    nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES),
+                           nodeIdHasTypeDefinition,
+                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERCAPABILITIESTYPE), UA_TRUE);
+
+    UA_VariableNode *localeIdArray = UA_VariableNode_new();
+    copyNames((UA_Node*)localeIdArray, "LocaleIdArray");
+    localeIdArray->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY;
+    localeIdArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], 1);
+    localeIdArray->value.variant.value.arrayLength = 1;
+    localeIdArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    *(UA_String *)localeIdArray->value.variant.value.data = UA_STRING_ALLOC("en");
+    localeIdArray->valueRank = 1;
+    localeIdArray->minimumSamplingInterval = 1.0;
+    addNodeInternal(server, (UA_Node*)localeIdArray,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES), nodeIdHasProperty);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY),
+                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
+
+    UA_VariableNode *maxBrowseContinuationPoints = UA_VariableNode_new();
     copyNames((UA_Node*)maxBrowseContinuationPoints, "MaxBrowseContinuationPoints");
     maxBrowseContinuationPoints->nodeId.identifier.numeric =
         UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS;
@@ -984,7 +999,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 #define MAX_PROFILEARRAY 16 //a *magic* limit to the number of supported profiles
 #define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING_ALLOC(x)
     UA_String profileArray[MAX_PROFILEARRAY];
-    UA_UInt16  profileArraySize = 0;
+    UA_UInt16 profileArraySize = 0;
     ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NanoEmbeddedDevice");
 
 #ifdef ENABLE_SERVICESET_NODEMANAGEMENT
@@ -1003,9 +1018,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     serverProfileArray->value.variant.value.arrayLength = profileArraySize;
     serverProfileArray->value.variant.value.data = UA_Array_new(&UA_TYPES[UA_TYPES_STRING], profileArraySize);
     serverProfileArray->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-    for(UA_UInt16 i=0;i<profileArraySize;i++){
+    for(UA_UInt16 i=0;i<profileArraySize;i++)
         ((UA_String *)serverProfileArray->value.variant.value.data)[i] = profileArray[i];
-    }
     serverProfileArray->valueRank = 1;
     serverProfileArray->minimumSamplingInterval = 1.0;
     addNodeInternal(server, (UA_Node*)serverProfileArray,
@@ -1022,173 +1036,177 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
                            nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERDIAGNOSTICSTYPE), UA_TRUE);
 
     UA_VariableNode *enabledFlag = UA_VariableNode_new();
-     copyNames((UA_Node*)enabledFlag, "EnabledFlag");
-     enabledFlag->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG;
-     enabledFlag->value.variant.value.data = UA_Boolean_new(); //initialized as false
-     enabledFlag->value.variant.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
-     enabledFlag->valueRank = 1;
-     enabledFlag->minimumSamplingInterval = 1.0;
-     addNodeInternal(server, (UA_Node*)enabledFlag,
-                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), nodeIdHasProperty);
-     UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
-                            nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE), UA_TRUE);
-
-     UA_VariableNode *serverstatus = UA_VariableNode_new();
-      copyNames((UA_Node*)serverstatus, "ServerStatus");
-      serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
-      serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
-      serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus, .write = UA_NULL};
-      addNodeInternal(server, (UA_Node*)serverstatus, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                      nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                             nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE), UA_TRUE);
-
-     UA_VariableNode *starttime = UA_VariableNode_new();
-      copyNames((UA_Node*)starttime, "StartTime");
-      starttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
-      starttime->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
-      starttime->value.variant.value.data = &server->startTime;
-      starttime->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
-      addNodeInternal(server, (UA_Node*)starttime, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                      nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
-                             nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-     UA_VariableNode *currenttime = UA_VariableNode_new();
-      copyNames((UA_Node*)currenttime, "CurrentTime");
-      currenttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
-      currenttime->valueSource = UA_VALUESOURCE_DATASOURCE;
-      currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
-                                                       .write = UA_NULL};
-      addNodeInternal(server, (UA_Node*)currenttime,
-                      UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
-                             nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-     UA_VariableNode *state = UA_VariableNode_new();
-     UA_ServerState *stateEnum = UA_ServerState_new();
-      *stateEnum = UA_SERVERSTATE_RUNNING;
-      copyNames((UA_Node*)state, "State");
-      state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
-      state->value.variant.value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
-      state->value.variant.value.arrayLength = -1;
-      state->value.variant.value.data = stateEnum; // points into the other object.
-      addNodeInternal(server, (UA_Node*)state, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                      nodeIdHasComponent);
-      UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE),
-                             nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-      UA_VariableNode *buildinfo = UA_VariableNode_new();
-       copyNames((UA_Node*)buildinfo, "BuildInfo");
-       buildinfo->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO);
-       buildinfo->value.variant.value.data = UA_BuildInfo_new();
-       buildinfo->value.variant.value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
-       getBulidInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
-       addNodeInternal(server, (UA_Node*)buildinfo,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
-                              nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE), UA_TRUE);
-
-       UA_VariableNode *producturi = UA_VariableNode_new();
-       copyNames((UA_Node*)producturi, "ProductUri");
-       producturi->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI);
-       producturi->value.variant.value.data = UA_String_new();
-       *((UA_String*)producturi->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_URI);
-       producturi->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       addNodeInternal(server, (UA_Node*)producturi,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-       UA_VariableNode *manufacturername = UA_VariableNode_new();
-       copyNames((UA_Node*)manufacturername, "ManufacturererName");
-       manufacturername->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME);
-       manufacturername->value.variant.value.data = UA_String_new();
-       *((UA_String*)manufacturername->value.variant.value.data) = UA_STRING_ALLOC(MANUFACTURER_NAME);
-       manufacturername->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       addNodeInternal(server, (UA_Node*)manufacturername,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server,
-                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-       UA_VariableNode *productname = UA_VariableNode_new();
-       copyNames((UA_Node*)productname, "ProductName");
-       productname->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME);
-       productname->value.variant.value.data = UA_String_new();
-       *((UA_String*)productname->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_NAME);
-       productname->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       addNodeInternal(server, (UA_Node*)productname,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-       UA_VariableNode *softwareversion = UA_VariableNode_new();
-       copyNames((UA_Node*)softwareversion, "SoftwareVersion");
-       softwareversion->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION);
-       softwareversion->value.variant.value.data = UA_String_new();
-       *((UA_String*)softwareversion->value.variant.value.data) = UA_STRING_ALLOC(SOFTWARE_VERSION);
-       softwareversion->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       addNodeInternal(server, (UA_Node*)softwareversion,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server,
-                              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-       UA_VariableNode *buildnumber = UA_VariableNode_new();
-       copyNames((UA_Node*)buildnumber, "BuildNumber");
-       buildnumber->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER);
-       buildnumber->value.variant.value.data = UA_String_new();
-       *((UA_String*)buildnumber->value.variant.value.data) = UA_STRING_ALLOC(BUILD_NUMBER);
-       buildnumber->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
-       addNodeInternal(server, (UA_Node*)buildnumber,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-       UA_VariableNode *builddate = UA_VariableNode_new();
-       copyNames((UA_Node*)builddate, "BuildDate");
-       builddate->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE);
-       builddate->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
-       builddate->value.variant.value.data = &server->buildDate;
-       builddate->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
-       addNodeInternal(server, (UA_Node*)builddate,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-       UA_VariableNode *secondstillshutdown = UA_VariableNode_new();
-       copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
-       secondstillshutdown->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN);
-       secondstillshutdown->value.variant.value.data = UA_UInt32_new();
-       secondstillshutdown->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT32];
-       addNodeInternal(server, (UA_Node*)secondstillshutdown,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-       UA_VariableNode *shutdownreason = UA_VariableNode_new();
-       copyNames((UA_Node*)shutdownreason, "ShutdownReason");
-       shutdownreason->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON);
-       shutdownreason->value.variant.value.data = UA_LocalizedText_new();
-       shutdownreason->value.variant.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
-       addNodeInternal(server, (UA_Node*)shutdownreason,
-                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
-       UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),
-                              nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
-
-   return server;
+    copyNames((UA_Node*)enabledFlag, "EnabledFlag");
+    enabledFlag->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG;
+    enabledFlag->value.variant.value.data = UA_Boolean_new(); //initialized as false
+    enabledFlag->value.variant.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
+    enabledFlag->valueRank = 1;
+    enabledFlag->minimumSamplingInterval = 1.0;
+    addNodeInternal(server, (UA_Node*)enabledFlag,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS), nodeIdHasProperty);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
+                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
+                           UA_TRUE);
+
+    UA_VariableNode *serverstatus = UA_VariableNode_new();
+    copyNames((UA_Node*)serverstatus, "ServerStatus");
+    serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
+    serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
+    serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus, .write = UA_NULL};
+    addNodeInternal(server, (UA_Node*)serverstatus, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
+                    nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE),
+                           UA_TRUE);
+
+    UA_VariableNode *starttime = UA_VariableNode_new();
+    copyNames((UA_Node*)starttime, "StartTime");
+    starttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
+    starttime->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
+    starttime->value.variant.value.data = &server->startTime;
+    starttime->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
+    addNodeInternal(server, (UA_Node*)starttime, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+                    nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *currenttime = UA_VariableNode_new();
+    copyNames((UA_Node*)currenttime, "CurrentTime");
+    currenttime->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
+    currenttime->valueSource = UA_VALUESOURCE_DATASOURCE;
+    currenttime->value.dataSource = (UA_DataSource) {.handle = NULL, .read = readCurrentTime,
+                                                     .write = UA_NULL};
+    addNodeInternal(server, (UA_Node*)currenttime,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *state = UA_VariableNode_new();
+    UA_ServerState *stateEnum = UA_ServerState_new();
+    *stateEnum = UA_SERVERSTATE_RUNNING;
+    copyNames((UA_Node*)state, "State");
+    state->nodeId.identifier.numeric = UA_NS0ID_SERVER_SERVERSTATUS_STATE;
+    state->value.variant.value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
+    state->value.variant.value.arrayLength = -1;
+    state->value.variant.value.data = stateEnum; // points into the other object.
+    addNodeInternal(server, (UA_Node*)state, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
+                    nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *buildinfo = UA_VariableNode_new();
+    copyNames((UA_Node*)buildinfo, "BuildInfo");
+    buildinfo->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO);
+    buildinfo->value.variant.value.data = UA_BuildInfo_new();
+    buildinfo->value.variant.value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
+    getBulidInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
+    addNodeInternal(server, (UA_Node*)buildinfo,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),
+                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_BUILDINFOTYPE),
+                           UA_TRUE);
+
+    UA_VariableNode *producturi = UA_VariableNode_new();
+    copyNames((UA_Node*)producturi, "ProductUri");
+    producturi->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI);
+    producturi->value.variant.value.data = UA_String_new();
+    *((UA_String*)producturi->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_URI);
+    producturi->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    addNodeInternal(server, (UA_Node*)producturi,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *manufacturername = UA_VariableNode_new();
+    copyNames((UA_Node*)manufacturername, "ManufacturererName");
+    manufacturername->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME);
+    manufacturername->value.variant.value.data = UA_String_new();
+    *((UA_String*)manufacturername->value.variant.value.data) = UA_STRING_ALLOC(MANUFACTURER_NAME);
+    manufacturername->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    addNodeInternal(server, (UA_Node*)manufacturername,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+    UA_Server_addReference(server,
+                           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *productname = UA_VariableNode_new();
+    copyNames((UA_Node*)productname, "ProductName");
+    productname->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME);
+    productname->value.variant.value.data = UA_String_new();
+    *((UA_String*)productname->value.variant.value.data) = UA_STRING_ALLOC(PRODUCT_NAME);
+    productname->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    addNodeInternal(server, (UA_Node*)productname,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *softwareversion = UA_VariableNode_new();
+    copyNames((UA_Node*)softwareversion, "SoftwareVersion");
+    softwareversion->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION);
+    softwareversion->value.variant.value.data = UA_String_new();
+    *((UA_String*)softwareversion->value.variant.value.data) = UA_STRING_ALLOC(SOFTWARE_VERSION);
+    softwareversion->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    addNodeInternal(server, (UA_Node*)softwareversion,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *buildnumber = UA_VariableNode_new();
+    copyNames((UA_Node*)buildnumber, "BuildNumber");
+    buildnumber->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER);
+    buildnumber->value.variant.value.data = UA_String_new();
+    *((UA_String*)buildnumber->value.variant.value.data) = UA_STRING_ALLOC(BUILD_NUMBER);
+    buildnumber->value.variant.value.type = &UA_TYPES[UA_TYPES_STRING];
+    addNodeInternal(server, (UA_Node*)buildnumber,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *builddate = UA_VariableNode_new();
+    copyNames((UA_Node*)builddate, "BuildDate");
+    builddate->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE);
+    builddate->value.variant.value.storageType = UA_VARIANT_DATA_NODELETE;
+    builddate->value.variant.value.data = &server->buildDate;
+    builddate->value.variant.value.type = &UA_TYPES[UA_TYPES_DATETIME];
+    addNodeInternal(server, (UA_Node*)builddate,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *secondstillshutdown = UA_VariableNode_new();
+    copyNames((UA_Node*)secondstillshutdown, "SecondsTillShutdown");
+    secondstillshutdown->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN);
+    secondstillshutdown->value.variant.value.data = UA_UInt32_new();
+    secondstillshutdown->value.variant.value.type = &UA_TYPES[UA_TYPES_UINT32];
+    addNodeInternal(server, (UA_Node*)secondstillshutdown,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+
+    UA_VariableNode *shutdownreason = UA_VariableNode_new();
+    copyNames((UA_Node*)shutdownreason, "ShutdownReason");
+    shutdownreason->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON);
+    shutdownreason->value.variant.value.data = UA_LocalizedText_new();
+    shutdownreason->value.variant.value.type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
+    addNodeInternal(server, (UA_Node*)shutdownreason,
+                    UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON),
+                           nodeIdHasTypeDefinition, expandedNodeIdBaseDataVariabletype, UA_TRUE);
+    return server;
 }
 
 UA_StatusCode
-__UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId nodeId,
+__UA_Server_writeAttribute(UA_Server *server, const UA_NodeId nodeId,
                              const UA_AttributeId attributeId, const UA_DataType *type,
                              const void *value) {
     UA_WriteValue wvalue;
     UA_WriteValue_init(&wvalue);
     wvalue.nodeId = nodeId;
     wvalue.attributeId = attributeId;
-    UA_Variant_setScalarCopy(&wvalue.value.value, value, type);
+    if(attributeId != UA_ATTRIBUTEID_VALUE)
+        UA_Variant_setScalarCopy(&wvalue.value.value, value, type);
+    else
+        UA_Variant_copy(value, &wvalue.value.value);
     wvalue.value.hasValue = UA_TRUE;
     UA_StatusCode retval = Service_Write_single(server, &adminSession, &wvalue);
     UA_NodeId_init(&wvalue.nodeId);
@@ -1197,25 +1215,7 @@ __UA_Server_setNodeAttribute(UA_Server *server, const UA_NodeId nodeId,
 }
 
 UA_StatusCode
-UA_Server_setNodeAttribute_value(UA_Server *server, const UA_NodeId nodeId,
-                                 const UA_Variant value) {
-    UA_WriteValue wvalue;
-    UA_WriteValue_init(&wvalue);
-    wvalue.nodeId = nodeId;
-    wvalue.attributeId = UA_ATTRIBUTEID_VALUE;
-    UA_StatusCode retval = UA_Variant_copy(&value, &wvalue.value.value);
-    if(retval != UA_STATUSCODE_GOOD)
-        return retval;
-    wvalue.value.hasValue = UA_TRUE;
-    retval = Service_Write_single(server, &adminSession, &wvalue);
-    UA_NodeId_init(&wvalue.nodeId);
-    UA_WriteValue_deleteMembers(&wvalue);
-    return retval;
-}
-
-UA_StatusCode
-UA_Server_setNodeAttribute_value_move(UA_Server *server, const UA_NodeId nodeId,
-                                      UA_Variant *value) {
+UA_Server_writeValueAttribute_move(UA_Server *server, const UA_NodeId nodeId, UA_Variant *value) {
     UA_WriteValue wvalue;
     UA_WriteValue_init(&wvalue);
     wvalue.nodeId = nodeId;
@@ -1229,53 +1229,25 @@ UA_Server_setNodeAttribute_value_move(UA_Server *server, const UA_NodeId nodeId,
     return retval;
 }
 
-#ifdef ENABLE_METHODCALLS
-struct methodAndHandle {
-    UA_MethodCallback method;
-    void *handle;
-};
-
-static UA_StatusCode replaceMethod(UA_Server *server, UA_Session *session, UA_MethodNode *node,
-                                   const struct methodAndHandle *mah) {
-
-    if(node->nodeClass != UA_NODECLASS_METHOD)
-        return UA_STATUSCODE_BADNODECLASSINVALID;
-    node->attachedMethod = mah->method;
-    node->methodHandle   = mah->handle;
-    return UA_STATUSCODE_GOOD;
-}
-
-UA_StatusCode
-UA_Server_setNodeAttribute_method(UA_Server *server, const UA_NodeId methodNodeId,
-                                  UA_MethodCallback method, void *handle) {
-    struct methodAndHandle mah;
-    mah.method = method;
-    mah.handle = handle;
-    return UA_Server_editNode(server, &adminSession, &methodNodeId,
-                              (UA_EditNodeCallback)replaceMethod, &mah);
-}
-#endif
-
 static UA_StatusCode setValueCallback(UA_Server *server, UA_Session *session, UA_VariableNode *node,
                                       UA_ValueCallback *callback) {
-    if(node->nodeClass != UA_NODECLASS_VARIABLE &&
-       node->nodeClass != UA_NODECLASS_VARIABLETYPE)
+    if(node->nodeClass != UA_NODECLASS_VARIABLE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
     node->value.variant.callback = *callback;
     return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode UA_EXPORT
-UA_Server_setNodeAttribute_value_callback(UA_Server *server, const UA_NodeId nodeId,
-                                          const UA_ValueCallback callback) {
+UA_Server_setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
+                                        const UA_ValueCallback callback) {
     return UA_Server_editNode(server, &adminSession, &nodeId,
                               (UA_EditNodeCallback)setValueCallback, &callback);
 }
 
 static UA_StatusCode
-setDataSource(UA_Server *server, UA_Session *session, UA_VariableNode* node, UA_DataSource *dataSource) {
-    if(node->nodeClass != UA_NODECLASS_VARIABLE &&
-       node->nodeClass != UA_NODECLASS_VARIABLETYPE)
+setDataSource(UA_Server *server, UA_Session *session,
+              UA_VariableNode* node, UA_DataSource *dataSource) {
+    if(node->nodeClass != UA_NODECLASS_VARIABLE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
     if(node->valueSource == UA_VALUESOURCE_VARIANT)
         UA_Variant_deleteMembers(&node->value.variant.value);
@@ -1285,83 +1257,55 @@ setDataSource(UA_Server *server, UA_Session *session, UA_VariableNode* node, UA_
 }
 
 UA_StatusCode
-UA_Server_setNodeAttribute_value_dataSource(UA_Server *server, const UA_NodeId nodeId,
-                                            const UA_DataSource dataSource) {
+UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
+                                     const UA_DataSource dataSource) {
     return UA_Server_editNode(server, &adminSession, &nodeId,
                               (UA_EditNodeCallback)setDataSource, &dataSource);
 }
 
 static UA_StatusCode
-setObjectManagement(UA_Server *server, UA_Session *session, UA_ObjectTypeNode* node,
-                    UA_ObjectInstanceManagement *oim) {
+setObjectTypeLifecycleManagement(UA_Server *server, UA_Session *session, UA_ObjectTypeNode* node,
+                                 UA_ObjectLifecycleManagement *olm) {
     if(node->nodeClass != UA_NODECLASS_OBJECTTYPE)
         return UA_STATUSCODE_BADNODECLASSINVALID;
-    node->instanceManagement = *oim;
+    node->lifecycleManagement = *olm;
     return UA_STATUSCODE_GOOD;
 }
 
 UA_StatusCode UA_EXPORT
-UA_Server_setObjectInstanceManagement(UA_Server *server, UA_NodeId nodeId,
-                                      UA_ObjectInstanceManagement oim) {
+UA_Server_setObjectTypeNode_instanceLifecycleManagement(UA_Server *server, UA_NodeId nodeId,
+                                                        UA_ObjectLifecycleManagement olm) {
     return UA_Server_editNode(server, &adminSession, &nodeId,
-                              (UA_EditNodeCallback)setObjectManagement, &oim);
+                              (UA_EditNodeCallback)setObjectTypeLifecycleManagement, &olm);
 }
 
 UA_StatusCode
-UA_Server_getNodeAttribute(UA_Server *server, const UA_NodeId nodeId,
-                           const UA_AttributeId attributeId, void *v) {
-    UA_Variant out;
-    UA_Variant_init(&out);
-    UA_StatusCode retval;
-    retval = UA_Server_getNodeAttribute(server, nodeId, attributeId, &out); 
-    if(retval != UA_STATUSCODE_GOOD)
+__UA_Server_readAttribute(UA_Server *server, const UA_NodeId nodeId,
+                          const UA_AttributeId attributeId, void *v) {
+    UA_ReadValueId item;
+    UA_ReadValueId_init(&item);
+    item.nodeId = nodeId;
+    item.attributeId = attributeId;
+    UA_DataValue dv;
+    UA_DataValue_init(&dv);
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER,
+                        &item, &dv);
+    UA_StatusCode retval = UA_STATUSCODE_GOOD;
+    if(dv.hasStatus)
+        retval = dv.hasStatus;
+    else if(!dv.hasValue)
+        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    if(retval != UA_STATUSCODE_GOOD) {
+        UA_DataValue_deleteMembers(&dv);
         return retval;
+    }
     if(attributeId == UA_ATTRIBUTEID_VALUE)
-        UA_memcpy(v, &out, sizeof(UA_Variant));
+        UA_memcpy(v, &dv.value, sizeof(UA_Variant));
     else {
-        UA_memcpy(v, out.data, out.type->memSize);
-        out.data = UA_NULL;
-        out.arrayLength = -1;
-        UA_Variant_deleteMembers(&out);
+        UA_memcpy(v, dv.value.data, dv.value.type->memSize);
+        dv.value.data = UA_NULL;
+        dv.value.arrayLength = -1;
+        UA_Variant_deleteMembers(&dv.value);
     }
     return UA_STATUSCODE_GOOD;
 }
-
-#ifdef ENABLE_METHODCALLS
-UA_StatusCode
-UA_Server_getNodeAttribute_method(UA_Server *server, UA_NodeId nodeId,
-                                  UA_MethodCallback *method) {
-    const UA_Node *node = UA_NodeStore_get(server->nodestore, &nodeId);
-    if(!node)
-        return UA_STATUSCODE_BADNODEIDUNKNOWN;
-    
-    if(node->nodeClass != UA_NODECLASS_METHOD) {
-        UA_NodeStore_release(node);
-        return UA_STATUSCODE_BADNODECLASSINVALID;
-    }
-
-    *method = ((const UA_MethodNode*)node)->attachedMethod;
-    UA_NodeStore_release(node);
-    return UA_STATUSCODE_GOOD;
-}
-#endif
-
-UA_StatusCode
-UA_Server_getNodeAttribute_value_dataSource(UA_Server *server, UA_NodeId nodeId,
-                                            UA_DataSource *dataSource) {
-    const UA_VariableNode *node =
-        (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, &nodeId);
-    if(!node)
-        return UA_STATUSCODE_BADNODEIDUNKNOWN;
-
-    if((node->nodeClass != UA_NODECLASS_VARIABLE &&
-        node->nodeClass != UA_NODECLASS_VARIABLETYPE) ||
-       node->valueSource != UA_VALUESOURCE_DATASOURCE) {
-        UA_NodeStore_release((const UA_Node*)node);
-        return UA_STATUSCODE_BADNODECLASSINVALID;
-    }
-
-    *dataSource = node->value.dataSource;
-    UA_NodeStore_release((const UA_Node*)node);
-    return UA_STATUSCODE_GOOD;
-}

+ 1 - 1
src/server/ua_services.h

@@ -119,7 +119,7 @@ UA_StatusCode Service_AddReferences_single(UA_Server *server, UA_Session *sessio
 /** Used to delete one or more Nodes from the AddressSpace. */
 void Service_DeleteNodes(UA_Server *server, UA_Session *session, const UA_DeleteNodesRequest *request,
                          UA_DeleteNodesResponse *response);
-UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId *nodeId,
+UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                                          UA_Boolean deleteReferences);
 
 /** Used to delete one or more References of a Node. */

+ 57 - 17
src/server/ua_services_nodemanagement.c

@@ -151,7 +151,7 @@ copyExistingVariable(UA_Server *server, UA_Session *session, const UA_NodeId *va
     return UA_STATUSCODE_GOOD;
 }
 
-/* copy an existing variable under the given parent. then instantiate the
+/* copy an existing object under the given parent. then instantiate the
    variable for all hastypedefinitions of the original version. */
 static UA_StatusCode
 copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *variable,
@@ -204,7 +204,16 @@ copyExistingObject(UA_Server *server, UA_Session *session, const UA_NodeId *vari
 }
 
 static UA_StatusCode
-instantiateObjectNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+setObjectInstanceHandle(UA_Server *server, UA_Session *session, UA_ObjectNode* node, void *handle) {
+    if(node->nodeClass != UA_NODECLASS_OBJECT)
+        return UA_STATUSCODE_BADNODECLASSINVALID;
+    node->instanceHandle = handle;
+    return UA_STATUSCODE_GOOD;
+}
+
+static UA_StatusCode
+instantiateObjectNode(UA_Server *server, UA_Session *session,
+                      const UA_NodeId *nodeId, const UA_NodeId *typeId) {
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -245,7 +254,6 @@ instantiateObjectNode(UA_Server *server, UA_Session *session, const UA_NodeId *n
         else if(rd->nodeClass == UA_NODECLASS_OBJECT)
             copyExistingObject(server, session, &rd->nodeId.nodeId, &rd->referenceTypeId, nodeId);
     }
-    UA_NodeStore_release((const UA_Node*)type);
 
     /* add a hastypedefinition reference */
     UA_AddReferencesItem addref;
@@ -258,18 +266,17 @@ instantiateObjectNode(UA_Server *server, UA_Session *session, const UA_NodeId *n
     Service_AddReferences_single(server, session, &addref);
 
     /* call the constructor */
-    /* void *instanceHandle = */
-    /*     ((const UA_ObjectTypeNode*)parent)->instanceManagement.constructor(result->addedNodeId); */
-    /* UA_Server_editNode(server, session, &result->addedNodeId, */
-    /*             (UA_EditNodeCallback)setInstanceHandle, instanceHandle); */
-    /* UA_NodeStore_release(parent); */
-    /* return; */
-    
+    const UA_ObjectLifecycleManagement *olm = &type->lifecycleManagement;
+    if(olm->constructor)
+        UA_Server_editNode(server, session, nodeId,
+                           (UA_EditNodeCallback)setObjectInstanceHandle, olm->constructor(*nodeId));
+    UA_NodeStore_release((const UA_Node*)type);
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode
-instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, const UA_NodeId *typeId) {
+instantiateVariableNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                        const UA_NodeId *typeId) {
     const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, typeId);
     if(!type)
         return UA_STATUSCODE_BADNODEIDINVALID;
@@ -461,9 +468,11 @@ void Service_AddNodes_single(UA_Server *server, UA_Session *session, UA_AddNodes
     /* instantiate if it has a type */
     if(!UA_NodeId_isNull(&item->typeDefinition.nodeId)) {
         if(item->nodeClass == UA_NODECLASS_OBJECT)
-            result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
+            result->statusCode = instantiateObjectNode(server, session, &result->addedNodeId,
+                                                       &item->typeDefinition.nodeId);
         else if(item->nodeClass == UA_NODECLASS_VARIABLE)
-            result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId, &item->typeDefinition.nodeId);
+            result->statusCode = instantiateVariableNode(server, session, &result->addedNodeId,
+                                                         &item->typeDefinition.nodeId);
     }
 
     /* if instantiation failed, remove the node */
@@ -830,7 +839,7 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 
 // TODO: Check consistency constraints, remove the references.
 
-UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, UA_NodeId *nodeId,
+UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                                          UA_Boolean deleteReferences) {
     const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
     if(!node)
@@ -839,15 +848,46 @@ UA_StatusCode Service_DeleteNodes_single(UA_Server *server, UA_Session *session,
         UA_DeleteReferencesItem delItem;
         UA_DeleteReferencesItem_init(&delItem);
         delItem.deleteBidirectional = UA_FALSE;
-        UA_NodeId_copy(nodeId, &delItem.targetNodeId.nodeId);
+        delItem.targetNodeId.nodeId = *nodeId;
         for(int i = 0; i < node->referencesSize; i++) {
             delItem.sourceNodeId = node->references[i].targetId.nodeId;
             delItem.isForward = node->references[i].isInverse;
             Service_DeleteReferences_single(server, session, &delItem);
         }
-        UA_NodeId_init(&delItem.sourceNodeId);
-        UA_DeleteReferencesItem_deleteMembers(&delItem);
     }
+
+    /* destroy an object before removing it */
+    if(node->nodeClass == UA_NODECLASS_OBJECT) {
+        /* find the object type(s) */
+        UA_BrowseDescription bd;
+        UA_BrowseDescription_init(&bd);
+        bd.browseDirection = UA_BROWSEDIRECTION_INVERSE;
+        bd.nodeId = *nodeId;
+        bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
+        bd.includeSubtypes = UA_TRUE;
+        bd.nodeClassMask = UA_NODECLASS_OBJECTTYPE;
+        
+        /* browse type definitions with admin rights */
+        UA_BrowseResult result;
+        UA_BrowseResult_init(&result);
+        Service_Browse_single(server, &adminSession, UA_NULL, &bd, UA_UINT32_MAX, &result);
+        for(int i = 0; i < result.referencesSize; i++) {
+            /* call the destructor */
+            UA_ReferenceDescription *rd = &result.references[i];
+            const UA_ObjectTypeNode *type = (const UA_ObjectTypeNode*)UA_NodeStore_get(server->nodestore, &rd->nodeId.nodeId);
+            if(!type)
+                continue;
+            if(type->nodeClass != UA_NODECLASS_OBJECTTYPE || !type->lifecycleManagement.destructor) {
+                UA_NodeStore_release((const UA_Node*)type);
+                continue;
+            }
+            /* if there are several types with lifecycle management, call all the destructors */
+            type->lifecycleManagement.destructor(*nodeId, ((const UA_ObjectNode*)node)->instanceHandle);
+            UA_NodeStore_release((const UA_Node*)type);
+        }
+        UA_BrowseResult_deleteMembers(&result);
+    }
+    
     UA_NodeStore_release(node);
     return UA_NodeStore_remove(server->nodestore, nodeId);
 }

+ 4 - 0
src/server/ua_services_view.c

@@ -292,6 +292,10 @@ Service_Browse_single(UA_Server *server, UA_Session *session, struct Continuatio
     UA_UInt32 real_maxrefs = maxrefs;
     if(real_maxrefs == 0)
         real_maxrefs = node->referencesSize;
+    if(node->referencesSize <= 0)
+        real_maxrefs = 0;
+    else if(real_maxrefs > (UA_UInt32)node->referencesSize)
+        real_maxrefs = node->referencesSize;
     result->references = UA_malloc(sizeof(UA_ReferenceDescription) * real_maxrefs);
     if(!result->references) {
         result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;

+ 8 - 3
tools/generate_datatypes.py

@@ -60,9 +60,14 @@ minimal_types = ["InvalidType", "Node", "NodeClass", "ReferenceNode", "Applicati
                  "DeleteReferencesItem", "DeleteReferencesRequest", "DeleteReferencesResponse",
                  "RegisterNodesRequest", "RegisterNodesResponse", "UnregisterNodesRequest", "UnregisterNodesResponse", 
                  "UserIdentityToken", "UserNameIdentityToken", "AnonymousIdentityToken", "ServiceFault",
-                 "CallMethodRequest", "CallMethodResult", "CallResponse", "CallRequest", "Argument"]
-
-subscription_types = ["DeleteMonitoredItemsRequest", "DeleteMonitoredItemsResponse", "NotificationMessage",
+                 "CallMethodRequest", "CallMethodResult", "CallResponse", "CallRequest", "Argument",
+                 "FilterOperator", "ContentFilterElement", "ContentFilter", "QueryDataDescription",
+                 "NodeTypeDescription", "QueryFirstRequest", "QueryDataSet", "ParsingResult",
+                 "ContentFilterElementResult", "ContentFilterResult", "QueryFirstResponse",
+                 "QueryNextRequest", "QueryNextResponse"]
+
+subscription_types = ["CreateSubscriptionRequest", "CreateSubscriptionResponse",
+                      "DeleteMonitoredItemsRequest", "DeleteMonitoredItemsResponse", "NotificationMessage",
                       "MonitoredItemNotification", "DataChangeNotification", "ModifySubscriptionRequest",
                       "ModifySubscriptionResponse"]