Selaa lähdekoodia

Merge branch 'master' into feature/architectures

Jose Cabral 5 vuotta sitten
vanhempi
commit
49fa7cc4a0

+ 34 - 16
CMakeLists.txt

@@ -121,16 +121,30 @@ option(UA_ENABLE_SUBSCRIPTIONS "Enable subscriptions support." ON)
 option(UA_ENABLE_SUBSCRIPTIONS_EVENTS "Enable the use of events. (EXPERIMENTAL)" OFF)
 option(UA_ENABLE_DISCOVERY "Enable Discovery Service (LDS)" ON)
 option(UA_ENABLE_DISCOVERY_MULTICAST "Enable Discovery Service with multicast support (LDS-ME)" OFF)
+option(UA_ENABLE_QUERY "Enable query support." OFF)
 option(UA_ENABLE_COVERAGE "Enable gcov coverage" OFF)
+option(UA_ENABLE_ENCRYPTION "Enable encryption support (uses mbedTLS)" OFF)
 option(BUILD_SHARED_LIBS "Enable building of shared libraries (dll/so)" OFF)
 
-# It should not be possible to enable events without enabling subscriptions and full ns0
-if ((UA_ENABLE_SUBSCRIPTIONS_EVENTS) AND (NOT (UA_ENABLE_SUBSCRIPTIONS AND UA_ENABLE_FULL_NS0)))
-    message(FATAL_ERROR "Unable to enable events without UA_ENABLE_SUBSCRIPTIONS and UA_ENABLE_FULL_NS0")
+# Namespace Zero
+set(UA_NAMESPACE_ZERO "REDUCED" CACHE STRING "Completeness of the generated namespace zero (minimal/reduced/full)")
+SET_PROPERTY(CACHE UA_NAMESPACE_ZERO PROPERTY STRINGS "MINIMAL" "REDUCED" "FULL")
+if(UA_NAMESPACE_ZERO STREQUAL "MINIMAL")
+    set(UA_GENERATED_NAMESPACE_ZERO OFF)
+else()
+    set(UA_GENERATED_NAMESPACE_ZERO ON)
 endif()
 
-# Encryption Options
-option(UA_ENABLE_ENCRYPTION "Enable encryption support (uses mbedTLS)" OFF)
+if(MSVC AND UA_NAMESPACE_ZERO STREQUAL "FULL")
+    # For the full NS0 we need a stack size of 8MB (as it is default on linux)
+    # See https://github.com/open62541/open62541/issues/1326
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8000000")
+endif()
+
+# It should not be possible to enable events without enabling subscriptions and full ns0
+if((UA_ENABLE_SUBSCRIPTIONS_EVENTS) AND (NOT (UA_ENABLE_SUBSCRIPTIONS AND UA_NAMESPACE_ZERO STREQUAL "FULL")))
+    message(FATAL_ERROR "Unable to enable events without UA_ENABLE_SUBSCRIPTIONS and full namespace 0")
+endif()
 
 if(UA_ENABLE_COVERAGE)
   set(CMAKE_BUILD_TYPE DEBUG)
@@ -188,14 +202,7 @@ mark_as_advanced(UA_ENABLE_VALGRIND_INTERACTIVE)
 option(UA_MSVC_FORCE_STATIC_CRT "Force linking with the static C-runtime library when compiling to static library with MSVC" ON)
 mark_as_advanced(UA_MSVC_FORCE_STATIC_CRT)
 
-option(UA_ENABLE_FULL_NS0 "Use the full NS0 instead of a minimal Namespace 0 nodeset" OFF)
-if (MSVC AND UA_ENABLE_FULL_NS0)
-    # For the full NS0 we need a stack size of 8MB (as it is default on linux)
-    # See https://github.com/open62541/open62541/issues/1326
-    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8000000")
-endif()
-
-option(UA_FILE_NS0 "Custom NodeSet file containing NS0")
+option(UA_FILE_NS0 "Override the NodeSet xml file used to generate namespace zero")
 mark_as_advanced(UA_FILE_NS0)
 
 # Semaphores/file system may not be available on embedded devices. It can be
@@ -549,7 +556,7 @@ endif()
 # Generate source files #
 #########################
 
-if (UA_ENABLE_FULL_NS0)
+if(UA_NAMESPACE_ZERO STREQUAL "FULL")
     if(NOT UA_FILE_NS0)
         set(UA_FILE_NS0 ${PROJECT_SOURCE_DIR}/deps/ua-nodeset/Schema/Opc.Ua.NodeSet2.xml)
     endif()
@@ -570,12 +577,23 @@ else()
         list(APPEND UA_FILE_DATATYPES ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_method.txt)
     endif()
 
+    if(UA_ENABLE_SUBSCRIPTIONS)
+        list(APPEND UA_FILE_DATATYPES ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_subscriptions.txt)
+    endif()
+
     if(UA_ENABLE_DISCOVERY)
         list(APPEND UA_FILE_DATATYPES ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_discovery.txt)
     endif()
 
-    if(UA_ENABLE_PUBSUB_INFORMATIONMODEL)
-        set(UA_FILE_NSPUBSUB --xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.NodeSet2.PubSubMinimal.xml)
+    if(UA_ENABLE_QUERY)
+        list(APPEND UA_FILE_DATATYPES ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_query.txt)
+    endif()
+
+    if(UA_ENABLE_PUBSUB)
+        list(APPEND UA_FILE_DATATYPES ${PROJECT_SOURCE_DIR}/tools/schema/datatypes_pubsub.txt)
+        if(UA_ENABLE_PUBSUB_INFORMATIONMODEL)
+            set(UA_FILE_NSPUBSUB --xml ${PROJECT_SOURCE_DIR}/tools/schema/Opc.Ua.NodeSet2.PubSubMinimal.xml)
+        endif()
     endif()
 endif()
 

+ 66 - 29
doc/building.rst

@@ -132,8 +132,8 @@ Most options can be changed manually in :file:`ua_config.h` (:file:`open62541.h`
 for the single-file release) after the code generation. But usually there is no
 need to adjust them.
 
-Build Type and Logging
-^^^^^^^^^^^^^^^^^^^^^^
+Main Build Options
+^^^^^^^^^^^^^^^^^^
 
 **CMAKE_BUILD_TYPE**
   - ``RelWithDebInfo`` -O2 optimization with debug symbols
@@ -152,62 +152,81 @@ Build Type and Logging
      - 200: Debug
      - 100: Trace
 
-UA_BUILD_* group
-^^^^^^^^^^^^^^^^
+Select build artefacts
+^^^^^^^^^^^^^^^^^^^^^^
 
-By default only the shared object libopen62541.so or the library open62541.dll
-and open62541.dll.a resp. open62541.lib are build. Additional artifacts can be
-specified by the following options:
+By default only the main library shared object libopen62541.so (open62541.dll)
+or static linking archive open62541.a (open62541.lib) is built. Additional
+artifacts can be specified by the following options:
 
 **UA_BUILD_EXAMPLES**
-   Compile example servers and clients from :file:`examples/{xyz}.c`. A static and a dynamic binary is linked, respectively.
+   Compile example servers and clients from :file:`examples/*.c`.
 
 **UA_BUILD_UNIT_TESTS**
-   Compile unit tests with Check framework. The tests can be executed with ``make test``
-
-**UA_BUILD_EXAMPLES_NODESET_COMPILER**
-   Generate an OPC UA information model from a nodeset XML (experimental)
+   Compile unit tests. The tests can be executed with ``make test``
 
 **UA_BUILD_SELFSIGNED_CERTIFICATE**
    Generate a self-signed certificate for the server (openSSL required)
 
-UA_ENABLE_* group
-^^^^^^^^^^^^^^^^^
-
-This group contains build options related to the supported OPC UA features.
+Detailed SDK Features
+^^^^^^^^^^^^^^^^^^^^^
 
 **UA_ENABLE_SUBSCRIPTIONS**
    Enable subscriptions
+
 **UA_ENABLE_SUBSCRIPTIONS_EVENTS**
     Enable the use of events for subscriptions. This is a new feature and currently marked as EXPERIMENTAL.
+
 **UA_ENABLE_METHODCALLS**
    Enable the Method service set
+
 **UA_ENABLE_NODEMANAGEMENT**
    Enable dynamic addition and removal of nodes at runtime
+
 **UA_ENABLE_AMALGAMATION**
    Compile a single-file release into the files :file:`open62541.c` and :file:`open62541.h`
+
 **UA_ENABLE_MULTITHREADING**
    Enable multi-threading support
+
 **UA_ENABLE_IMMUTABLE_NODES**
-   Nodes in the information model are not edited but copied and replaced. The replacement is done with atomic operations so that the information model is always consistent and can be accessed from an interrupt or parallel thread (depends on the node storage plugin implementation). This feature is a prerequisite for ``UA_ENABLE_MULTITHREADING``.
+   Nodes in the information model are not edited but copied and replaced. The
+   replacement is done with atomic operations so that the information model is
+   always consistent and can be accessed from an interrupt or parallel thread
+   (depends on the node storage plugin implementation). This feature is a
+   prerequisite for ``UA_ENABLE_MULTITHREADING``.
+
 **UA_ENABLE_COVERAGE**
    Measure the coverage of unit tests
 
+**UA_NAMESPACE_ZERO**
+
+   Namespace zero contains the standard-defined nodes. The full namespace zero
+   may not be required for all applications. The selectable options are as follows:
+
+   - ``MINIMAL``: A barebones namespace zero that is compatible with most
+     clients. But this namespace 0 is so small that it does not pass the CTT
+     (Conformance Testing Tools of the OPC Foundation).
+   - ``REDUCED``: Small namespace zero that passes the CTT.
+   - ``FULL``: Full namespace zero generated from the official XML definitions.
+
+   The advanced build option ``UA_FILE_NS0`` can be used to override the XML
+   file used for namespace zero generation.
+
 Some options are marked as advanced. The advanced options need to be toggled to
 be visible in the cmake GUIs.
 
 **UA_ENABLE_TYPENAMES**
    Add the type and member names to the UA_DataType structure. Enabled by default.
+
 **UA_ENABLE_STATUSCODE_DESCRIPTIONS**
    Compile the human-readable name of the StatusCodes into the binary. Enabled by default.
-**UA_ENABLE_GENERATE_NAMESPACE0**
-   Generate and load UA XML Namespace 0 definition
-   ``UA_GENERATE_NAMESPACE0_FILE`` is used to specify the file for NS0 generation from namespace0 folder. Default value is ``Opc.Ua.NodeSet2.xml``
+
 **UA_ENABLE_NONSTANDARD_UDP**
    Enable udp extension
 
-UA_DEBUG_* group
-^^^^^^^^^^^^^^^^
+Debug Build Options
+^^^^^^^^^^^^^^^^^^^
 
 This group contains build options mainly useful for development of the library itself.
 
@@ -231,15 +250,33 @@ Minimizing the binary size
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 The size of the generated binary can be reduced considerably by adjusting the
-build configuration. First, in CMake, the build type can be set to
-``CMAKE_BUILD_TYPE=MinSizeRel``. This sets the compiler flags to minimize the
-binary size. The build type also strips out debug information. Second, the
-binary size can be reduced by removing features via the build-flags described
-above.
+build configuration. With open2541, it is possible to configure minimal servers
+that require less than 100kB of RAM and ROM.
 
-Especially, logging takes up a lot of space in the binary and might not be
+The following options influence the ROM requirements:
+
+First, in CMake, the build type can be set to ``CMAKE_BUILD_TYPE=MinSizeRel``.
+This sets the compiler flags to minimize the binary size. The build type also
+strips out debug information. Second, the binary size can be reduced by removing
+features via the build-flags described above.
+
+Second, setting ``UA_NAMESPACE_ZERO`` to ``MINIMAL`` reduces the size of the
+builtin information model. Setting this option can reduce the binary size by
+half in some cases.
+
+Third, some features might not be needed and can be disabled to reduce the
+binary footprint. Examples for this are Subscriptions or encrypted
+communication.
+
+Last, logging messages take up a lot of space in the binary and might not be
 needed in embedded scenarios. Setting ``UA_LOGLEVEL`` to a value above 600
-(=FATAL) disables all logging. In addition, the feature-flags
+(``FATAL``) disables all logging. In addition, the feature-flags
 ``UA_ENABLE_TYPENAMES`` and ``UA_ENABLE_STATUSCODE_DESCRIPTIONS`` add static
 information to the binary that is only used for human-readable logging and
 debugging.
+
+The RAM requirements of a server are mostly due to the following settings:
+
+- The size of the information model
+- The number of connected clients
+- The configured maximum message size that is preallocated

+ 6 - 2
examples/client_async.c

@@ -70,9 +70,10 @@ attrWritten (UA_Client *client, void *userdata, UA_UInt32 requestId,
 }
 
 #ifdef NODES_EXIST
+#ifdef UA_ENABLE_METHODCALLS
 static void
-methodCalled (UA_Client *client, void *userdata, UA_UInt32 requestId,
-              UA_CallResponse *response) {
+methodCalled(UA_Client *client, void *userdata, UA_UInt32 requestId,
+             UA_CallResponse *response) {
 
     printf ("%-50s%i\n", "Called method for request ", requestId);
     size_t outputSize;
@@ -116,6 +117,7 @@ translateCalled (UA_Client *client, void *userdata, UA_UInt32 requestId,
     }
     UA_TranslateBrowsePathsToNodeIdsResponse_deleteMembers (response);
 }
+#endif /* UA_ENABLE_METHODCALLS */
 #endif
 
 int
@@ -188,6 +190,7 @@ main (int argc, char *argv[]) {
 
 //TODO: check the existance of the nodes inside these functions (otherwise seg faults)
 #ifdef NODES_EXIST
+#ifdef UA_ENABLE_METHODCALLS
             UA_String stringValue = UA_String_fromChars ("World");
             UA_Variant_setScalar (&input, &stringValue, &UA_TYPES[UA_TYPES_STRING]);
 
@@ -206,6 +209,7 @@ main (int argc, char *argv[]) {
                                                           pathSize,
                                                           translateCalled, NULL,
                                                           &reqId);
+#endif /* UA_ENABLE_METHODCALLS */
 #endif
             /* How often UA_Client_run_iterate is called depends on the number of request sent */
             UA_Client_run_iterate(client, 0);

+ 4 - 0
include/ua_client.h

@@ -353,6 +353,8 @@ UA_Client_Service_unregisterNodes(UA_Client *client,
 /*
  * Query Service Set
  * ^^^^^^^^^^^^^^^^^ */
+#ifdef UA_ENABLE_QUERY
+
 static UA_INLINE UA_QueryFirstResponse
 UA_Client_Service_queryFirst(UA_Client *client,
                              const UA_QueryFirstRequest request) {
@@ -371,6 +373,8 @@ UA_Client_Service_queryNext(UA_Client *client,
     return response;
 }
 
+#endif
+
 /**
  * .. _client-async-services:
  *

+ 2 - 0
include/ua_client_highlevel.h

@@ -395,10 +395,12 @@ UA_Client_writeUserExecutableAttribute(UA_Client *client, const UA_NodeId nodeId
 /**
  * Method Calling
  * ^^^^^^^^^^^^^^ */
+#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT
 UA_Client_call(UA_Client *client, const UA_NodeId objectId,
                const UA_NodeId methodId, size_t inputSize, const UA_Variant *input,
                size_t *outputSize, UA_Variant **output);
+#endif
 
 /**
  * Node Management

+ 9 - 6
include/ua_client_highlevel_async.h

@@ -8,8 +8,9 @@
 #define UA_CLIENT_HIGHLEVEL_ASYNC_H_
 #include "ua_client.h"
 
-/*Raw Services
- * ^^^^^^^^^^^^^^ */
+/**
+ * Raw Services
+ * ^^^^^^^^^^^^ */
 typedef void (*UA_ClientAsyncReadCallback)(UA_Client *client, void *userdata,
 		UA_UInt32 requestId, UA_ReadResponse *rr);
 static UA_INLINE UA_StatusCode UA_Client_sendAsyncReadRequest(UA_Client *client,
@@ -467,7 +468,7 @@ static UA_INLINE UA_StatusCode UA_Client_writeUserExecutableAttribute_async(
 /**
  * Method Calling
  * ^^^^^^^^^^^^^^ */
-
+#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode UA_EXPORT __UA_Client_call_async(UA_Client *client,
 		const UA_NodeId objectId, const UA_NodeId methodId, size_t inputSize,
 		const UA_Variant *input, UA_ClientAsyncServiceCallback callback,
@@ -475,17 +476,19 @@ UA_StatusCode UA_EXPORT __UA_Client_call_async(UA_Client *client,
 
 typedef void (*UA_ClientAsyncCallCallback)(UA_Client *client, void *userdata,
 		UA_UInt32 requestId, UA_CallResponse *cr);
+
 static UA_INLINE UA_StatusCode UA_Client_call_async(UA_Client *client,
 		const UA_NodeId objectId, const UA_NodeId methodId, size_t inputSize,
 		const UA_Variant *input, UA_ClientAsyncCallCallback callback,
 		void *userdata, UA_UInt32 *reqId) {
-
 	return __UA_Client_call_async(client, objectId, methodId, inputSize, input,
 			(UA_ClientAsyncServiceCallback) callback, userdata, reqId);
 }
+#endif
 
-/*Node Management
- * ^^^^^^^^^^^^^*/
+/**
+ * Node Management
+ * ^^^^^^^^^^^^^^^ */
 typedef void (*UA_ClientAsyncAddNodesCallback)(UA_Client *client,
 		void *userdata, UA_UInt32 requestId, UA_AddNodesResponse *ar);
 

+ 2 - 0
include/ua_config.h.in

@@ -49,10 +49,12 @@ extern "C" {
 #cmakedefine UA_ENABLE_NONSTANDARD_UDP
 #cmakedefine UA_ENABLE_DISCOVERY
 #cmakedefine UA_ENABLE_DISCOVERY_MULTICAST
+#cmakedefine UA_ENABLE_QUERY
 #cmakedefine UA_ENABLE_DISCOVERY_SEMAPHORE
 #cmakedefine UA_ENABLE_UNIT_TEST_FAILURE_HOOKS
 #cmakedefine UA_ENABLE_VALGRIND_INTERACTIVE
 #define UA_VALGRIND_INTERACTIVE_INTERVAL ${UA_VALGRIND_INTERACTIVE_INTERVAL}
+#cmakedefine UA_GENERATED_NAMESPACE_ZERO
 
 /* Options for Debugging */
 #cmakedefine UA_DEBUG

+ 4 - 0
include/ua_plugin_pubsub.h

@@ -14,6 +14,8 @@ extern "C" {
 
 #include "ua_server_pubsub.h"
 
+#ifdef UA_ENABLE_PUBSUB
+
 /**
  * .. _pubsub_connection:
  *
@@ -86,6 +88,8 @@ typedef struct UA_PubSubTransportLayer{
     UA_PubSubChannel * (*createPubSubChannel)(UA_PubSubConnectionConfig *connectionConfig);
 } UA_PubSubTransportLayer;
 
+#endif /* UA_ENABLE_PUBSUB */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 4 - 0
include/ua_server.h

@@ -795,6 +795,8 @@ UA_Server_setVariableNode_valueCallback(UA_Server *server,
  * also be registered locally. Notifications are then forwarded to a
  * user-defined callback instead of a remote client. */
 
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+
 typedef void (*UA_Server_DataChangeNotificationCallback)
     (UA_Server *server, UA_UInt32 monitoredItemId, void *monitoredItemContext,
      const UA_NodeId *nodeId, void *nodeContext, UA_UInt32 attributeId,
@@ -835,6 +837,8 @@ UA_Server_createDataChangeMonitoredItem(UA_Server *server,
 UA_StatusCode UA_EXPORT
 UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId);
 
+#endif
+
 /**
  * Method Callbacks
  * ^^^^^^^^^^^^^^^^

+ 4 - 0
include/ua_server_pubsub.h

@@ -14,6 +14,8 @@ extern "C" {
 
 #include "ua_server.h"
 
+#ifdef UA_ENABLE_PUBSUB
+
 /**
  * .. _pubsub:
  *
@@ -344,6 +346,8 @@ UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dsw,
 
 UA_StatusCode
 UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw);
+
+#endif /* UA_ENABLE_PUBSUB */
     
 #ifdef __cplusplus
 } // extern "C"

+ 3 - 1
src/client/ua_client_highlevel.c

@@ -604,7 +604,8 @@ __UA_Client_addNode_async(UA_Client *client, const UA_NodeClass nodeClass,
 
 }
 
-/*Misc Highlevel Functions*/
+/* Misc Highlevel Functions */
+#ifdef UA_ENABLE_METHODCALLS
 UA_StatusCode __UA_Client_call_async(UA_Client *client,
         const UA_NodeId objectId, const UA_NodeId methodId, size_t inputSize,
         const UA_Variant *input, UA_ClientAsyncServiceCallback callback,
@@ -625,6 +626,7 @@ UA_StatusCode __UA_Client_call_async(UA_Client *client,
             &UA_TYPES[UA_TYPES_CALLREQUEST], callback,
             &UA_TYPES[UA_TYPES_CALLRESPONSE], userdata, reqId);
 }
+#endif
 
 UA_StatusCode __UA_Client_translateBrowsePathsToNodeIds_async(UA_Client *client,
         char *paths[], UA_UInt32 ids[], size_t pathSize,

+ 14 - 4
src/pubsub/ua_pubsub.c

@@ -6,13 +6,15 @@
  */
 
 #include "ua_types_encoding_binary.h"
-#include "ua_server_pubsub.h"
 #include "server/ua_server_internal.h"
+
+#ifdef UA_ENABLE_PUBSUB /* conditional compilation */
+
+#include "ua_server_pubsub.h"
 #include "ua_pubsub.h"
 #include "ua_pubsub_manager.h"
 #include "ua_pubsub_networkmessage.h"
 
-#ifdef UA_ENABLE_PUBSUB /* conditional compilation */
 #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
 #include "ua_pubsub_ns0.h"
 #endif
@@ -1001,7 +1003,9 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
     memset(dsmStore, 0, sizeof(UA_DataSetMessage) * writerGroup->writersCount);
     //The binary DataSetMessage sizes are part of the payload. Memory is allocated on the stack.
     UA_STACKARRAY(UA_UInt16, dsmSizes, writerGroup->writersCount);
+    UA_STACKARRAY(UA_UInt16, dsWriterIds, writerGroup->writersCount);
     memset(dsmSizes, 0, writerGroup->writersCount * sizeof(UA_UInt16));
+    memset(dsWriterIds, 0, writerGroup->writersCount * sizeof(UA_UInt16));
     /*
      * Calculate the number of needed NetworkMessages. The previous allocated DataSetMessage array is
      * filled from left for combined DSM messages and from the right for single DSM.
@@ -1031,6 +1035,7 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
                 UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Publish failed. DataSetMessage creation failed");
                 return;
             };
+            dsWriterIds[(writerGroup->writersCount - 1) - singleNetworkMessagesCount] = tmpDataSetWriter->config.dataSetWriterId;
             dsmSizes[(writerGroup->writersCount-1) - singleNetworkMessagesCount] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsmStore[(writerGroup->writersCount-1)
                                                                                                                                           - singleNetworkMessagesCount]);
             singleNetworkMessagesCount++;
@@ -1039,6 +1044,7 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
                 UA_LOG_ERROR(server->config.logger, UA_LOGCATEGORY_SERVER, "Publish failed. DataSetMessage creation failed");
                 return;
             };
+            dsWriterIds[combinedNetworkMessageCount] = tmpDataSetWriter->config.dataSetWriterId;
             dsmSizes[combinedNetworkMessageCount] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsmStore[combinedNetworkMessageCount]);
             combinedNetworkMessageCount++;
         }
@@ -1057,6 +1063,7 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
     for(UA_UInt32 i = 0; i < networkMessageCount; i++) {
         nmStore[i].version = 1;
         nmStore[i].networkMessageType = UA_NETWORKMESSAGE_DATASET;
+        nmStore[i].payloadHeaderEnabled = UA_TRUE;
         //create combined NetworkMessages
         if(i < (networkMessageCount-singleNetworkMessagesCount)){
             if(combinedNetworkMessageCount - (i * writerGroup->config.maxEncapsulatedDataSetMessageCount)){
@@ -1070,11 +1077,13 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
                 //nmStore[i].payloadHeader.dataSetPayloadHeader.count = (UA_Byte) writerGroup->config.maxEncapsulatedDataSetMessageCount;
                 nmStore[i].payload.dataSetPayload.dataSetMessages = &dsmStore[currentDSMPosition];
                 nmStore->payload.dataSetPayload.sizes = &dsmSizes[currentDSMPosition];
+                nmStore->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = &dsWriterIds[currentDSMPosition];
             } else {
                 currentDSMPosition = i * writerGroup->config.maxEncapsulatedDataSetMessageCount;
                 nmStore[i].payloadHeader.dataSetPayloadHeader.count = (UA_Byte) (currentDSMPosition - ((i - 1) * writerGroup->config.maxEncapsulatedDataSetMessageCount)); //attention cast from uint32 to byte
                 nmStore[i].payload.dataSetPayload.dataSetMessages = &dsmStore[currentDSMPosition];
                 nmStore->payload.dataSetPayload.sizes = &dsmSizes[currentDSMPosition];
+                nmStore->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = &dsWriterIds[currentDSMPosition];
             }
         } else {///create single NetworkMessages (1 DSM per NM)
             nmStore[i].payloadHeader.dataSetPayloadHeader.count = 1;
@@ -1082,6 +1091,7 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
                                                                             + (combinedNetworkMessageCount % writerGroup->config.maxEncapsulatedDataSetMessageCount) == 0 ? 0 : 1);
             nmStore[i].payload.dataSetPayload.dataSetMessages = &dsmStore[currentDSMPosition];
             nmStore->payload.dataSetPayload.sizes = &dsmSizes[currentDSMPosition];
+            nmStore->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = &dsWriterIds[currentDSMPosition];
         }
         UA_PubSubConnection *connection = UA_PubSubConnection_findConnectionbyId(server, writerGroup->linkedConnection);
         if(!connection){
@@ -1101,9 +1111,9 @@ UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
             };
             connection->channel->send(connection->channel, NULL, &buf);
         }
-        nmStore[i].payloadHeaderEnabled = UA_TRUE;
-        //The stack allocated sizes field must be set to NULL to prevent invalid free.
+        //The stack allocated sizes and dataSetWriterIds field must be set to NULL to prevent invalid free.
         nmStore[i].payload.dataSetPayload.sizes = NULL;
+        nmStore->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = NULL;
         UA_ByteString_deleteMembers(&buf);
         UA_NetworkMessage_deleteMembers(&nmStore[i]);
     }

+ 4 - 0
src/pubsub/ua_pubsub.h

@@ -18,6 +18,8 @@ extern "C" {
 #include "ua_server.h"
 #include "ua_server_pubsub.h"
 
+#ifdef UA_ENABLE_PUBSUB /* conditional compilation */
+
 //forward declarations
 struct UA_WriterGroup;
 typedef struct UA_WriterGroup UA_WriterGroup;
@@ -152,6 +154,8 @@ UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup
 void
 UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup);
 
+#endif /* UA_ENABLE_PUBSUB */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 4 - 0
src/pubsub/ua_pubsub_manager.h

@@ -15,6 +15,8 @@ extern "C" {
 #include "ua_pubsub.h"
 #include "ua_server_pubsub.h"
 
+#ifdef UA_ENABLE_PUBSUB /* conditional compilation */
+
 typedef struct UA_PubSubManager{
     //Connections and PublishedDataSets can exist alone (own lifecycle) -> top level components
     size_t connectionsSize;
@@ -44,6 +46,8 @@ UA_PubSubManager_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 cal
 UA_StatusCode
 UA_PubSubManager_removeRepeatedPubSubCallback(UA_Server *server, UA_UInt64 callbackId);
 
+#endif /* UA_ENABLE_PUBSUB */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 2 - 1
src/pubsub/ua_pubsub_networkmessage.c

@@ -6,7 +6,6 @@
  */
 
 #include "ua_types.h"
-#include "ua_pubsub_networkmessage.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated_encoding_binary.h"
@@ -14,6 +13,8 @@
 
 #ifdef UA_ENABLE_PUBSUB /* conditional compilation */
 
+#include "ua_pubsub_networkmessage.h"
+
 const UA_Byte NM_VERSION_MASK = 15;
 const UA_Byte NM_PUBLISHER_ID_ENABLED_MASK = 16;
 const UA_Byte NM_GROUP_HEADER_ENABLED_MASK = 32;

+ 11 - 0
src/pubsub/ua_pubsub_ns0.h

@@ -15,26 +15,37 @@ extern "C" {
 #include "server/ua_server_internal.h"
 #include "ua_pubsub.h"
 
+#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */
+
 UA_StatusCode
 UA_Server_initPubSubNS0(UA_Server *server);
 
 UA_StatusCode
 addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection);
+
 UA_StatusCode
 removePubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection);
+
 UA_StatusCode
 addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);
+
 UA_StatusCode
 removeWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);
+
 UA_StatusCode
 addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter);
+
 UA_StatusCode
 removeDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter);
+
 UA_StatusCode
 addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet);
+
 UA_StatusCode
 removePublishedDataSetRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet);
 
+#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 16 - 7
src/server/ua_server_internal.h

@@ -261,6 +261,12 @@ getTypeHierarchy(UA_Nodestore *ns, const UA_NodeId *leafType,
  * on the stack and returned. */
 const UA_Node * getNodeType(UA_Server *server, const UA_Node *node);
 
+/* Write a node attribute with a defined session */
+UA_StatusCode
+UA_Server_writeWithSession(UA_Server *server, UA_Session *session,
+                           const UA_WriteValue *value);
+
+
 /* Many services come as an array of operations. This function generalizes the
  * processing of the operations. */
 typedef void (*UA_ServiceOperation)(UA_Server *server, UA_Session *session,
@@ -375,15 +381,18 @@ UA_Discovery_removeRecord(UA_Server *server, const UA_String *servername,
 
 /* Creates a new node in the nodestore. */
 UA_StatusCode
-Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
-                        const UA_AddNodesItem *item, const UA_NodeId *parentNodeId,
-                        const UA_NodeId *referenceTypeId,
-                        UA_NodeId *outNewNodeId);
+AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
+            const UA_AddNodesItem *item, UA_NodeId *outNewNodeId);
+
+/* Check the reference to the parent node; Add references. */
+UA_StatusCode
+AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                const UA_NodeId *typeDefinitionId);
 
-/* Children, references, type-checking, constructors. */
+/* Type-check type-definition; Run the constructors */
 UA_StatusCode
-Operation_addNode_finish(UA_Server *server, UA_Session *session,
-                         const UA_NodeId *nodeId);
+AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId);
 
 /**********************/
 /* Create Namespace 0 */

+ 195 - 199
src/server/ua_server_ns0.c

@@ -15,15 +15,10 @@
 #include "ua_subscription.h"
 #include "ua_session.h"
 
-
-/*****************/
-/* Node Creation */
-/*****************/
-
 static UA_StatusCode
-addNode_begin(UA_Server *server, UA_NodeClass nodeClass,
-              UA_UInt32 nodeId, char *name, void *attributes,
-              const UA_DataType *attributesType) {
+addNode_raw(UA_Server *server, UA_NodeClass nodeClass,
+            UA_UInt32 nodeId, char *name, void *attributes,
+            const UA_DataType *attributesType) {
     UA_AddNodesItem item;
     UA_AddNodesItem_init(&item);
     item.nodeClass = nodeClass;
@@ -32,46 +27,19 @@ addNode_begin(UA_Server *server, UA_NodeClass nodeClass,
     item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
     item.nodeAttributes.content.decoded.data = attributes;
     item.nodeAttributes.content.decoded.type = attributesType;
-    UA_NodeId parentNode = UA_NODEID_NULL;
-    UA_NodeId referenceType = UA_NODEID_NULL;
-    return Operation_addNode_begin(server, &adminSession, NULL, &item, &parentNode, &referenceType, NULL);
+    return AddNode_raw(server, &adminSession, NULL, &item, NULL);
 }
 
 static UA_StatusCode
 addNode_finish(UA_Server *server, UA_UInt32 nodeId,
                UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId) {
-    UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId);
-    UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId);
-    UA_ExpandedNodeId targetId = UA_EXPANDEDNODEID_NUMERIC(0, parentNodeId);
+    const UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId);
+    const UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId);
+    const UA_ExpandedNodeId targetId = UA_EXPANDEDNODEID_NUMERIC(0, parentNodeId);
     UA_StatusCode retval = UA_Server_addReference(server, sourceId, refTypeId, targetId, UA_FALSE);
     if (retval != UA_STATUSCODE_GOOD)
         return retval;
-
-
-    UA_NodeId node = UA_NODEID_NUMERIC(0, nodeId);
-    return Operation_addNode_finish(server, &adminSession, &node);
-}
-
-static UA_StatusCode
-addDataTypeNode(UA_Server *server, char* name, UA_UInt32 datatypeid,
-                UA_Boolean isAbstract, UA_UInt32 parentid) {
-    UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
-    attr.displayName = UA_LOCALIZEDTEXT("", name);
-    attr.isAbstract = isAbstract;
-    return UA_Server_addDataTypeNode(server, UA_NODEID_NUMERIC(0, datatypeid),
-                              UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL,
-                              UA_QUALIFIEDNAME(0, name), attr, NULL, NULL);
-}
-
-static UA_StatusCode
-addObjectTypeNode(UA_Server *server, char* name, UA_UInt32 objecttypeid,
-                  UA_Boolean isAbstract, UA_UInt32 parentid) {
-    UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
-    attr.displayName = UA_LOCALIZEDTEXT("", name);
-    attr.isAbstract = isAbstract;
-    return UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(0, objecttypeid),
-                                UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL,
-                                UA_QUALIFIEDNAME(0, name), attr, NULL, NULL);
+    return AddNode_finish(server, &adminSession, &sourceId);
 }
 
 static UA_StatusCode
@@ -80,11 +48,11 @@ addObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
     UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
     object_attr.displayName = UA_LOCALIZEDTEXT("", name);
     return UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(0, objectid),
-                            UA_NODEID_NUMERIC(0, parentid),
-                            UA_NODEID_NUMERIC(0, referenceid),
-                            UA_QUALIFIEDNAME(0, name),
-                            UA_NODEID_NUMERIC(0, type_id),
-                            object_attr, NULL, NULL);
+                                   UA_NODEID_NUMERIC(0, parentid),
+                                   UA_NODEID_NUMERIC(0, referenceid),
+                                   UA_QUALIFIEDNAME(0, name),
+                                   UA_NODEID_NUMERIC(0, type_id),
+                                   object_attr, NULL, NULL);
 }
 
 static UA_StatusCode
@@ -101,68 +69,38 @@ addReferenceTypeNode(UA_Server *server, char* name, char *inverseName, UA_UInt32
                                    UA_QUALIFIEDNAME(0, name), reference_attr, NULL, NULL);
 }
 
-static UA_StatusCode
-addVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
-                    UA_Boolean isAbstract, UA_Int32 valueRank, UA_UInt32 dataType,
-                    const UA_DataType *type, UA_UInt32 parentid) {
-    UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
-    attr.displayName = UA_LOCALIZEDTEXT("", name);
-    attr.dataType = UA_NODEID_NUMERIC(0, dataType);
-    attr.isAbstract = isAbstract;
-    attr.valueRank = valueRank;
-
-    if(type) {
-        UA_STACKARRAY(UA_Byte, tempVal, type->memSize);
-        UA_init(tempVal, type);
-        UA_Variant_setScalar(&attr.value, tempVal, type);
-        return UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, variabletypeid),
-                                             UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL,
-                                             UA_QUALIFIEDNAME(0, name), UA_NODEID_NULL, attr, NULL, NULL);
-    }
-    return UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, variabletypeid),
-                                         UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL,
-                                         UA_QUALIFIEDNAME(0, name), UA_NODEID_NULL, attr, NULL, NULL);
-}
-
-/**********************/
-/* Create Namespace 0 */
-/**********************/
+/***************************/
+/* Bootstrap NS0 hierarchy */
+/***************************/
 
 /* Creates the basic nodes which are expected by the nodeset compiler to be
  * already created. This is necessary to reduce the dependencies for the nodeset
  * compiler. */
 static UA_StatusCode
 UA_Server_createNS0_base(UA_Server *server) {
-
-    UA_StatusCode ret = UA_STATUSCODE_GOOD;
-    /*********************************/
-    /* Bootstrap reference hierarchy */
-    /*********************************/
-
     /* Bootstrap References and HasSubtype */
+    UA_StatusCode ret = UA_STATUSCODE_GOOD;
     UA_ReferenceTypeAttributes references_attr = UA_ReferenceTypeAttributes_default;
     references_attr.displayName = UA_LOCALIZEDTEXT("", "References");
     references_attr.isAbstract = true;
     references_attr.symmetric = true;
     references_attr.inverseName = UA_LOCALIZEDTEXT("", "References");
-    ret |= addNode_begin(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_REFERENCES, "References",
-                  &references_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);
+    ret |= addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_REFERENCES, "References",
+                       &references_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);
 
     UA_ReferenceTypeAttributes hassubtype_attr = UA_ReferenceTypeAttributes_default;
     hassubtype_attr.displayName = UA_LOCALIZEDTEXT("", "HasSubtype");
     hassubtype_attr.isAbstract = false;
     hassubtype_attr.symmetric = false;
     hassubtype_attr.inverseName = UA_LOCALIZEDTEXT("", "HasSupertype");
-    ret |= addNode_begin(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_HASSUBTYPE, "HasSubtype",
-                  &hassubtype_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);
+    ret |= addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_HASSUBTYPE, "HasSubtype",
+                       &hassubtype_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);
 
     ret |= addReferenceTypeNode(server, "HierarchicalReferences", NULL,
-                         UA_NS0ID_HIERARCHICALREFERENCES,
-                         true, false, UA_NS0ID_REFERENCES);
+                         UA_NS0ID_HIERARCHICALREFERENCES, true, false, UA_NS0ID_REFERENCES);
 
     ret |= addReferenceTypeNode(server, "NonHierarchicalReferences", NULL,
-                         UA_NS0ID_NONHIERARCHICALREFERENCES,
-                         true, false, UA_NS0ID_REFERENCES);
+                         UA_NS0ID_NONHIERARCHICALREFERENCES, true, false, UA_NS0ID_REFERENCES);
 
     ret |= addReferenceTypeNode(server, "HasChild", NULL, UA_NS0ID_HASCHILD,
                          true, false, UA_NS0ID_HIERARCHICALREFERENCES);
@@ -214,68 +152,45 @@ UA_Server_createNS0_base(UA_Server *server) {
     UA_DataTypeAttributes basedatatype_attr = UA_DataTypeAttributes_default;
     basedatatype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataType");
     basedatatype_attr.isAbstract = true;
-    ret |= addNode_begin(server, UA_NODECLASS_DATATYPE, UA_NS0ID_BASEDATATYPE, "BaseDataType",
-                  &basedatatype_attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]);
-
-    ret |= addDataTypeNode(server, "Number", UA_NS0ID_NUMBER, true, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "Integer", UA_NS0ID_INTEGER, true, UA_NS0ID_NUMBER);
-    ret |= addDataTypeNode(server, "UInteger", UA_NS0ID_UINTEGER, true, UA_NS0ID_NUMBER);
-    ret |= addDataTypeNode(server, "Boolean", UA_NS0ID_BOOLEAN, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "SByte", UA_NS0ID_SBYTE, false, UA_NS0ID_INTEGER);
-    ret |= addDataTypeNode(server, "Byte", UA_NS0ID_BYTE, false, UA_NS0ID_UINTEGER);
-    ret |= addDataTypeNode(server, "Int16", UA_NS0ID_INT16, false, UA_NS0ID_INTEGER);
-    ret |= addDataTypeNode(server, "UInt16", UA_NS0ID_UINT16, false, UA_NS0ID_UINTEGER);
-    ret |= addDataTypeNode(server, "Int32", UA_NS0ID_INT32, false, UA_NS0ID_INTEGER);
-    ret |= addDataTypeNode(server, "UInt32", UA_NS0ID_UINT32, false, UA_NS0ID_UINTEGER);
-    ret |= addDataTypeNode(server, "Int64", UA_NS0ID_INT64, false, UA_NS0ID_INTEGER);
-    ret |= addDataTypeNode(server, "UInt64", UA_NS0ID_UINT64, false, UA_NS0ID_UINTEGER);
-    ret |= addDataTypeNode(server, "Float", UA_NS0ID_FLOAT, false, UA_NS0ID_NUMBER);
-    ret |= addDataTypeNode(server, "Double", UA_NS0ID_DOUBLE, false, UA_NS0ID_NUMBER);
-    ret |= addDataTypeNode(server, "DateTime", UA_NS0ID_DATETIME, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "String", UA_NS0ID_STRING, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "ByteString", UA_NS0ID_BYTESTRING, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "Guid", UA_NS0ID_GUID, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "XmlElement", UA_NS0ID_XMLELEMENT, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "NodeId", UA_NS0ID_NODEID, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "ExpandedNodeId", UA_NS0ID_EXPANDEDNODEID, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "QualifiedName", UA_NS0ID_QUALIFIEDNAME, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "LocalizedText", UA_NS0ID_LOCALIZEDTEXT, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "StatusCode", UA_NS0ID_STATUSCODE, false, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "Structure", UA_NS0ID_STRUCTURE, true, UA_NS0ID_BASEDATATYPE);
-    ret |= addDataTypeNode(server, "Decimal", UA_NS0ID_DECIMAL, false, UA_NS0ID_NUMBER);
-
-    ret |= addDataTypeNode(server, "Duration", UA_NS0ID_DURATION, false, UA_NS0ID_DOUBLE);
-    ret |= addDataTypeNode(server, "UtcTime", UA_NS0ID_UTCTIME, false, UA_NS0ID_DATETIME);
-    ret |= addDataTypeNode(server, "LocaleId", UA_NS0ID_LOCALEID, false, UA_NS0ID_STRING);
+    ret |= addNode_raw(server, UA_NODECLASS_DATATYPE, UA_NS0ID_BASEDATATYPE, "BaseDataType",
+                       &basedatatype_attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]);
 
     /*****************/
     /* VariableTypes */
     /*****************/
 
-    /* Bootstrap BaseVariableType */
     UA_VariableTypeAttributes basevar_attr = UA_VariableTypeAttributes_default;
     basevar_attr.displayName = UA_LOCALIZEDTEXT("", "BaseVariableType");
     basevar_attr.isAbstract = true;
     basevar_attr.valueRank = -2;
     basevar_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
-    ret |= addNode_begin(server, UA_NODECLASS_VARIABLETYPE, UA_NS0ID_BASEVARIABLETYPE, "BaseVariableType",
-                  &basevar_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]);
-
-    ret |= addVariableTypeNode(server, "BaseDataVariableType", UA_NS0ID_BASEDATAVARIABLETYPE,
-                        false, -2, UA_NS0ID_BASEDATATYPE, NULL, UA_NS0ID_BASEVARIABLETYPE);
+    ret |= addNode_raw(server, UA_NODECLASS_VARIABLETYPE, UA_NS0ID_BASEVARIABLETYPE, "BaseVariableType",
+                       &basevar_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]);
+
+    UA_VariableTypeAttributes bdv_attr = UA_VariableTypeAttributes_default;
+    bdv_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataVariableType");
+    bdv_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
+    bdv_attr.valueRank = -2;
+    ret |= UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE),
+                                         UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "BaseDataVariableType"),
+                                         UA_NODEID_NULL, bdv_attr, NULL, NULL);
 
     /***************/
     /* ObjectTypes */
     /***************/
 
-    /* Bootstrap BaseObjectType */
     UA_ObjectTypeAttributes baseobj_attr = UA_ObjectTypeAttributes_default;
     baseobj_attr.displayName = UA_LOCALIZEDTEXT("", "BaseObjectType");
-    ret |= addNode_begin(server, UA_NODECLASS_OBJECTTYPE, UA_NS0ID_BASEOBJECTTYPE, "BaseObjectType",
-                  &baseobj_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]);
+    ret |= addNode_raw(server, UA_NODECLASS_OBJECTTYPE, UA_NS0ID_BASEOBJECTTYPE, "BaseObjectType",
+                       &baseobj_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]);
 
-    ret |= addObjectTypeNode(server, "FolderType", UA_NS0ID_FOLDERTYPE,
-                      false, UA_NS0ID_BASEOBJECTTYPE);
+    UA_ObjectTypeAttributes folder_attr = UA_ObjectTypeAttributes_default;
+    folder_attr.displayName = UA_LOCALIZEDTEXT("", "FolderType");
+    ret |= UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                       UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "FolderType"),
+                                       folder_attr, NULL, NULL);
 
     /******************/
     /* Root and below */
@@ -296,13 +211,11 @@ UA_Server_createNS0_base(UA_Server *server) {
 
     ret |= addObjectNode(server, "DataTypes", UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
-
     ret |= addNode_finish(server, UA_NS0ID_BASEDATATYPE, UA_NS0ID_DATATYPESFOLDER,
                    UA_NS0ID_ORGANIZES);
 
     ret |= addObjectNode(server, "VariableTypes", UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
-
     ret |= addNode_finish(server, UA_NS0ID_BASEVARIABLETYPE, UA_NS0ID_VARIABLETYPESFOLDER,
                    UA_NS0ID_ORGANIZES);
 
@@ -318,8 +231,9 @@ UA_Server_createNS0_base(UA_Server *server) {
                   UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
 
     if(ret != UA_STATUSCODE_GOOD)
-        return UA_STATUSCODE_BADINTERNALERROR;
-    return UA_STATUSCODE_GOOD;
+        ret = UA_STATUSCODE_BADINTERNALERROR;
+
+    return ret;
 }
 
 /****************/
@@ -356,6 +270,7 @@ readStatus(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
     return UA_STATUSCODE_GOOD;
 }
 
+#ifdef UA_GENERATED_NAMESPACE_ZERO
 static UA_StatusCode
 readServiceLevel(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                  const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp,
@@ -405,6 +320,7 @@ readAuditing(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext
     }
     return UA_STATUSCODE_GOOD;
 }
+#endif
 
 static UA_StatusCode
 readNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
@@ -487,7 +403,7 @@ readCurrentTime(UA_Server *server, const UA_NodeId *sessionId, void *sessionCont
     return UA_STATUSCODE_GOOD;
 }
 
-#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
+#if defined(UA_GENERATED_NAMESPACE_ZERO) && defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
 static UA_StatusCode
 readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                    const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId,
@@ -543,6 +459,85 @@ writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v,
     return UA_Server_writeValue(server, UA_NODEID_NUMERIC(0, id), var);
 }
 
+#ifndef UA_GENERATED_NAMESPACE_ZERO
+static UA_StatusCode
+addVariableNode(UA_Server *server, char* name, UA_UInt32 variableid,
+                UA_UInt32 parentid, UA_UInt32 referenceid,
+                UA_Int32 valueRank, UA_UInt32 dataType) {
+    UA_VariableAttributes attr = UA_VariableAttributes_default;
+    attr.displayName = UA_LOCALIZEDTEXT("", name);
+    attr.dataType = UA_NODEID_NUMERIC(0, dataType);
+    attr.valueRank = valueRank;
+    attr.accessLevel = UA_ACCESSLEVELMASK_READ;
+    return UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(0, variableid),
+                                     UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid),
+                                     UA_QUALIFIEDNAME(0, name),
+                                     UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
+                                     attr, NULL, NULL);
+}
+
+/* A minimal server object that is not complete and does not use the mandated
+ * references to a server type. To be used on very constrained devices. */
+static UA_StatusCode
+UA_Server_minimalServerObject(UA_Server *server) {
+    /* Server */
+    UA_StatusCode retval = addObjectNode(server, "Server", UA_NS0ID_SERVER, UA_NS0ID_OBJECTSFOLDER,
+                                         UA_NS0ID_ORGANIZES, UA_NS0ID_BASEOBJECTTYPE);
+
+    retval |= addVariableNode(server, "ServerArray", UA_NS0ID_SERVER_SERVERARRAY,
+                              UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, 1, UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "NamespaceArray", UA_NS0ID_SERVER_NAMESPACEARRAY,
+                              UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, 1, UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "ServerStatus", UA_NS0ID_SERVER_SERVERSTATUS,
+                              UA_NS0ID_SERVER, UA_NS0ID_HASCOMPONENT, -1, UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "CurrentTime", UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME,
+                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "State", UA_NS0ID_SERVER_SERVERSTATUS_STATE,
+                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "BuildInfo", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO,
+                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "ProductUri", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI,
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "ManufacturerName",
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME,
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "ProductName",
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME,
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "SoftwareVersion",
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION,
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "BuildNumber",
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER,
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    retval |= addVariableNode(server, "BuildDate",
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE,
+                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, -1,
+                              UA_NS0ID_BASEDATATYPE);
+
+    return retval;
+}
+#endif
+
 /* Initialize the nodeset 0 by using the generated code of the nodeset compiler.
  * This also initialized the data sources for various variables, such as for
  * example server time. */
@@ -557,15 +552,18 @@ UA_Server_initNS0(UA_Server *server) {
     if(retVal != UA_STATUSCODE_GOOD)
         return retVal;
 
+#ifdef UA_GENERATED_NAMESPACE_ZERO
     /* Load nodes and references generated from the XML ns0 definition */
-    server->bootstrapNS0 = true;
     retVal = ua_namespace0(server);
-    server->bootstrapNS0 = false;
+#else
+    /* Create a minimal server object */
+    UA_Server_minimalServerObject(server);
+#endif
 
     /* NamespaceArray */
-    UA_DataSource namespaceDataSource = {readNamespaces, NULL};
+    UA_DataSource namespaceDataSource = {readNamespaces, writeNamespaces};
     retVal |= UA_Server_setVariableNode_dataSource(server,
-                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
+                                                   UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                                                    namespaceDataSource);
 
     /* ServerArray */
@@ -573,66 +571,10 @@ UA_Server_initNS0(UA_Server *server) {
                                     &server->config.applicationDescription.applicationUri,
                                     1, &UA_TYPES[UA_TYPES_STRING]);
 
-    /* LocaleIdArray */
-    UA_LocaleId locale_en = UA_STRING("en");
-    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY,
-                                    &locale_en, 1, &UA_TYPES[UA_TYPES_LOCALEID]);
-
-    /* MaxBrowseContinuationPoints */
-    UA_UInt16 maxBrowseContinuationPoints = UA_MAXCONTINUATIONPOINTS;
-    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS,
-                               &maxBrowseContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);
-
-    /* ServerProfileArray */
-    UA_String profileArray[5];
-    UA_UInt16 profileArraySize = 0;
-#define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING_ALLOC(x)
-    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NanoEmbeddedDevice");
-#ifdef UA_ENABLE_NODEMANAGEMENT
-    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement");
-#endif
-#ifdef UA_ENABLE_METHODCALLS
-    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods");
-#endif
-#ifdef UA_ENABLE_SUBSCRIPTIONS
-    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/EmbeddedDataChangeSubscription");
-#endif
-#ifdef UA_ENABLE_HISTORIZING
-    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/HistoricalRawData");
-#endif
-
-    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY,
-                                    profileArray, profileArraySize, &UA_TYPES[UA_TYPES_STRING]);
-    for(int i=0; i<profileArraySize; i++) {
-        UA_String_deleteMembers(&profileArray[i]);
-    }
-
-    /* MaxQueryContinuationPoints */
-    UA_UInt16 maxQueryContinuationPoints = 0;
-    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS,
-                               &maxQueryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);
-
-    /* MaxHistoryContinuationPoints */
-    UA_UInt16 maxHistoryContinuationPoints = 0;
-    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS,
-                               &maxHistoryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);
-
     /* MinSupportedSampleRate */
     retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE,
                                &server->config.samplingIntervalLimits.min, &UA_TYPES[UA_TYPES_DURATION]);
 
-    /* ServerDiagnostics - ServerDiagnosticsSummary */
-    UA_ServerDiagnosticsSummaryDataType serverDiagnosticsSummary;
-    UA_ServerDiagnosticsSummaryDataType_init(&serverDiagnosticsSummary);
-    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY,
-                               &serverDiagnosticsSummary,
-                               &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE]);
-
-    /* ServerDiagnostics - EnabledFlag */
-    UA_Boolean enabledFlag = false;
-    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG,
-                               &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]);
-
     /* ServerStatus */
     UA_DataSource serverStatus = {readStatus, NULL};
     retVal |= UA_Server_setVariableNode_dataSource(server,
@@ -678,6 +620,8 @@ UA_Server_initNS0(UA_Server *server) {
     retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE,
                                &server->config.buildInfo.buildDate, &UA_TYPES[UA_TYPES_DATETIME]);
 
+#ifdef UA_GENERATED_NAMESPACE_ZERO
+
     /* SecondsTillShutdown */
     UA_UInt32 secondsTillShutdown = 0;
     retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN,
@@ -694,21 +638,72 @@ UA_Server_initNS0(UA_Server *server) {
     retVal |= UA_Server_setVariableNode_dataSource(server,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVICELEVEL), serviceLevel);
 
+    /* ServerDiagnostics - ServerDiagnosticsSummary */
+    UA_ServerDiagnosticsSummaryDataType serverDiagnosticsSummary;
+    UA_ServerDiagnosticsSummaryDataType_init(&serverDiagnosticsSummary);
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY,
+                               &serverDiagnosticsSummary,
+                               &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE]);
+
+    /* ServerDiagnostics - EnabledFlag */
+    UA_Boolean enabledFlag = false;
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG,
+                               &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]);
+
     /* Auditing */
     UA_DataSource auditing = {readAuditing, NULL};
     retVal |= UA_Server_setVariableNode_dataSource(server,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_AUDITING), auditing);
 
-    /* NamespaceArray */
-    UA_DataSource nsarray_datasource =  {readNamespaces, writeNamespaces};
-    retVal |= UA_Server_setVariableNode_dataSource(server,
-                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), nsarray_datasource);
-
     /* Redundancy Support */
     UA_RedundancySupport redundancySupport = UA_REDUNDANCYSUPPORT_NONE;
     retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT,
                                &redundancySupport, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]);
 
+    /* ServerCapabilities - LocaleIdArray */
+    UA_LocaleId locale_en = UA_STRING("en");
+    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY,
+                                    &locale_en, 1, &UA_TYPES[UA_TYPES_LOCALEID]);
+
+    /* ServerCapabilities - MaxBrowseContinuationPoints */
+    UA_UInt16 maxBrowseContinuationPoints = UA_MAXCONTINUATIONPOINTS;
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS,
+                               &maxBrowseContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);
+
+    /* ServerProfileArray */
+    UA_String profileArray[5];
+    UA_UInt16 profileArraySize = 0;
+#define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING(x)
+    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NanoEmbeddedDevice");
+#ifdef UA_ENABLE_NODEMANAGEMENT
+    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement");
+#endif
+#ifdef UA_ENABLE_METHODCALLS
+    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods");
+#endif
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/EmbeddedDataChangeSubscription");
+#endif
+#ifdef UA_ENABLE_HISTORIZING
+    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/HistoricalRawData");
+#endif
+    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY,
+                                    profileArray, profileArraySize, &UA_TYPES[UA_TYPES_STRING]);
+
+    /* ServerCapabilities - MaxQueryContinuationPoints */
+    UA_UInt16 maxQueryContinuationPoints = 0;
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS,
+                               &maxQueryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);
+
+    /* ServerCapabilities - MaxHistoryContinuationPoints */
+    UA_UInt16 maxHistoryContinuationPoints = 0;
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS,
+                               &maxHistoryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);
+
+    /* ServerCapabilities - MinSupportedSampleRate */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE,
+                               &server->config.samplingIntervalLimits.min, &UA_TYPES[UA_TYPES_DURATION]);
+
     /* ServerCapabilities - OperationLimits - MaxNodesPerRead */
     retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD,
                                &server->config.maxNodesPerRead, &UA_TYPES[UA_TYPES_UINT32]);
@@ -804,6 +799,7 @@ UA_Server_initNS0(UA_Server *server) {
                         UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), readMonitoredItems);
 #endif
 
+#endif /* UA_GENERATED_NAMESPACE_ZERO */
 
     /* create the OverFlowEventType
      * The EventQueueOverflowEventType is defined as abstract, therefore we can not create an instance of that type

+ 4 - 0
src/server/ua_services.h

@@ -356,6 +356,8 @@ void Service_Call(UA_Server *server, UA_Session *session,
                   UA_CallResponse *response);
 #endif
 
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+
 /**
  * MonitoredItem Service Set
  * -------------------------
@@ -484,6 +486,8 @@ void Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
  * its Session. */
 /* Not Implemented */
 
+#endif /* UA_ENABLE_SUBSCRIPTIONS */
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 13 - 6
src/server/ua_services_attribute.c

@@ -1342,14 +1342,21 @@ Service_Write(UA_Server *server, UA_Session *session,
                                            &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
+UA_StatusCode
+UA_Server_writeWithSession(UA_Server *server, UA_Session *session,
+                           const UA_WriteValue *value) {
+    return UA_Server_editNode(server, session, &value->nodeId,
+                              (UA_EditNodeCallback)copyAttributeIntoNode,
+                              /* casting away const qualifier because callback uses const anyway */
+                              (UA_WriteValue *)(uintptr_t)value);
+}
+
 UA_StatusCode
 UA_Server_write(UA_Server *server, const UA_WriteValue *value) {
-    UA_StatusCode retval =
-        UA_Server_editNode(server, &adminSession, &value->nodeId,
-                  (UA_EditNodeCallback)copyAttributeIntoNode,
-                   /* casting away const qualifier because callback uses const anyway */
-                   (UA_WriteValue *)(uintptr_t)value);
-    return retval;
+    return UA_Server_editNode(server, &adminSession, &value->nodeId,
+                              (UA_EditNodeCallback)copyAttributeIntoNode,
+                              /* casting away const qualifier because callback uses const anyway */
+                              (UA_WriteValue *)(uintptr_t)value);
 }
 
 /* Convenience function to be wrapped into inline functions */

+ 144 - 138
src/server/ua_services_nodemanagement.c

@@ -74,10 +74,6 @@ checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeCl
        UA_NodeId_isNull(referenceTypeId))
         return UA_STATUSCODE_GOOD;
 
-    /* Omit checks during bootstrap */
-    if(server->bootstrapNS0)
-        return UA_STATUSCODE_GOOD;
-
     /* See if the parent exists */
     const UA_Node *parent = UA_Nodestore_get(server, parentNodeId);
     if(!parent) {
@@ -149,8 +145,7 @@ checkParentReference(UA_Server *server, UA_Session *session, UA_NodeClass nodeCl
 static UA_StatusCode
 typeCheckVariableNode(UA_Server *server, UA_Session *session,
                       const UA_VariableNode *node,
-                      const UA_VariableTypeNode *vt,
-                      const UA_NodeId *parentNodeId) {
+                      const UA_VariableTypeNode *vt) {
     /* The value might come from a datasource, so we perform a
      * regular read. */
     UA_DataValue value;
@@ -174,7 +169,8 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
     }
 
     /* Check valueRank against array dimensions */
-    if(!(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
+    if(arrayDims != 0 &&
+       !(node->nodeClass == UA_NODECLASS_VARIABLETYPE &&
          ((const UA_VariableTypeNode*)node)->isAbstract && node->valueRank == 0) &&
        !compatibleValueRankArrayDimensions(node->valueRank, arrayDims)) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
@@ -182,33 +178,23 @@ typeCheckVariableNode(UA_Server *server, UA_Session *session,
         return UA_STATUSCODE_BADTYPEMISMATCH;
     }
 
-    /* If variable node is created below BaseObjectType and has its default valueRank of -2,
-     * skip the test */
-    const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
-
-    // TODO handle subtypes of parent reference types
-    if(node->valueRank != vt->valueRank &&
-       node->valueRank != UA_VariableAttributes_default.valueRank &&
-       !isNodeInTree(&server->config.nodestore, parentNodeId, &objectTypes,
-                     parentReferences, UA_PARENT_REFERENCES_COUNT)) {
-        /* Check valueRank against the vt */
-        if(!compatibleValueRanks(node->valueRank, vt->valueRank)) {
-            UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: The value rank is incomatible with the value rank of the VariableType");
-            return UA_STATUSCODE_BADTYPEMISMATCH;
-        }
+    /* Check valueRank against the vt */
+    if(!compatibleValueRanks(node->valueRank, vt->valueRank)) {
+        UA_LOG_INFO_SESSION(server->config.logger, session,
+                            "AddNodes: The value rank is incomatible with the value rank of the VariableType");
+        return UA_STATUSCODE_BADTYPEMISMATCH;
     }
 
     /* Check array dimensions against the vt */
     if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions,
                                   node->arrayDimensionsSize, node->arrayDimensions)) {
-        UA_LOG_INFO_SESSION(server->config.logger, session,
-                            "AddNodes: The array dimensions are incomatible with the array dimensions of the VariableType");
+        UA_LOG_INFO_SESSION(server->config.logger, session, "AddNodes: The array dimensions are "
+                            "incomatible with the array dimensions of the VariableType");
         return UA_STATUSCODE_BADTYPEMISMATCH;
     }
 
     /* Typecheck the value */
-    if(!server->bootstrapNS0 && value.hasValue) {
+    if(value.hasValue) {
         /* If the type-check failed write the same value again. The
          * write-service tries to convert to the correct type... */
         if(!compatibleValue(server, &node->dataType, node->valueRank,
@@ -231,62 +217,92 @@ static const UA_NodeId baseObjectType =
 static const UA_NodeId hasTypeDefinition =
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASTYPEDEFINITION}};
 
-/* Use attributes from the variable type wherever required */
+/* Use attributes from the variable type wherever required. Reload the node if
+ * changes were made. */
 static UA_StatusCode
 useVariableTypeAttributes(UA_Server *server, UA_Session *session,
-                          UA_VariableNode *node, const UA_AddNodesItem *item) {
-    const UA_VariableAttributes *attributes = (const UA_VariableAttributes*)
-        item->nodeAttributes.content.decoded.data;
-
-    /* Select the type definition */
-    const UA_NodeId *typeDefinition;
-    if(node->nodeClass == UA_NODECLASS_VARIABLE)
-        typeDefinition = &item->typeDefinition.nodeId;
-    else /* UA_NODECLASS_VARIABLETYPE */
-        typeDefinition = &item->parentNodeId.nodeId;
-
-    /* Replace an empty typeDefinition with the most permissive default */
-    if(UA_NodeId_isNull(typeDefinition))
-        typeDefinition = &baseDataVariableType;
-
-    const UA_VariableTypeNode *vt = (const UA_VariableTypeNode*)
-        UA_Nodestore_get(server, typeDefinition);
-    if(!vt || vt->nodeClass != UA_NODECLASS_VARIABLETYPE) {
-        UA_Nodestore_release(server, (const UA_Node*)vt);
-        return UA_STATUSCODE_BADTYPEMISMATCH;
-    }
+                          const UA_VariableNode **node_ptr, const UA_VariableTypeNode *vt) {
+    const UA_VariableNode *node = *node_ptr;
+    UA_Boolean modified = false;
 
     /* If no value is set, see if the vt provides one and copy it. This needs to
      * be done before copying the datatype from the vt, as setting the datatype
      * triggers a typecheck. */
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    if(!attributes->value.type) {
+    UA_DataValue orig;
+    UA_DataValue_init(&orig);
+    UA_StatusCode retval = readValueAttribute(server, session, node, &orig);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
+
+    if(orig.value.type) {
+        /* A value is present */
+        UA_DataValue_deleteMembers(&orig);
+    } else {
         UA_LOG_DEBUG_SESSION(server->config.logger, session,
                              "AddNodes: No value given; Copy the value "
                              "from the TypeDefinition");
-        UA_DataValue vt_value;
-        UA_DataValue_init(&vt_value);
-        retval = readValueAttribute(server, session,
-                                    (const UA_VariableNode*)vt, &vt_value);
-        if(retval == UA_STATUSCODE_GOOD && vt_value.hasValue) {
-            retval = UA_Variant_copy(&vt_value.value, &node->value.data.value.value);
-            node->value.data.value.hasValue = true;
+        UA_WriteValue v;
+        UA_WriteValue_init(&v);
+        retval = readValueAttribute(server, session, (const UA_VariableNode*)vt, &v.value);
+        if(retval == UA_STATUSCODE_GOOD && v.value.hasValue) {
+            v.nodeId = node->nodeId;
+            v.attributeId = UA_ATTRIBUTEID_VALUE;
+            retval = UA_Server_writeWithSession(server, session, &v);
+            modified = true;
         }
-        UA_DataValue_deleteMembers(&vt_value);
+        UA_DataValue_deleteMembers(&v.value);
+
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
     }
 
     /* If no datatype is given, use the datatype of the vt */
-    if(retval == UA_STATUSCODE_GOOD && UA_NodeId_isNull(&node->dataType)) {
+    if(UA_NodeId_isNull(&node->dataType)) {
         UA_LOG_INFO_SESSION(server->config.logger, session, "AddNodes: "
                             "No datatype given; Copy the datatype attribute "
                             "from the TypeDefinition");
-        retval = UA_NodeId_copy(&vt->dataType, &node->dataType);
+        UA_WriteValue v;
+        UA_WriteValue_init(&v);
+        v.nodeId = node->nodeId;
+        v.attributeId = UA_ATTRIBUTEID_DATATYPE;
+        v.value.hasValue = true;
+        UA_Variant_setScalar(&v.value.value, (void*)(uintptr_t)&vt->dataType, &UA_TYPES[UA_TYPES_NODEID]);
+        retval = UA_Server_writeWithSession(server, session, &v);
+        modified = true;
+
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
     }
 
-    /* TODO: If the vt has arraydimensions but this variable does not, copy */
+    /* Use the ArrayDimensions of the vt */
+    if(node->arrayDimensionsSize == 0 && vt->arrayDimensionsSize > 0) {
+        UA_WriteValue v;
+        UA_WriteValue_init(&v);
+        v.nodeId = node->nodeId;
+        v.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
+        v.value.hasValue = true;
+        UA_Variant_setArray(&v.value.value, vt->arrayDimensions, vt->arrayDimensionsSize,
+                            &UA_TYPES[UA_TYPES_UINT32]);
+        retval = UA_Server_writeWithSession(server, session, &v);
+        modified = true;
 
-    UA_Nodestore_release(server, (const UA_Node*)vt);
-    return retval;
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
+    }
+
+    /* If the node was modified, update the pointer to the new version */
+    if(modified) {
+        const UA_VariableNode *updated = (const UA_VariableNode*)
+            UA_Nodestore_get(server, &node->nodeId);
+
+        if(!updated)
+            return UA_STATUSCODE_BADINTERNALERROR;
+
+        UA_Nodestore_release(server, (const UA_Node*)node);
+        *node_ptr = updated;
+    }
+
+    return UA_STATUSCODE_GOOD;
 }
 
 /* Search for an instance of "browseName" in node searchInstance. Used during
@@ -438,11 +454,6 @@ static void deleteReferencesSubset(UA_Node *node, size_t referencesSkipSize, UA_
     }
 }
 
-static UA_StatusCode
-AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                         const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
-                         const UA_NodeId *typeDefinitionId);
-
 static UA_StatusCode
 copyChildNode(UA_Server *server, UA_Session *session,
               const UA_NodeId *destinationNodeId,
@@ -526,8 +537,8 @@ copyChildNode(UA_Server *server, UA_Session *session,
         copyChildNodes(server, session, &rd->nodeId.nodeId, &newNodeId);
 
         /* Add the parent reference */
-        retval = AddNode_typeCheckAddRefs(server, session, &newNodeId, destinationNodeId,
-                                          &rd->referenceTypeId, typeId);
+        retval = AddNode_addRefs(server, session, &newNodeId, destinationNodeId,
+                                 &rd->referenceTypeId, typeId);
         if(retval != UA_STATUSCODE_GOOD) {
             UA_Nodestore_remove(server, &node->nodeId);
             UA_Nodestore_release(server, type);
@@ -537,7 +548,7 @@ copyChildNode(UA_Server *server, UA_Session *session,
         /* Call addnode_finish, this recursively adds additional members, the type
          * definition and so on of the base type of this child, if they are not yet
          * in the destination */
-        retval |= Operation_addNode_finish(server, session, &newNodeId);
+        retval |= AddNode_finish(server, session, &newNodeId);
         UA_NodeId_deleteMembers(&newNodeId);
         UA_Nodestore_release(server, type);
     }
@@ -662,18 +673,16 @@ removeDeconstructedNode(UA_Server *server, UA_Session *session,
 
 static const UA_NodeId hasSubtype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
 
-static UA_StatusCode
-AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
-                         const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
-                         const UA_NodeId *typeDefinitionId) {
+UA_StatusCode
+AddNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
+                const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
+                const UA_NodeId *typeDefinitionId) {
     /* Get the node */
+    const UA_Node *type = NULL;
     const UA_Node *node = UA_Nodestore_get(server, nodeId);
     if(!node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
 
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    const UA_Node *type = NULL;
-
     /* Use the typeDefinition as parent for type-nodes */
     if(node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
        node->nodeClass == UA_NODECLASS_OBJECTTYPE ||
@@ -689,12 +698,9 @@ AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId
         }
     }
 
-    if(server->bootstrapNS0)
-        goto get_type;
-
     /* Check parent reference. Objects may have no parent. */
-    retval = checkParentReference(server, session, node->nodeClass,
-                                  parentNodeId, referenceTypeId);
+    UA_StatusCode retval = checkParentReference(server, session, node->nodeClass,
+                                                parentNodeId, referenceTypeId);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
                             "AddNodes: The parent reference is invalid "
@@ -715,7 +721,6 @@ AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId
             typeDefinitionId = &baseObjectType;
     }
 
- get_type:
     /* Get the node type. There must be a typedefinition for variables, objects
      * and type-nodes. See the above checks. */
     if(!UA_NodeId_isNull(typeDefinitionId)) {
@@ -723,7 +728,7 @@ AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId
         type = UA_Nodestore_get(server, typeDefinitionId);
         if(!type) {
             UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Node type not found in nodestore");
+                                "AddNodes: Node type not found");
             retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
             goto cleanup;
         }
@@ -766,7 +771,7 @@ AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId
 
         /* See if the type has the correct node class. For type-nodes, we know
          * that type has the same nodeClass from checkParentReference. */
-        if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_VARIABLE) {
+        if(node->nodeClass == UA_NODECLASS_VARIABLE) {
             if(((const UA_VariableTypeNode*)type)->isAbstract) {
                 /* Abstract variable is allowed if parent is a children of a base data variable */
                 const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
@@ -786,7 +791,7 @@ AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId
             }
         }
 
-        if(!server->bootstrapNS0 && node->nodeClass == UA_NODECLASS_OBJECT) {
+        if(node->nodeClass == UA_NODECLASS_OBJECT) {
             if(((const UA_ObjectTypeNode*)type)->isAbstract) {
                 /* Object node created of an abstract ObjectType. Only allowed
                  * if within BaseObjectType folder */
@@ -804,21 +809,6 @@ AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId
         }
     }
 
-    /* Check if all attributes hold the constraints of the type now. The initial
-     * attributes must type-check. The constructor might change the attributes
-     * again. Then, the changes are type-checked by the normal write service. */
-    if(type && (node->nodeClass == UA_NODECLASS_VARIABLE ||
-                node->nodeClass == UA_NODECLASS_VARIABLETYPE)) {
-        retval = typeCheckVariableNode(server, session, (const UA_VariableNode*)node,
-                                       (const UA_VariableTypeNode*)type, parentNodeId);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Type-checking the variable node "
-                                "failed with error code %s", UA_StatusCode_name(retval));
-            goto cleanup;
-        }
-    }
-
     /* Add reference to the parent */
     if(!UA_NodeId_isNull(parentNodeId)) {
         if(UA_NodeId_isNull(referenceTypeId)) {
@@ -857,11 +847,9 @@ AddNode_typeCheckAddRefs(UA_Server *server, UA_Session *session, const UA_NodeId
 
 /* Create the node and add it to the nodestore. But don't typecheck and add
  * references so far */
-static UA_StatusCode
+UA_StatusCode
 AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
             const UA_AddNodesItem *item, UA_NodeId *outNewNodeId) {
-    UA_assert(outNewNodeId);
-
     /* Do not check access for server */
     if(session != &adminSession && server->config.accessControl.allowAddNode &&
        !server->config.accessControl.allowAddNode(server, &server->config.accessControl,
@@ -907,23 +895,6 @@ AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
         return retval;
     }
 
-    /* Use attributes from the typedefinition */
-    if(!server->bootstrapNS0 &&
-       (node->nodeClass == UA_NODECLASS_VARIABLE ||
-        node->nodeClass == UA_NODECLASS_VARIABLETYPE)) {
-        /* Use attributes from the type. The value and value constraints are the
-         * same for the variable and variabletype attribute structs. */
-        retval = useVariableTypeAttributes(server, session,
-                                           (UA_VariableNode*)node, item);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Using attributes from the variable type "
-                                "failed with error code %s", UA_StatusCode_name(retval));
-            UA_Nodestore_delete(server, node);
-            return retval;
-        }
-    }
-
     /* Add the node to the nodestore */
     retval = UA_Nodestore_insert(server, node, outNewNodeId);
     if(retval != UA_STATUSCODE_GOOD)
@@ -935,7 +906,7 @@ AddNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
 }
 
 /* Prepare the node, then add it to the nodestore */
-UA_StatusCode
+static UA_StatusCode
 Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
                         const UA_AddNodesItem *item, const UA_NodeId *parentNodeId,
                         const UA_NodeId *referenceTypeId, UA_NodeId *outNewNodeId) {
@@ -952,10 +923,11 @@ Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContex
         return retval;
 
     /* Typecheck and add references to parent and type definition */
-    retval = AddNode_typeCheckAddRefs(server, session, outNewNodeId, parentNodeId,
-                                      referenceTypeId, &item->typeDefinition.nodeId);
+    retval = AddNode_addRefs(server, session, outNewNodeId, parentNodeId,
+                             referenceTypeId, &item->typeDefinition.nodeId);
     if(retval != UA_STATUSCODE_GOOD)
         UA_Server_deleteNode(server, *outNewNodeId, UA_TRUE);
+
     if(outNewNodeId == &newId)
         UA_NodeId_deleteMembers(&newId);
     return retval;
@@ -963,7 +935,7 @@ Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContex
 
 /* Children, references, type-checking, constructors. */
 UA_StatusCode
-Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) {
+AddNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
 
     /* Get the node */
@@ -975,27 +947,61 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
 
     /* Instantiate variables and objects */
     if(node->nodeClass == UA_NODECLASS_VARIABLE ||
+       node->nodeClass == UA_NODECLASS_VARIABLETYPE ||
        node->nodeClass == UA_NODECLASS_OBJECT) {
         /* Get the type node */
         type = getNodeType(server, node);
         if(!type) {
+            if(server->bootstrapNS0)
+                goto constructor;
             UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Node type not found in nodestore");
+                                "AddNodes: Node type not found");
             retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
             goto cleanup;
         }
 
+        /* Use attributes from the type. The value and value constraints are the
+         * same for the variable and variabletype attribute structs. */
+        if(node->nodeClass == UA_NODECLASS_VARIABLE ||
+           node->nodeClass == UA_NODECLASS_VARIABLETYPE) {
+            retval = useVariableTypeAttributes(server, session,
+                                               (const UA_VariableNode**)&node,
+                                               (const UA_VariableTypeNode*)type);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_LOG_INFO_SESSION(server->config.logger, session,
+                                    "AddNodes: Using attributes from the variable type "
+                                    "failed with error code %s", UA_StatusCode_name(retval));
+                goto cleanup;
+            }
+
+            /* Check if all attributes hold the constraints of the type now. The initial
+             * attributes must type-check. The constructor might change the attributes
+             * again. Then, the changes are type-checked by the normal write service. */
+            retval = typeCheckVariableNode(server, session, (const UA_VariableNode*)node,
+                                           (const UA_VariableTypeNode*)type);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_LOG_INFO_SESSION(server->config.logger, session,
+                                    "AddNodes: Type-checking the variable node "
+                                    "failed with error code %s", UA_StatusCode_name(retval));
+                goto cleanup;
+            }
+        }
+
         /* Add (mandatory) child nodes from the type definition */
-        retval = addChildren(server, session, node, type);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_LOG_INFO_SESSION(server->config.logger, session,
-                                "AddNodes: Adding child nodes failed with error code %s",
-                                UA_StatusCode_name(retval));
-            goto cleanup;
+        if(node->nodeClass == UA_NODECLASS_VARIABLE ||
+           node->nodeClass == UA_NODECLASS_OBJECT) {
+            retval = addChildren(server, session, node, type);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_LOG_INFO_SESSION(server->config.logger, session,
+                                    "AddNodes: Adding child nodes failed with error code %s",
+                                    UA_StatusCode_name(retval));
+                goto cleanup;
+            }
         }
     }
 
     /* Call the constructor(s) */
+ constructor:
     retval = callConstructors(server, session, node, type);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
@@ -1023,7 +1029,7 @@ Operation_addNode(UA_Server *server, UA_Session *session, void *nodeContext,
 
     /* AddNodes_finish */
     result->statusCode =
-        Operation_addNode_finish(server, session, &result->addedNodeId);
+        AddNode_finish(server, session, &result->addedNodeId);
 
     /* If finishing failed, the node was deleted */
     if(result->statusCode != UA_STATUSCODE_GOOD)
@@ -1106,7 +1112,7 @@ UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
 
 UA_StatusCode
 UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId) {
-    return Operation_addNode_finish(server, &adminSession, &nodeId);
+    return AddNode_finish(server, &adminSession, &nodeId);
 }
 
 /****************/
@@ -1535,13 +1541,13 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
         goto cleanup;
 
     /* Typecheck and add references to parent and type definition */
-    retval = AddNode_typeCheckAddRefs(server, &adminSession, outNewNodeId, &parentNodeId,
-                                      &referenceTypeId, &typeDefinition);
+    retval = AddNode_addRefs(server, &adminSession, outNewNodeId, &parentNodeId,
+                             &referenceTypeId, &typeDefinition);
     if(retval != UA_STATUSCODE_GOOD)
         goto cleanup;
 
     /* Call the constructors */
-    retval = Operation_addNode_finish(server, &adminSession, outNewNodeId);
+    retval = AddNode_finish(server, &adminSession, outNewNodeId);
 
  cleanup:
     if(outNewNodeId == &newNodeId)
@@ -1657,7 +1663,7 @@ UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
     retval |= UA_Server_setMethodNode_callback(server, nodeId, method);
 
     /* Call finish to add the parent reference */
-    retval |= Operation_addNode_finish(server, &adminSession, &nodeId);
+    retval |= AddNode_finish(server, &adminSession, &nodeId);
 
     if(retval != UA_STATUSCODE_GOOD) {
         UA_Server_deleteNode(server, nodeId, true);

+ 4 - 1
src/server/ua_services_subscription.c

@@ -180,8 +180,11 @@ setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
             return UA_STATUSCODE_BADFILTERNOTALLOWED;
         }
         UA_DataChangeFilter_copy(filter, &(mon->filter.dataChangeFilter));
+#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
     } else if (params->filter.content.decoded.type == &UA_TYPES[UA_TYPES_EVENTFILTER]) {
-        UA_EventFilter_copy((UA_EventFilter *)params->filter.content.decoded.data, &(mon->filter.eventFilter));
+        UA_EventFilter_copy((UA_EventFilter *)params->filter.content.decoded.data,
+                            &mon->filter.eventFilter);
+#endif
     } else {
         return UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID;
     }

+ 2 - 0
src/server/ua_subscription.c

@@ -49,11 +49,13 @@ UA_Notification_delete(UA_Subscription *sub, UA_MonitoredItem *mon,
     if(mon->monitoredItemType == UA_MONITOREDITEMTYPE_CHANGENOTIFY) {
         UA_DataValue_deleteMembers(&n->data.value);
         --sub->dataChangeNotifications;
+#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
     } else if(mon->monitoredItemType == UA_MONITOREDITEMTYPE_EVENTNOTIFY) {
         UA_EventFieldList_deleteMembers(&n->data.event.fields);
         /* EventFilterResult currently isn't being used
          * UA_EventFilterResult_delete(notification->data.event->result); */
         --sub->eventNotifications;
+#endif
     } else if(mon->monitoredItemType == UA_MONITOREDITEMTYPE_STATUSNOTIFY) {
         --sub->statusChangeNotifications;
     }

+ 10 - 0
src/server/ua_subscription.h

@@ -19,6 +19,8 @@
 #include "ua_types_generated.h"
 #include "ua_session.h"
 
+#ifdef UA_ENABLE_SUBSCRIPTIONS
+
 /**
  * MonitoredItems create Notifications. Subscriptions collect Notifications from
  * (several) MonitoredItems and publish them to the client.
@@ -44,11 +46,13 @@ typedef enum {
 struct UA_MonitoredItem;
 typedef struct UA_MonitoredItem UA_MonitoredItem;
 
+#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
 typedef struct UA_EventNotification {
     UA_EventFieldList fields;
     /* EventFilterResult currently isn't being used
     UA_EventFilterResult result; */
 } UA_EventNotification;
+#endif
 
 typedef struct UA_Notification {
     TAILQ_ENTRY(UA_Notification) listEntry; /* Notification list for the MonitoredItem */
@@ -58,7 +62,9 @@ typedef struct UA_Notification {
 
     /* See the monitoredItemType of the MonitoredItem */
     union {
+#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
         UA_EventNotification event;
+#endif
         UA_DataValue value;
     } data;
 } UA_Notification;
@@ -92,7 +98,9 @@ struct UA_MonitoredItem {
     UA_Boolean discardOldest;
     // TODO: dataEncoding is hardcoded to UA binary
     union {
+#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
         UA_EventFilter eventFilter;
+#endif
         UA_DataChangeFilter dataChangeFilter;
     } filter;
     UA_Variant lastValue;
@@ -202,4 +210,6 @@ UA_StatusCode UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub,
 void UA_Subscription_answerPublishRequestsNoSubscription(UA_Server *server, UA_Session *session);
 UA_Boolean UA_Subscription_reachedPublishReqLimit(UA_Server *server,  UA_Session *session);
 
+#endif /* UA_ENABLE_SUBSCRIPTIONS */
+
 #endif /* UA_SUBSCRIPTION_H_ */

+ 1 - 1
tools/appveyor/build.ps1

@@ -70,7 +70,7 @@ try {
     Write-Host -ForegroundColor Green "`n##### Testing $env:CC_NAME with full NS0 #####`n"
     New-Item -ItemType directory -Path "build"
     cd build
-    & cmake -DUA_ENABLE_SUBSCRIPTIONS_EVENTS:BOOL=ON -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_ENABLE_FULL_NS0:BOOL=ON -DUA_COMPILE_AS_CXX:BOOL=$env:FORCE_CXX -G"$env:CC_NAME"  ..
+    & cmake -DUA_ENABLE_SUBSCRIPTIONS_EVENTS:BOOL=ON -DUA_BUILD_EXAMPLES:BOOL=ON -DUA_NAMESPACE_ZERO:STRING=FULL -DUA_COMPILE_AS_CXX:BOOL=$env:FORCE_CXX -G"$env:CC_NAME"  ..
     Invoke-Expression $make_cmd
     if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) {
         Write-Host -ForegroundColor Red "`n`n*** Make failed. Exiting ... ***"

+ 0 - 27
tools/nodeset_compiler/NodeID_AssumeExternal.txt

@@ -1,27 +0,0 @@
-i=2253
-i=2254
-i=2255
-i=2256
-i=2257
-i=2258
-i=2259
-i=2260
-i=2261
-i=2262
-i=2263
-i=2264
-i=2265
-i=2266
-i=2267
-i=2271
-i=2274
-i=2294
-i=2735
-i=2992
-i=2993
-i=2994
-i=2268
-i=295
-i=296
-i=11715
-i=11492

+ 0 - 0
tools/nodeset_compiler/NodeID_Blacklist.txt


+ 0 - 29
tools/nodeset_compiler/NodeID_NS0_Base.txt

@@ -1,29 +1,4 @@
-i=1
-i=2
-i=3
-i=4
-i=5
-i=6
-i=7
-i=8
-i=9
-i=10
-i=11
-i=12
-i=13
-i=14
-i=15
-i=16
-i=17
-i=18
-i=19
-i=20
-i=21
-i=22
 i=24
-i=26
-i=27
-i=28
 i=31
 i=32
 i=33
@@ -42,7 +17,6 @@ i=46
 i=47
 i=48
 i=49
-i=50
 i=58
 i=61
 i=62
@@ -55,7 +29,4 @@ i=88
 i=89
 i=90
 i=91
-i=290
-i=294
-i=295
 i=3048

+ 7 - 7
tools/nodeset_compiler/backend_open62541_datatypes.py

@@ -38,24 +38,24 @@ def splitStringLiterals(value, splitLength=500, max_string_length=0):
 
 def generateStringCode(value, alloc=False, max_string_length=0):
     value = makeCLiteral(value)
-    return "UA_STRING{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length))
+    return u"UA_STRING{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length))
 
 def generateXmlElementCode(value, alloc=False, max_string_length=0):
     value = makeCLiteral(value)
-    return "UA_XMLELEMENT{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length))
+    return u"UA_XMLELEMENT{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length))
 
 def generateByteStringCode(value, alloc=False, max_string_length=0):
     value = makeCLiteral(value)
-    return "UA_BYTESTRING{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length))
+    return u"UA_BYTESTRING{}({})".format("_ALLOC" if alloc else "", splitStringLiterals(value, max_string_length=max_string_length))
 
 def generateLocalizedTextCode(value, alloc=False, max_string_length=0):
     vt = makeCLiteral(value.text)
-    return "UA_LOCALIZEDTEXT{}(\"{}\", {})".format("_ALLOC" if alloc else "", value.locale,
+    return u"UA_LOCALIZEDTEXT{}(\"{}\", {})".format("_ALLOC" if alloc else "", value.locale,
                                                    splitStringLiterals(vt, max_string_length=max_string_length))
 
 def generateQualifiedNameCode(value, alloc=False, max_string_length=0):
     vn = makeCLiteral(value.name)
-    return "UA_QUALIFIEDNAME{}(ns[{}], {})".format("_ALLOC" if alloc else "",
+    return u"UA_QUALIFIEDNAME{}(ns[{}], {})".format("_ALLOC" if alloc else "",
                                                      str(value.ns), splitStringLiterals(vn, max_string_length=max_string_length))
 
 def generateNodeIdCode(value):
@@ -65,7 +65,7 @@ def generateNodeIdCode(value):
         return "UA_NODEID_NUMERIC(ns[%s], %s)" % (value.ns, value.i)
     elif value.s != None:
         v = makeCLiteral(value.s)
-        return "UA_NODEID_STRING(ns[%s], \"%s\")" % (value.ns, v)
+        return u"UA_NODEID_STRING(ns[%s], \"%s\")" % (value.ns, v)
     raise Exception(str(value) + " no NodeID generation for bytestring and guid..")
 
 def generateExpandedNodeIdCode(value):
@@ -73,7 +73,7 @@ def generateExpandedNodeIdCode(value):
         return "UA_EXPANDEDNODEID_NUMERIC(ns[%s], %s)" % (str(value.ns), str(value.i))
     elif value.s != None:
         vs = makeCLiteral(value.s)
-        return "UA_EXPANDEDNODEID_STRING(ns[%s], \"%s\")" % (str(value.ns), vs)
+        return u"UA_EXPANDEDNODEID_STRING(ns[%s], \"%s\")" % (str(value.ns), vs)
     raise Exception(str(value) + " no NodeID generation for bytestring and guid..")
 
 def generateDateTimeCode(value):

+ 12 - 106
tools/schema/datatypes_minimal.txt

@@ -24,7 +24,6 @@ DataValue
 Variant
 DiagnosticInfo
 NodeClass
-ReferenceNode
 ApplicationDescription
 ApplicationType
 ChannelSecurityToken
@@ -42,6 +41,10 @@ ActivateSessionRequest
 ActivateSessionResponse
 SignatureData
 SignedSoftwareCertificate
+ServiceFault
+UserIdentityToken
+UserNameIdentityToken
+AnonymousIdentityToken
 CreateSessionResponse
 CreateSessionRequest
 EndpointDescription
@@ -49,40 +52,30 @@ UserTokenPolicy
 UserTokenType
 GetEndpointsRequest
 GetEndpointsResponse
-PublishRequest
-PublishResponse
 FindServersRequest
 FindServersResponse
-SubscriptionAcknowledgement
+TimestampsToReturn
 ReadRequest
 ReadResponse
 ReadValueId
-TimestampsToReturn
 WriteRequest
 WriteResponse
 WriteValue
-CreateMonitoredItemsResponse
-MonitoredItemCreateResult
-CreateMonitoredItemsRequest
-MonitoredItemCreateRequest
-MonitoringMode
-MonitoringParameters
 TranslateBrowsePathsToNodeIdsRequest
 TranslateBrowsePathsToNodeIdsResponse
+BrowseResultMask
 BrowsePath
 BrowsePathResult
-RelativePath
 BrowsePathTarget
+RelativePath
 RelativePathElement
 BrowseResponse
 BrowseResult
 ReferenceDescription
-BrowseRequest
 ViewDescription
+BrowseRequest
 BrowseNextRequest
 BrowseNextResponse
-DeleteSubscriptionsRequest
-DeleteSubscriptionsResponse
 BrowseDescription
 BrowseDirection
 AddNodesRequest
@@ -92,11 +85,6 @@ AddNodesResult
 AddReferencesRequest
 AddReferencesResponse
 AddReferencesItem
-BrowseResultMask
-ServerState
-ServerStatusDataType
-BuildInfo
-IdType
 NodeAttributes
 VariableAttributes
 ObjectAttributes
@@ -117,93 +105,11 @@ RegisterNodesRequest
 RegisterNodesResponse
 UnregisterNodesRequest
 UnregisterNodesResponse
-UserIdentityToken
-UserNameIdentityToken
-AnonymousIdentityToken
-ServiceFault
-FilterOperator
-ContentFilterElement
-ContentFilter
-QueryDataDescription
-NodeTypeDescription
-QueryFirstRequest
-QueryDataSet
-ParsingResult
-ContentFilterElementResult
-ContentFilterResult
-EventFilterResult
-QueryFirstResponse
-QueryNextRequest
-QueryNextResponse
-CreateSubscriptionRequest
-CreateSubscriptionResponse
-SetPublishingModeRequest
-SetPublishingModeResponse
-DeleteMonitoredItemsRequest
-DeleteMonitoredItemsResponse
-NotificationMessage
-MonitoredItemNotification
-DataChangeNotification
-ModifySubscriptionRequest
-ModifySubscriptionResponse
-RepublishRequest
-RepublishResponse
-MonitoredItemModifyRequest
-ModifyMonitoredItemsRequest
-MonitoredItemModifyResult
-ModifyMonitoredItemsResponse
-SetMonitoringModeRequest
-SetMonitoringModeResponse
-DataChangeTrigger
-DeadbandType
-DataChangeFilter
-EventFilter
-FilterOperand
-ElementOperand
-LiteralOperand
-AttributeOperand
-SimpleAttributeOperand
-EventNotificationList
-EventFieldList
-StatusChangeNotification
-ServerDiagnosticsSummaryDataType
-SubscriptionDiagnosticsDataType
-SessionDiagnosticsDataType
-ServiceCounterDataType
-SessionSecurityDiagnosticsDataType
+ServerState
+ServerStatusDataType
+BuildInfo
 Duration
 UtcTime
 LocaleId
 RedundancySupport
-RedundantServerDataType
-NetworkGroupDataType
-NumericRange
-EndpointUrlListDataType
-ModelChangeStructureDataType
-SemanticChangeStructureDataType
-TimeZoneDataType
-AggregateConfiguration
-AggregateFilter
-SetTriggeringRequest
-SetTriggeringResponse
-KeyValuePair
-NetworkAddressUrlDataType
-ConfigurationVersionDataType
-DataSetMetaDataType
-FieldMetaData
-DataSetFieldFlags
-StructureDescription
-EnumDescription
-StructureDefinition
-EnumDefinition
-StructureType
-StructureField
-EnumField
-PublishedVariableDataType
-UadpDataSetWriterMessageDataType
-UadpWriterGroupMessageDataType
-DataSetOrderingType
-DataSetFieldContentMask
-UadpDataSetMessageContentMask
-UadpNetworkMessageContentMask
-SimpleTypeDescription
+ServerDiagnosticsSummaryDataType

+ 21 - 0
tools/schema/datatypes_pubsub.txt

@@ -0,0 +1,21 @@
+KeyValuePair
+DataSetMetaDataType
+ConfigurationVersionDataType
+UadpDataSetWriterMessageDataType
+UadpWriterGroupMessageDataType
+UadpDataSetMessageContentMask
+UadpNetworkMessageContentMask
+NetworkAddressUrlDataType
+PublishedVariableDataType
+DataSetOrderingType
+DataSetFieldContentMask
+StructureDefinition
+StructureDescription
+StructureType
+StructureField
+EnumField
+EnumDefinition
+EnumDescription
+SimpleTypeDescription
+DataSetFieldFlags
+FieldMetaData

+ 8 - 0
tools/schema/datatypes_query.txt

@@ -0,0 +1,8 @@
+ParsingResult
+NodeTypeDescription
+QueryDataDescription
+QueryDataSet
+QueryFirstRequest
+QueryFirstResponse
+QueryNextRequest
+QueryNextResponse

+ 52 - 0
tools/schema/datatypes_subscriptions.txt

@@ -0,0 +1,52 @@
+SubscriptionAcknowledgement
+FilterOperator
+ContentFilterElement
+ContentFilter
+ContentFilterElementResult
+ContentFilterResult
+EventFilterResult
+DeadbandType
+AggregateConfiguration
+AggregateFilter
+MonitoringMode
+MonitoringParameters
+CreateMonitoredItemsRequest
+MonitoredItemCreateRequest
+MonitoredItemCreateResult
+CreateMonitoredItemsResponse
+MonitoredItemModifyRequest
+ModifyMonitoredItemsRequest
+MonitoredItemModifyResult
+ModifyMonitoredItemsResponse
+SetMonitoringModeRequest
+SetMonitoringModeResponse
+DataChangeTrigger
+SetTriggeringRequest
+SetTriggeringResponse
+DeleteMonitoredItemsRequest
+DeleteMonitoredItemsResponse
+CreateSubscriptionRequest
+CreateSubscriptionResponse
+ModifySubscriptionRequest
+ModifySubscriptionResponse
+SetPublishingModeRequest
+SetPublishingModeResponse
+DataChangeFilter
+EventFilter
+FilterOperand
+ElementOperand
+LiteralOperand
+AttributeOperand
+SimpleAttributeOperand
+EventNotificationList
+EventFieldList
+DataChangeNotification
+NotificationMessage
+MonitoredItemNotification
+StatusChangeNotification
+PublishRequest
+PublishResponse
+RepublishRequest
+RepublishResponse
+DeleteSubscriptionsRequest
+DeleteSubscriptionsResponse

+ 2 - 2
tools/travis/travis_linux_script.sh

@@ -110,7 +110,7 @@ else
     echo -e "\r\n== Full Namespace 0 Generation ==" && echo -en 'travis_fold:start:script.build.ns0\\r'
     mkdir -p build
     cd build
-    cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON -DCMAKE_BUILD_TYPE=Debug -DUA_ENABLE_FULL_NS0=ON -DUA_BUILD_EXAMPLES=ON  \
+    cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON -DCMAKE_BUILD_TYPE=Debug -DUA_NAMESPACE_ZERO=FULL -DUA_BUILD_EXAMPLES=ON  \
     -DUA_ENABLE_SUBSCRIPTIONS_EVENTS=ON ..
     make -j
     if [ $? -ne 0 ] ; then exit 1 ; fi
@@ -238,7 +238,7 @@ else
     echo -e "\r\n== Unit tests (full NS0) ==" && echo -en 'travis_fold:start:script.build.unit_test_ns0_full\\r'
     mkdir -p build && cd build
     # Valgrind cannot handle the full NS0 because the generated file is too big. Thus run NS0 full without valgrind
-    cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON -DUA_ENABLE_FULL_NS0=ON \
+    cmake -DPYTHON_EXECUTABLE:FILEPATH=/usr/bin/$PYTHON -DUA_NAMESPACE_ZERO=FULL \
     -DCMAKE_BUILD_TYPE=Debug -DUA_BUILD_EXAMPLES=ON -DUA_ENABLE_PUBSUB=ON -DUA_ENABLE_ENCRYPTION=ON -DUA_ENABLE_DISCOVERY=ON \
     -DUA_ENABLE_DISCOVERY_MULTICAST=ON -DUA_BUILD_UNIT_TESTS=ON -DUA_ENABLE_COVERAGE=OFF \
     -DUA_ENABLE_UNIT_TESTS_MEMCHECK=OFF -DUA_ENABLE_SUBSCRIPTIONS_EVENTS=ON ..