Browse Source

Merge branch 'master' into inline_setattribute

Conflicts:
	src/server/ua_server_addressspace.c
	src/server/ua_services_attribute.c
Julius Pfrommer 9 years ago
parent
commit
63cdd6d09a

+ 5 - 2
.travis.yml

@@ -80,14 +80,17 @@ script:
 - cp open62541-linux64.tar.gz ..
 - cp open62541.h .. #copy single file-release
 - cp open62541.c .. #copy single file-release
-- cd .. && rm build -rf && mkdir -p build && cd build
 - echo "Upgrade to gcc 4.8"
 - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
 - sudo apt-get update -qq
-- sudo apt-get install -qq gcc-4.8 valgrind
+- sudo apt-get install -qq gcc-4.8 g++-4.8 valgrind
 - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 20
 - sudo update-alternatives --config gcc
 - echo "Compile multithreaded version"
+- echo "Building the C++ example"
+- gcc -std=c99 -c open62541.c
+- g++-4.8 ../examples/server.cpp -I./ open62541.o -o cpp-server
+- cd .. && rm build -rf && mkdir -p build && cd build
 - cmake -DENABLE_MULTITHREADING=ON -DBUILD_EXAMPLESERVER=ON ..
 - make 
 - cd .. && rm build -rf && mkdir -p build && cd build

+ 3 - 1
CMakeLists.txt

@@ -90,6 +90,7 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/examples/logger_stdout.h)
 set(internal_headers ${PROJECT_SOURCE_DIR}/src/ua_util.h
                      ${PROJECT_SOURCE_DIR}/deps/queue.h
+                     ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
@@ -125,7 +126,8 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
                 ${PROJECT_SOURCE_DIR}/src/server/ua_services_view.c
                 ${PROJECT_SOURCE_DIR}/src/client/ua_client.c
                 ${PROJECT_SOURCE_DIR}/examples/networklayer_tcp.c
-                ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c)
+                ${PROJECT_SOURCE_DIR}/examples/logger_stdout.c
+                ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
                 ##TODO: make client stuff optional
 
 ## generate code from xml definitions

+ 3 - 2
README.md

@@ -60,11 +60,12 @@ int main(int argc, char** argv)
     UA_Int32 myInteger = 42;
     UA_Variant_setScalarCopy(myIntegerVariant, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
+    UA_LocalizedText myIntegerBrowseName = UA_LOCALIZEDTEXT("en_US","the answer");
     UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
-                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
+    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName, myIntegerBrowseName, myIntegerBrowseName,
+                              0, 0, parentNodeId, parentReferenceNodeId, myIntegerVariant, NULL);
 
     /* run the server loop */
     UA_StatusCode retval = UA_Server_run(server, WORKER_THREADS, &running);

+ 116 - 0
deps/pcg_basic.c

@@ -0,0 +1,116 @@
+/*
+ * PCG Random Number Generation for C.
+ *
+ * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * For additional information about the PCG random number generation scheme,
+ * including its license and other licensing options, visit
+ *
+ *       http://www.pcg-random.org
+ */
+
+/*
+ * This code is derived from the full C implementation, which is in turn
+ * derived from the canonical C++ PCG implementation. The C++ version
+ * has many additional features and is preferable if you can use C++ in
+ * your project.
+ */
+
+#include "pcg_basic.h"
+
+// state for global RNGs
+
+static pcg32_random_t pcg32_global = PCG32_INITIALIZER;
+
+// pcg32_srandom(initstate, initseq)
+// pcg32_srandom_r(rng, initstate, initseq):
+//     Seed the rng.  Specified in two parts, state initializer and a
+//     sequence selection constant (a.k.a. stream id)
+
+void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq)
+{
+    rng->state = 0U;
+    rng->inc = (initseq << 1u) | 1u;
+    pcg32_random_r(rng);
+    rng->state += initstate;
+    pcg32_random_r(rng);
+}
+
+void pcg32_srandom(uint64_t seed, uint64_t seq)
+{
+    pcg32_srandom_r(&pcg32_global, seed, seq);
+}
+
+// pcg32_random()
+// pcg32_random_r(rng)
+//     Generate a uniformly distributed 32-bit random number
+
+uint32_t pcg32_random_r(pcg32_random_t* rng)
+{
+    uint64_t oldstate = rng->state;
+    rng->state = oldstate * 6364136223846793005ULL + rng->inc;
+    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
+    uint32_t rot = oldstate >> 59u;
+    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
+}
+
+uint32_t pcg32_random()
+{
+    return pcg32_random_r(&pcg32_global);
+}
+
+
+// pcg32_boundedrand(bound):
+// pcg32_boundedrand_r(rng, bound):
+//     Generate a uniformly distributed number, r, where 0 <= r < bound
+
+uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound)
+{
+    // To avoid bias, we need to make the range of the RNG a multiple of
+    // bound, which we do by dropping output less than a threshold.
+    // A naive scheme to calculate the threshold would be to do
+    //
+    //     uint32_t threshold = 0x100000000ull % bound;
+    //
+    // but 64-bit div/mod is slower than 32-bit div/mod (especially on
+    // 32-bit platforms).  In essence, we do
+    //
+    //     uint32_t threshold = (0x100000000ull-bound) % bound;
+    //
+    // because this version will calculate the same modulus, but the LHS
+    // value is less than 2^32.
+
+    uint32_t threshold = -bound % bound;
+
+    // Uniformity guarantees that this loop will terminate.  In practice, it
+    // should usually terminate quickly; on average (assuming all bounds are
+    // equally likely), 82.25% of the time, we can expect it to require just
+    // one iteration.  In the worst case, someone passes a bound of 2^31 + 1
+    // (i.e., 2147483649), which invalidates almost 50% of the range.  In 
+    // practice, bounds are typically small and only a tiny amount of the range
+    // is eliminated.
+    for (;;) {
+        uint32_t r = pcg32_random_r(rng);
+        if (r >= threshold)
+            return r % bound;
+    }
+}
+
+
+uint32_t pcg32_boundedrand(uint32_t bound)
+{
+    return pcg32_boundedrand_r(&pcg32_global, bound);
+}
+

+ 78 - 0
deps/pcg_basic.h

@@ -0,0 +1,78 @@
+/*
+ * PCG Random Number Generation for C.
+ *
+ * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * For additional information about the PCG random number generation scheme,
+ * including its license and other licensing options, visit
+ *
+ *     http://www.pcg-random.org
+ */
+
+/*
+ * This code is derived from the full C implementation, which is in turn
+ * derived from the canonical C++ PCG implementation. The C++ version
+ * has many additional features and is preferable if you can use C++ in
+ * your project.
+ */
+
+#ifndef PCG_BASIC_H_INCLUDED
+#define PCG_BASIC_H_INCLUDED 1
+
+#include <inttypes.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+struct pcg_state_setseq_64 {    // Internals are *Private*.
+    uint64_t state;             // RNG state.  All values are possible.
+    uint64_t inc;               // Controls which RNG sequence (stream) is
+                                // selected. Must *always* be odd.
+};
+typedef struct pcg_state_setseq_64 pcg32_random_t;
+
+// If you *must* statically initialize it, here's one.
+
+#define PCG32_INITIALIZER   { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }
+
+// pcg32_srandom(initstate, initseq)
+// pcg32_srandom_r(rng, initstate, initseq):
+//     Seed the rng.  Specified in two parts, state initializer and a
+//     sequence selection constant (a.k.a. stream id)
+
+void pcg32_srandom(uint64_t initstate, uint64_t initseq);
+void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate,
+                     uint64_t initseq);
+
+// pcg32_random()
+// pcg32_random_r(rng)
+//     Generate a uniformly distributed 32-bit random number
+
+uint32_t pcg32_random(void);
+uint32_t pcg32_random_r(pcg32_random_t* rng);
+
+// pcg32_boundedrand(bound):
+// pcg32_boundedrand_r(rng, bound):
+//     Generate a uniformly distributed number, r, where 0 <= r < bound
+
+uint32_t pcg32_boundedrand(uint32_t bound);
+uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound);
+
+#if __cplusplus
+}
+#endif
+
+#endif // PCG_BASIC_H_INCLUDED

+ 3 - 3
doc/mainpage.dox

@@ -11,12 +11,12 @@ late, OPC UA is marketed as the one standard for non-realtime industrial communi
 
 We believe that it is best to understand OPC UA <em>from the inside out</em>, building upon conceptually
 simple first principles. After establishing a first understanding, we go on explaining how these
-principles are realized in detail. Examples are given based on the </em>open62541</em> implementation of the
+principles are realized in detail. Examples are given based on the <em>open62541</em> implementation of the
 standard.
 
 <h2>OPC UA, a collection of services</h2>
 
-In OPC-UA, all communication is based on service calls, each consisting of a request and a response
+In OPC UA, all communication is based on service calls, each consisting of a request and a response
 message. Be careful to note the difference between services and methods. Services are pre-defined in
 the standard and cannot be changed. But you can use the <em>Call</em> service to invoke user-defined
 methods on the server.
@@ -96,7 +96,7 @@ open62541, these are defined in ua_types.h.
 <tr> <td>UInt64</td> <td>ExpandedNodeId</td> <td> </td> </tr>
 </table>
 
-The builtin datatypes are combined to more complex structures. When the structure contains an array,
+The builtin datatypes are combined into more complex structures. When the structure contains an array,
 then the size of the array is stored in an Int32 value just before the array itself. A size of -1
 indicates an undefined array. Positive sizes (and zero) have the usual semantics.
 

+ 4 - 4
examples/server.c

@@ -46,7 +46,7 @@ UA_Logger logger;
 /*************************/
 /* Read-only data source */
 /*************************/
-static UA_StatusCode readTimeData(void *handle, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
+static UA_StatusCode readTimeData(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = UA_TRUE;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
@@ -72,7 +72,7 @@ static UA_StatusCode readTimeData(void *handle, UA_Boolean sourceTimeStamp, cons
 /*      Only on Linux        */
 /*****************************/
 FILE* temperatureFile = NULL;
-static UA_StatusCode readTemperature(void *handle, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
+static UA_StatusCode readTemperature(void *handle, const UA_NodeId nodeId, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = UA_TRUE;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
@@ -115,7 +115,7 @@ FILE* triggerFile = NULL;
 FILE* ledFile = NULL;
 UA_Boolean ledStatus = 0;
 
-static UA_StatusCode readLedStatus(void *handle, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
+static UA_StatusCode readLedStatus(void *handle, UA_NodeId nodeid, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
   if(range)
     return UA_STATUSCODE_BADINDEXRANGEINVALID;
 
@@ -132,7 +132,7 @@ static UA_StatusCode readLedStatus(void *handle, UA_Boolean sourceTimeStamp, con
   return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode writeLedStatus(void *handle, const UA_Variant *data, const UA_NumericRange *range) {
+static UA_StatusCode writeLedStatus(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range) {
     if(range)
         return UA_STATUSCODE_BADINDEXRANGEINVALID;
 

+ 5 - 2
examples/server.cpp

@@ -37,8 +37,11 @@ int main()
     UA_NodeId myIntegerNodeId = UA_NODEID_NULL; /* assign a random free nodeid */
     UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
     UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
-    UA_Server_addVariableNode(server, myIntegerVariant, myIntegerName,
-                              myIntegerNodeId, parentNodeId, parentReferenceNodeId);
+    UA_Server_addVariableNode(server, myIntegerNodeId, myIntegerName,
+                              UA_LOCALIZEDTEXT("", "the.answer"),
+                              UA_LOCALIZEDTEXT("", ""), 0, 0,
+                              parentNodeId, parentReferenceNodeId,
+                              myIntegerVariant, NULL);
 
     UA_Boolean running = UA_TRUE;
     UA_StatusCode retval = UA_Server_run(server, 1, &running);

+ 6 - 2
examples/server_datasource.c

@@ -23,17 +23,21 @@ static void stopHandler(int sign) {
     running = 0;
 }
 
-static UA_StatusCode readInteger(void *handle, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *dataValue) {
+static UA_StatusCode readInteger(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *dataValue) {
     dataValue->hasValue = UA_TRUE;
     UA_Variant_setScalarCopy(&dataValue->value, (UA_UInt32*)handle, &UA_TYPES[UA_TYPES_INT32]);
+    //note that this is only possible if the identifier is a string - but we are sure to have one here
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node read %.*s",nodeid.identifier.string.length, nodeid.identifier.string.data);
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "read value %i", *(UA_UInt32*)handle);
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode writeInteger(void *handle, const UA_Variant *data, const UA_NumericRange *range){
+static UA_StatusCode writeInteger(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range){
     if(UA_Variant_isScalar(data) && data->type == &UA_TYPES[UA_TYPES_INT32] && data->data){
         *(UA_UInt32*)handle = *(UA_Int32*)data->data;
     }
+    //note that this is only possible if the identifier is a string - but we are sure to have one here
+    UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "Node written %.*s",nodeid.identifier.string.length, nodeid.identifier.string.data);
     UA_LOG_INFO(logger, UA_LOGCATEGORY_USERLAND, "written value %i", *(UA_UInt32*)handle);
     return UA_STATUSCODE_GOOD;
 }

+ 4 - 2
include/ua_server.h

@@ -93,6 +93,7 @@ typedef struct {
      * Copies the data from the source into the provided value.
      *
      * @param handle An optional pointer to user-defined data for the specific data source
+     * @param nodeid Id of the read node
      * @param includeSourceTimeStamp If true, then the datasource is expected to set the source
      *        timestamp in the returned value
      * @param range If not null, then the datasource shall return only a selection of the (nonscalar)
@@ -102,19 +103,20 @@ typedef struct {
      * @return Returns a status code for logging. Error codes intended for the original caller are set
      *         in the value. If an error is returned, then no releasing of the value is done.
      */
-    UA_StatusCode (*read)(void *handle, UA_Boolean includeSourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value);
+    UA_StatusCode (*read)(void *handle, const UA_NodeId nodeid,  UA_Boolean includeSourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value);
 
     /**
      * Write into a data source. The write member of UA_DataSource can be empty if the operation
      * is unsupported.
      *
      * @param handle An optional pointer to user-defined data for the specific data source
+     * @param nodeid Id of the node being written to
      * @param data The data to be written into the data source
      * @param range An optional data range. If the data source is scalar or does not support writing
      *        of ranges, then an error code is returned.
      * @return Returns a status code that is returned to the user
      */
-    UA_StatusCode (*write)(void *handle, const UA_Variant *data, const UA_NumericRange *range);
+    UA_StatusCode (*write)(void *handle, const UA_NodeId nodeid, const UA_Variant *data, const UA_NumericRange *range);
 } UA_DataSource;
 
 /** @brief Add a new namespace to the server. Returns the index of the new namespace */

+ 3 - 2
include/ua_statuscodes.h

@@ -1,7 +1,8 @@
 #ifndef OPCUA_STATUSCODES_H_
 #define OPCUA_STATUSCODES_H_
 
-enum UA_StatusCode {
+/** A numeric identifier for a error or condition that is associated with a value or an operation. */
+typedef enum {
 	UA_STATUSCODE_GOOD = 0x00,
 	UA_STATUSCODE_BADUNEXPECTEDERROR = 0x80010000, // An unexpected error occurred.
 	UA_STATUSCODE_BADINTERNALERROR = 0x80020000, // An internal error occurred as a result of a programming or configuration error.
@@ -219,6 +220,6 @@ enum UA_StatusCode {
 	UA_STATUSCODE_BADWOULDBLOCK = 0x80b50000, // Non blocking behaviour is required and the operation would block.
 	UA_STATUSCODE_BADSYNTAXERROR = 0x80b60000, // A value had an invalid syntax.
 	UA_STATUSCODE_BADMAXCONNECTIONSREACHED = 0x80b70000 // The operation could not be finished because all available connections are in use.
-};
+} UA_StatusCode;
 
 #endif /* UA_STATUSCODES_H_ */

+ 248 - 169
include/ua_types.h

@@ -20,76 +20,77 @@
 extern "C" {
 #endif
 
+#ifndef UA_FFI_BINDINGS
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <string.h>
+#endif
 #include "ua_config.h"
+#include "ua_statuscodes.h"
 
-/** @brief A two-state logical value (true or false). */
+/** A two-state logical value (true or false). */
 typedef bool UA_Boolean;
 #define UA_TRUE true
 #define UA_FALSE false
 
-/** @brief An integer value between -128 and 127. */
+/** An integer value between -128 and 127. */
 typedef int8_t UA_SByte;
 #define UA_SBYTE_MAX 127
 #define UA_SBYTE_MIN -128
 
-/** @brief An integer value between 0 and 256. */
+/** An integer value between 0 and 256. */
 typedef uint8_t UA_Byte;
 #define UA_BYTE_MAX 256
 #define UA_BYTE_MIN 0
 
-/** @brief An integer value between -32 768 and 32 767. */
+/** An integer value between -32 768 and 32 767. */
 typedef int16_t UA_Int16;
 #define UA_INT16_MAX 32767
 #define UA_INT16_MIN -32768
 
-/** @brief An integer value between 0 and 65 535. */
+/** An integer value between 0 and 65 535. */
 typedef uint16_t UA_UInt16;
 #define UA_UINT16_MAX 65535
 #define UA_UINT16_MIN 0
 
-/** @brief An integer value between -2 147 483 648 and 2 147 483 647. */
+/** An integer value between -2 147 483 648 and 2 147 483 647. */
 typedef int32_t UA_Int32;
 #define UA_INT32_MAX 2147483647
 #define UA_INT32_MIN -2147483648
 
-/** @brief An integer value between 0 and 429 4967 295. */
+/** An integer value between 0 and 429 4967 295. */
 typedef uint32_t UA_UInt32;
 #define UA_UINT32_MAX 4294967295
 #define UA_UINT32_MIN 0
 
-/** @brief An integer value between -10 223 372 036 854 775 808 and 9 223 372 036 854 775 807 */
+/** An integer value between -10 223 372 036 854 775 808 and 9 223 372 036 854 775 807 */
 typedef int64_t UA_Int64;
 #define UA_INT64_MAX (int64_t)9223372036854775807
 #define UA_INT64_MIN (int64_t)-9223372036854775808
 
-/** @brief An integer value between 0 and 18 446 744 073 709 551 615. */
+/** An integer value between 0 and 18 446 744 073 709 551 615. */
 typedef uint64_t UA_UInt64;
 #define UA_UINT64_MAX (int64_t)18446744073709551615
 #define UA_UINT64_MIN (int64_t)0
 
-/** @brief An IEEE single precision (32 bit) floating point value. */
+/** An IEEE single precision (32 bit) floating point value. */
 typedef float UA_Float;
 
-/** @brief An IEEE double precision (64 bit) floating point value. */
+/** An IEEE double precision (64 bit) floating point value. */
 typedef double UA_Double;
 
-/** @brief A sequence of Unicode characters. */
+/** A sequence of Unicode characters. */
 typedef struct {
     UA_Int32 length; ///< The length of the string
     UA_Byte *data; ///< The string's content (not null-terminated)
 } UA_String;
 
-/** @brief An instance in time.
- * A DateTime value is encoded as a 64-bit signed integer which represents the
- * number of 100 nanosecond intervals since January 1, 1601 (UTC).
- */
-typedef UA_Int64 UA_DateTime; // 100 nanosecond resolution
+/** An instance in time. A DateTime value is encoded as a 64-bit signed integer which represents the
+    number of 100 nanosecond intervals since January 1, 1601 (UTC). */
+typedef UA_Int64 UA_DateTime;
 
-/** @brief A 16 byte value that can be used as a globally unique identifier. */
+/** A 16 byte value that can be used as a globally unique identifier. */
 typedef struct {
     UA_UInt32 data1;
     UA_UInt16 data2;
@@ -97,14 +98,12 @@ typedef struct {
     UA_Byte   data4[8];
 } UA_Guid;
 
-/** @brief A sequence of octets. */
+/** A sequence of octets. */
 typedef UA_String UA_ByteString;
 
-/** @brief An XML element. */
+/** An XML element. */
 typedef UA_String UA_XmlElement;
 
-/** @brief An identifier for a node in the address space of an OPC UA Server. */
-/* The shortened numeric types are introduced during encoding. */
 enum UA_NodeIdType {
     UA_NODEIDTYPE_NUMERIC    = 2,
     UA_NODEIDTYPE_STRING     = 3,
@@ -112,6 +111,8 @@ enum UA_NodeIdType {
     UA_NODEIDTYPE_BYTESTRING = 5
 };
 
+/** An identifier for a node in the address space of an OPC UA Server. The shortened numeric types
+    are introduced during encoding. */
 typedef struct {
     UA_UInt16 namespaceIndex; ///< The namespace index of the node
     enum UA_NodeIdType identifierType; ///< The type of the node identifier
@@ -123,31 +124,27 @@ typedef struct {
     } identifier; ///< The node identifier
 } UA_NodeId;
 
-/** @brief A NodeId that allows the namespace URI to be specified instead of an index. */
+/** A NodeId that allows the namespace URI to be specified instead of an index. */
 typedef struct {
     UA_NodeId nodeId; ///< The nodeid without extensions
     UA_String namespaceUri; ///< The Uri of the namespace (tindex in the nodeId is ignored)
     UA_UInt32 serverIndex;  ///< The index of the server
 } UA_ExpandedNodeId;
 
-#include "ua_statuscodes.h"
-/** @brief A numeric identifier for a error or condition that is associated with a value or an operation. */
-typedef enum UA_StatusCode UA_StatusCode; // StatusCodes aren't an enum(=int) since 32 unsigned bits are needed. See also ua_statuscodes.h */
-
-/** @brief A name qualified by a namespace. */
+/** A name qualified by a namespace. */
 typedef struct {
     UA_UInt16 namespaceIndex; ///< The namespace index
     UA_String name; ///< The actual name
 } UA_QualifiedName;
 
-/** @brief Human readable text with an optional locale identifier. */
+/** Human readable text with an optional locale identifier. */
 typedef struct {
     UA_String locale; ///< The locale (e.g. "en-US")
     UA_String text; ///< The actual text
 } UA_LocalizedText;
 
-/** @brief A structure that contains an application specific data type that may
-    not be recognized by the receiver. */
+/** A structure that contains an application specific data type that may not be recognized by the
+    receiver. */
 typedef struct {
     UA_NodeId typeId; ///< The nodeid of the datatype
     enum {
@@ -158,10 +155,24 @@ typedef struct {
     UA_ByteString body; ///< The bytestring of the encoded data
 } UA_ExtensionObject;
 
+/* Forward Declaration of UA_DataType */
 struct UA_DataType;
 typedef struct UA_DataType UA_DataType; 
 
-/** @brief Variants store (arrays of) any data type. Either they provide a pointer to the data in
+/* NumericRanges are used select a subset in a (multidimensional) variant array.
+ * NumericRange has no official type structure in the standard. On the wire, it
+ * only exists as an encoded string, such as "1:2,0:3,5". The colon separates
+ * min/max index and the comma separates dimensions. A single value indicates a
+ * range with a single element (min==max). */
+typedef struct {
+    UA_Int32 dimensionsSize;
+    struct UA_NumericRangeDimension {
+        UA_UInt32 min;
+        UA_UInt32 max;
+    } *dimensions;
+} UA_NumericRange;
+
+ /** Variants store (arrays of) any data type. Either they provide a pointer to the data in
  *   memory, or functions from which the data can be accessed. Variants are replaced together with
  *   the data they store (exception: use a data source).
  *
@@ -171,7 +182,6 @@ typedef struct UA_DataType UA_DataType;
  *  - arrayLength >= 0: variant holds an array of the appropriate length
  *                      data can be NULL if arrayLength == 0
  */
-
 typedef struct {
     const UA_DataType *type; ///< The nodeid of the datatype
     enum {
@@ -187,7 +197,7 @@ typedef struct {
     UA_Int32 *arrayDimensions; ///< the length of each dimension of the data-array
 } UA_Variant;
 
-/** @brief A data value with an associated status code and timestamps. */
+/** A data value with an associated status code and timestamps. */
 typedef struct {
     UA_Boolean    hasValue : 1;
     UA_Boolean    hasStatus : 1;
@@ -203,7 +213,7 @@ typedef struct {
     UA_Int16      serverPicoseconds;
 } UA_DataValue;
 
-/** @brief A structure that contains detailed error and diagnostic information associated with a StatusCode. */
+/** A structure that contains detailed error and diagnostic information associated with a StatusCode. */
 typedef struct UA_DiagnosticInfo {
     UA_Boolean    hasSymbolicId : 1;
     UA_Boolean    hasNamespaceUri : 1;
@@ -221,78 +231,108 @@ typedef struct UA_DiagnosticInfo {
     struct UA_DiagnosticInfo *innerDiagnosticInfo;
 } UA_DiagnosticInfo;
 
-#define UA_TYPE_HANDLING_FUNCTIONS(TYPE)                             \
-    TYPE UA_EXPORT * TYPE##_new(void);                               \
-    void UA_EXPORT TYPE##_init(TYPE * p);                            \
-    void UA_EXPORT TYPE##_delete(TYPE * p);                          \
-    void UA_EXPORT TYPE##_deleteMembers(TYPE * p);                   \
-    UA_StatusCode UA_EXPORT TYPE##_copy(const TYPE *src, TYPE *dst);
-
-/* Functions for all types */
-UA_TYPE_HANDLING_FUNCTIONS(UA_Boolean)
-UA_TYPE_HANDLING_FUNCTIONS(UA_SByte)
-UA_TYPE_HANDLING_FUNCTIONS(UA_Byte)
-UA_TYPE_HANDLING_FUNCTIONS(UA_Int16)
-UA_TYPE_HANDLING_FUNCTIONS(UA_UInt16)
-UA_TYPE_HANDLING_FUNCTIONS(UA_Int32)
-UA_TYPE_HANDLING_FUNCTIONS(UA_UInt32)
-UA_TYPE_HANDLING_FUNCTIONS(UA_Int64)
-UA_TYPE_HANDLING_FUNCTIONS(UA_UInt64)
-UA_TYPE_HANDLING_FUNCTIONS(UA_Float)
-UA_TYPE_HANDLING_FUNCTIONS(UA_Double)
-UA_TYPE_HANDLING_FUNCTIONS(UA_String)
-#define UA_DateTime_new UA_Int64_new
-#define UA_DateTime_init UA_Int64_init
-#define UA_DateTime_delete UA_Int64_delete
-#define UA_DateTime_deleteMembers UA_Int64_deleteMembers
-#define UA_DateTime_copy UA_Int64_copy
-UA_TYPE_HANDLING_FUNCTIONS(UA_Guid)
-#define UA_ByteString_new UA_String_new
-#define UA_ByteString_init UA_String_init
-#define UA_ByteString_delete UA_String_delete
-#define UA_ByteString_deleteMembers UA_String_deleteMembers
-#define UA_ByteString_copy UA_String_copy
-#define UA_XmlElement_new UA_String_new
-#define UA_XmlElement_init UA_String_init
-#define UA_XmlElement_delete UA_String_delete
-#define UA_XmlElement_deleteMembers UA_String_deleteMembers
-#define UA_XmlElement_copy UA_String_copy
-UA_TYPE_HANDLING_FUNCTIONS(UA_NodeId)
-UA_TYPE_HANDLING_FUNCTIONS(UA_ExpandedNodeId)
-#define UA_StatusCode_new() UA_Int32_new()
-#define UA_StatusCode_init(p) UA_Int32_init((UA_Int32*)p)
-#define UA_StatusCode_delete(p) UA_Int32_delete((UA_Int32*)p)
-#define UA_StatusCode_deleteMembers(p) UA_Int32_deleteMembers((UA_Int32*)p)
-#define UA_StatusCode_copy(p, q) UA_Int32_copy((UA_Int32*)p, (UA_Int32*)q)
-UA_TYPE_HANDLING_FUNCTIONS(UA_QualifiedName)
-UA_TYPE_HANDLING_FUNCTIONS(UA_LocalizedText)
-UA_TYPE_HANDLING_FUNCTIONS(UA_ExtensionObject)
-UA_TYPE_HANDLING_FUNCTIONS(UA_DataValue)
-UA_TYPE_HANDLING_FUNCTIONS(UA_Variant)
-UA_TYPE_HANDLING_FUNCTIONS(UA_DiagnosticInfo)
-
-/**********************************************/
-/* Custom functions for the builtin datatypes */
-/**********************************************/
+/***************************/
+/* Type Handling Functions */
+/***************************/
+
+/* Boolean */
+UA_Boolean UA_EXPORT * UA_Boolean_new(void);
+static UA_INLINE void UA_Boolean_init(UA_Boolean *p) { *p = UA_FALSE; }
+void UA_EXPORT UA_Boolean_delete(UA_Boolean *p);
+static UA_INLINE void UA_Boolean_deleteMembers(UA_Boolean *p) { }
+static UA_INLINE UA_StatusCode UA_Boolean_copy(const UA_Boolean *src, UA_Boolean *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* SByte */
+UA_SByte UA_EXPORT * UA_SByte_new(void);
+static UA_INLINE void UA_SByte_init(UA_SByte *p) { *p = 0; }
+void UA_EXPORT UA_SByte_delete(UA_SByte *p);
+static UA_INLINE void UA_SByte_deleteMembers(UA_SByte *p) { }
+static UA_INLINE UA_StatusCode UA_SByte_copy(const UA_SByte *src, UA_SByte *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* Byte */
+UA_Byte UA_EXPORT * UA_Byte_new(void);
+static UA_INLINE void UA_Byte_init(UA_Byte *p) { *p = 0; }
+void UA_EXPORT UA_Byte_delete(UA_Byte *p);
+static UA_INLINE void UA_Byte_deleteMembers(UA_Byte *p) { }
+static UA_INLINE UA_StatusCode UA_Byte_copy(const UA_Byte *src, UA_Byte *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* Int16 */
+UA_Int16 UA_EXPORT * UA_Int16_new(void);
+static UA_INLINE void UA_Int16_init(UA_Int16 *p) { *p = 0; }
+void UA_EXPORT UA_Int16_delete(UA_Int16 *p);
+static UA_INLINE void UA_Int16_deleteMembers(UA_Int16 *p) { }
+static UA_INLINE UA_StatusCode UA_Int16_copy(const UA_Int16 *src, UA_Int16 *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* UInt16 */
+UA_UInt16 UA_EXPORT * UA_UInt16_new(void);
+static UA_INLINE void UA_UInt16_init(UA_UInt16 *p) { *p = 0; }
+void UA_EXPORT UA_UInt16_delete(UA_UInt16 *p);
+static UA_INLINE void UA_UInt16_deleteMembers(UA_UInt16 *p) { }
+static UA_INLINE UA_StatusCode UA_UInt16_copy(const UA_UInt16 *src, UA_UInt16 *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* Int32 */
+UA_Int32 UA_EXPORT * UA_Int32_new(void);
+static UA_INLINE void UA_Int32_init(UA_Int32 *p) { *p = 0; }
+void UA_EXPORT UA_Int32_delete(UA_Int32 *p);
+static UA_INLINE void UA_Int32_deleteMembers(UA_Int32 *p) { }
+static UA_INLINE UA_StatusCode UA_Int32_copy(const UA_Int32 *src, UA_Int32 *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* UInt32 */
+UA_UInt32 UA_EXPORT * UA_UInt32_new(void);
+static UA_INLINE void UA_UInt32_init(UA_UInt32 *p) { *p = 0; }
+void UA_EXPORT UA_UInt32_delete(UA_UInt32 *p);
+static UA_INLINE void UA_UInt32_deleteMembers(UA_UInt32 *p) { }
+static UA_INLINE UA_StatusCode UA_UInt32_copy(const UA_UInt32 *src, UA_UInt32 *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* Int64 */
+UA_Int64 UA_EXPORT * UA_Int64_new(void);
+static UA_INLINE void UA_Int64_init(UA_Int64 *p) { *p = 0; }
+void UA_EXPORT UA_Int64_delete(UA_Int64 *p);
+static UA_INLINE void UA_Int64_deleteMembers(UA_Int64 *p) { }
+static UA_INLINE UA_StatusCode UA_Int64_copy(const UA_Int64 *src, UA_Int64 *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* UInt64 */
+UA_UInt64 UA_EXPORT * UA_UInt64_new(void);
+static UA_INLINE void UA_UInt64_init(UA_UInt64 *p) { *p = 0; }
+void UA_EXPORT UA_UInt64_delete(UA_UInt64 *p);
+static UA_INLINE void UA_UInt64_deleteMembers(UA_UInt64 *p) { }
+static UA_INLINE UA_StatusCode UA_UInt64_copy(const UA_UInt64 *src, UA_UInt64 *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* Float */
+UA_Float UA_EXPORT * UA_Float_new(void);
+static UA_INLINE void UA_Float_init(UA_Float *p) { *p = 0.0f; }
+void UA_EXPORT UA_Float_delete(UA_Float *p);
+static UA_INLINE void UA_Float_deleteMembers(UA_Float *p) { }
+static UA_INLINE UA_StatusCode UA_Float_copy(const UA_Float *src, UA_Float *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
+/* Double */
+UA_Double UA_EXPORT * UA_Double_new(void);
+static UA_INLINE void UA_Double_init(UA_Double *p) { *p = 0.0f; }
+void UA_EXPORT UA_Double_delete(UA_Double *p);
+static UA_INLINE void UA_Double_deleteMembers(UA_Double *p) { }
+static UA_INLINE UA_StatusCode UA_Double_copy(const UA_Double *src, UA_Double *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
 
 /* String */
-/** Copy a (zero terminated) char-array into a UA_String. Memory for the string data is
-    allocated. If the memory cannot be allocated, a null-string is returned. */
-UA_String UA_EXPORT UA_String_fromChars(char const src[]);
-
+UA_String UA_EXPORT * UA_String_new(void);
+void UA_EXPORT UA_String_init(UA_String *p);
+void UA_EXPORT UA_String_delete(UA_String *p);
+void UA_EXPORT UA_String_deleteMembers(UA_String *p);
+UA_StatusCode UA_EXPORT UA_String_copy(const UA_String *src, UA_String *dst);
+UA_String UA_EXPORT UA_String_fromChars(char const src[]); ///> Copies the char-array on the heap. Returns a null-string when alloc fails.
+UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2); ///> Compares two strings
+UA_StatusCode UA_EXPORT UA_String_copyprintf(char const fmt[], UA_String *dst, ...); ///> Printf a char-array into a UA_String. Memory for the string data is allocated.
 #define UA_STRING_NULL (UA_String) {-1, (UA_Byte*)0 }
 #define UA_STRING(CHARS) (UA_String) {strlen(CHARS), (UA_Byte*)CHARS }
 #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
 
-/** Compares two strings */
-UA_Boolean UA_EXPORT UA_String_equal(const UA_String *string1, const UA_String *string2);
-
-/** Printf a char-array into a UA_String. Memory for the string data is allocated. */
-UA_StatusCode UA_EXPORT UA_String_copyprintf(char const fmt[], UA_String *dst, ...);
-
 /* DateTime */
-/** Returns the current time */
-UA_DateTime UA_EXPORT UA_DateTime_now(void);
+UA_DateTime UA_EXPORT * UA_DateTime_new(void);
+static UA_INLINE void UA_DateTime_init(UA_DateTime *p) { *p = 0.0f; }
+void UA_EXPORT UA_DateTime_delete(UA_DateTime *p);
+static UA_INLINE void UA_DateTime_deleteMembers(UA_DateTime *p) { }
+static UA_INLINE UA_StatusCode UA_DateTime_copy(const UA_DateTime *src, UA_DateTime *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+UA_DateTime UA_EXPORT UA_DateTime_now(void); ///> The current time
+UA_StatusCode UA_EXPORT UA_DateTime_toString(UA_DateTime time, UA_String *timeString);
 
 typedef struct UA_DateTimeStruct {
     UA_Int16 nanoSec;
@@ -307,30 +347,41 @@ typedef struct UA_DateTimeStruct {
 } UA_DateTimeStruct;
 
 UA_DateTimeStruct UA_EXPORT UA_DateTime_toStruct(UA_DateTime time);
-UA_StatusCode UA_EXPORT UA_DateTime_toString(UA_DateTime time, UA_String *timeString);
 
 /* Guid */
-/** Compares two guids */
+UA_Guid UA_EXPORT * UA_Guid_new(void);
+static UA_INLINE void UA_Guid_init(UA_Guid *p) { *p = (UA_Guid){0,0,0,{0,0,0,0,0,0,0,0}}; }
+void UA_EXPORT UA_Guid_delete(UA_Guid *p);
+static UA_INLINE void UA_Guid_deleteMembers(UA_Guid *p) { }
+static UA_INLINE UA_StatusCode UA_Guid_copy(const UA_Guid *src, UA_Guid *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
 UA_Boolean UA_EXPORT UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2);
-    
-/** Returns a randomly generated guid. Do not use for security-critical entropy! */
-UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed);
+UA_Guid UA_EXPORT UA_Guid_random(UA_UInt32 *seed); ///> Do not use for security-critical entropy!
 
 /* ByteString */
+static UA_INLINE UA_ByteString * UA_ByteString_new(void) { return UA_String_new(); }
+static UA_INLINE void UA_ByteString_init(UA_ByteString *p) { UA_String_init(p); }
+static UA_INLINE void UA_ByteString_delete(UA_ByteString *p) { UA_String_delete(p); }
+static UA_INLINE void UA_ByteString_deleteMembers(UA_ByteString *p) { UA_String_deleteMembers(p); }
+static UA_INLINE UA_StatusCode UA_ByteString_copy(const UA_ByteString *src, UA_ByteString *dst) { return UA_String_copy(src, dst); }
 #define UA_BYTESTRING_NULL (UA_ByteString) {-1, (UA_Byte*)0 }
-#define UA_ByteString_equal(string1, string2) \
-    UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
+#define UA_ByteString_equal(string1, string2) UA_String_equal((const UA_String*) string1, (const UA_String*)string2)
+UA_StatusCode UA_EXPORT UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length); ///> Allocates memory of size length for the bytestring. The content is not set to zero.
 
-/** Allocates memory of size length for the bytestring. The content is not set to zero. */
-UA_StatusCode UA_EXPORT UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length);
+/* XmlElement */
+static UA_INLINE UA_XmlElement * UA_XmlElement_new(void) { return UA_String_new(); }
+static UA_INLINE void UA_XmlElement_init(UA_XmlElement *p) { UA_String_init(p); }
+static UA_INLINE void UA_XmlElement_delete(UA_XmlElement *p) { UA_String_delete(p); }
+static UA_INLINE void UA_XmlElement_deleteMembers(UA_XmlElement *p) { UA_String_deleteMembers(p); }
+static UA_INLINE UA_StatusCode UA_XmlElement_copy(const UA_XmlElement *src, UA_XmlElement *dst) { return UA_String_copy(src, dst); }
 
 /* NodeId */
-/** Compares two nodeids */
+UA_NodeId UA_EXPORT * UA_NodeId_new(void);
+void UA_EXPORT UA_NodeId_init(UA_NodeId *p);
+void UA_EXPORT UA_NodeId_delete(UA_NodeId *p);
+void UA_EXPORT UA_NodeId_deleteMembers(UA_NodeId *p);
+UA_StatusCode UA_EXPORT UA_NodeId_copy(const UA_NodeId *src, UA_NodeId *dst);
 UA_Boolean UA_EXPORT UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2);
-
-/** Is the nodeid a null-nodeid? */
 UA_Boolean UA_EXPORT UA_NodeId_isNull(const UA_NodeId *p);
-
 UA_NodeId UA_EXPORT UA_NodeId_fromInteger(UA_UInt16 nsIndex, UA_Int32 identifier);
 UA_NodeId UA_EXPORT UA_NodeId_fromCharString(UA_UInt16 nsIndex, char identifier[]);
 UA_NodeId UA_EXPORT UA_NodeId_fromCharStringCopy(UA_UInt16 nsIndex, char const identifier[]);
@@ -341,36 +392,64 @@ UA_NodeId UA_EXPORT UA_NodeId_fromCharByteString(UA_UInt16 nsIndex, char identif
 UA_NodeId UA_EXPORT UA_NodeId_fromCharByteStringCopy(UA_UInt16 nsIndex, char const identifier[]);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteString(UA_UInt16 nsIndex, UA_ByteString identifier);
 UA_NodeId UA_EXPORT UA_NodeId_fromByteStringCopy(UA_UInt16 nsIndex, UA_ByteString identifier);
-
 #define UA_NODEID_NUMERIC(NSID, NUMERICID) UA_NodeId_fromInteger(NSID, NUMERICID)
 #define UA_NODEID_STRING(NSID, CHARS) UA_NodeId_fromCharString(NSID, CHARS)
 #define UA_NODEID_STRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharStringCopy(NSID, CHARS)
 #define UA_NODEID_GUID(NSID, GUID) UA_NodeId_fromGuid(NSID, GUID)
 #define UA_NODEID_BYTESTRING(NSID, CHARS) UA_NodeId_fromCharByteString(NSID, CHARS)
 #define UA_NODEID_BYTESTRING_ALLOC(NSID, CHARS) UA_NodeId_fromCharByteStringCopy(NSID, CHARS)
-#define UA_NODEID_NULL UA_NODEID_NUMERIC(0,0)
+#define UA_NODEID_NULL (UA_NodeId){0, UA_NODEIDTYPE_NUMERIC, {0}}
 
 /* ExpandedNodeId */
+UA_ExpandedNodeId UA_EXPORT * UA_ExpandedNodeId_new(void);
+void UA_EXPORT UA_ExpandedNodeId_init(UA_ExpandedNodeId *p);
+void UA_EXPORT UA_ExpandedNodeId_delete(UA_ExpandedNodeId *p);
+void UA_EXPORT UA_ExpandedNodeId_deleteMembers(UA_ExpandedNodeId *p);
+UA_StatusCode UA_EXPORT UA_ExpandedNodeId_copy(const UA_ExpandedNodeId *src, UA_ExpandedNodeId *dst);
 UA_Boolean UA_EXPORT UA_ExpandedNodeId_isNull(const UA_ExpandedNodeId *p);
-
 #define UA_EXPANDEDNODEID_NUMERIC(NSID, NUMERICID) (UA_ExpandedNodeId) {            \
         .nodeId = {.namespaceIndex = NSID, .identifierType = UA_NODEIDTYPE_NUMERIC, \
-                   .identifier.numeric = NUMERICID },                                   \
+                   .identifier.numeric = NUMERICID },                               \
         .serverIndex = 0, .namespaceUri = {.data = (UA_Byte*)0, .length = -1} }
-    
+
+/* StatusCode */
+UA_StatusCode UA_EXPORT * UA_StatusCode_new(void);
+static UA_INLINE void UA_StatusCode_init(UA_StatusCode *p) { *p = UA_STATUSCODE_GOOD; }
+void UA_EXPORT UA_StatusCode_delete(UA_StatusCode *p);
+static UA_INLINE void UA_StatusCode_deleteMembers(UA_StatusCode *p) { }
+static UA_INLINE UA_StatusCode UA_StatusCode_copy(const UA_StatusCode *src, UA_StatusCode *dst) { *dst = *src; return UA_STATUSCODE_GOOD; }
+
 /* QualifiedName */
-#define UA_QUALIFIEDNAME(NSID, CHARS) (const UA_QualifiedName) {    \
-        .namespaceIndex = NSID, .name = UA_STRING(CHARS) }
-#define UA_QUALIFIEDNAME_ALLOC(NSID, CHARS) (UA_QualifiedName) {    \
-        .namespaceIndex = NSID, .name = UA_STRING_ALLOC(CHARS) }
+UA_QualifiedName UA_EXPORT * UA_QualifiedName_new(void);
+void UA_EXPORT UA_QualifiedName_init(UA_QualifiedName *p);
+void UA_EXPORT UA_QualifiedName_delete(UA_QualifiedName *p);
+void UA_EXPORT UA_QualifiedName_deleteMembers(UA_QualifiedName *p);
+UA_StatusCode UA_EXPORT UA_QualifiedName_copy(const UA_QualifiedName *src, UA_QualifiedName *dst);
+#define UA_QUALIFIEDNAME(NSID, CHARS) (const UA_QualifiedName) { .namespaceIndex = NSID, .name = UA_STRING(CHARS) }
+#define UA_QUALIFIEDNAME_ALLOC(NSID, CHARS) (UA_QualifiedName) { .namespaceIndex = NSID, .name = UA_STRING_ALLOC(CHARS) }
 
 /* LocalizedText */
-#define UA_LOCALIZEDTEXT(LOCALE, TEXT) (const UA_LocalizedText) {       \
-        .locale = UA_STRING(LOCALE), .text = UA_STRING(TEXT) }
-#define UA_LOCALIZEDTEXT_ALLOC(LOCALE, TEXT) (UA_LocalizedText) {       \
-        .locale = UA_STRING_ALLOC(LOCALE), .text = UA_STRING_ALLOC(TEXT) }
+UA_LocalizedText UA_EXPORT * UA_LocalizedText_new(void);
+void UA_EXPORT UA_LocalizedText_init(UA_LocalizedText *p);
+void UA_EXPORT UA_LocalizedText_delete(UA_LocalizedText *p);
+void UA_EXPORT UA_LocalizedText_deleteMembers(UA_LocalizedText *p);
+UA_StatusCode UA_EXPORT UA_LocalizedText_copy(const UA_LocalizedText *src, UA_LocalizedText *dst);
+#define UA_LOCALIZEDTEXT(LOCALE, TEXT) (const UA_LocalizedText) { .locale = UA_STRING(LOCALE), .text = UA_STRING(TEXT) }
+#define UA_LOCALIZEDTEXT_ALLOC(LOCALE, TEXT) (UA_LocalizedText) { .locale = UA_STRING_ALLOC(LOCALE), .text = UA_STRING_ALLOC(TEXT) }
+
+/* ExtensionObject */
+UA_ExtensionObject UA_EXPORT * UA_ExtensionObject_new(void);
+void UA_EXPORT UA_ExtensionObject_init(UA_ExtensionObject *p);
+void UA_EXPORT UA_ExtensionObject_delete(UA_ExtensionObject *p);
+void UA_EXPORT UA_ExtensionObject_deleteMembers(UA_ExtensionObject *p);
+UA_StatusCode UA_EXPORT UA_ExtensionObject_copy(const UA_ExtensionObject *src, UA_ExtensionObject *dst);
 
 /* Variant */
+UA_Variant UA_EXPORT * UA_Variant_new(void);
+void UA_EXPORT UA_Variant_init(UA_Variant *p);
+void UA_EXPORT UA_Variant_delete(UA_Variant *p);
+void UA_EXPORT UA_Variant_deleteMembers(UA_Variant *p);
+UA_StatusCode UA_EXPORT UA_Variant_copy(const UA_Variant *src, UA_Variant *dst);
 
 /**
  * Returns true if the variant contains a scalar value. Note that empty variants contain an array of
@@ -412,8 +491,7 @@ UA_StatusCode UA_EXPORT UA_Variant_setScalarCopy(UA_Variant *v, const void *p, c
  * @param type The datatype of the array
  * @return Indicates whether the operation succeeded or returns an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 elements,
-                                            const UA_DataType *type);
+UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32 elements, const UA_DataType *type);
 
 /**
  * Set the variant to an array that is copied from an existing array.
@@ -424,21 +502,7 @@ UA_StatusCode UA_EXPORT UA_Variant_setArray(UA_Variant *v, void *array, UA_Int32
  * @param type The datatype of the array
  * @return Indicates whether the operation succeeded or returns an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32 elements,
-                                                const UA_DataType *type);
-
-/** @brief NumericRanges are used select a subset in a (multidimensional)
-    variant array. NumericRange has no official type structure in the standard.
-    On the wire, it only exists as an encoded string, such as "1:2,0:3,5". The
-    colon separates min/max index and the comma separates dimensions. A single
-    value indicates a range with a single element (min==max). */
-typedef struct {
-    UA_Int32 dimensionsSize;
-    struct UA_NumericRangeDimension {
-        UA_UInt32 min;
-        UA_UInt32 max;
-    } *dimensions;
-} UA_NumericRange;
+UA_StatusCode UA_EXPORT UA_Variant_setArrayCopy(UA_Variant *v, const void *array, UA_Int32 elements, const UA_DataType *type);
 
 /**
  * Copy the variant, but use only a subset of the (multidimensional) array into a variant. Returns
@@ -449,7 +513,7 @@ typedef struct {
  * @param range The range of the copied data
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, UA_NumericRange range);
+UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range);
 
 /**
  * Insert a range of data into an existing variant. The data array can't be reused afterwards if it
@@ -462,8 +526,7 @@ UA_StatusCode UA_EXPORT UA_Variant_copyRange(const UA_Variant *src, UA_Variant *
  * @param range The range of where the new data is inserted
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_Int32 dataArraySize,
-                                            const UA_NumericRange range);
+UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_Int32 dataArraySize, const UA_NumericRange range);
 
 /**
  * Deep-copy a range of data into an existing variant.
@@ -474,8 +537,21 @@ UA_StatusCode UA_EXPORT UA_Variant_setRange(UA_Variant *v, void *dataArray, UA_I
  * @param range The range of where the new data is inserted
  * @return Returns UA_STATUSCODE_GOOD or an error code
  */
-UA_StatusCode UA_EXPORT UA_Variant_setRangeCopy(UA_Variant *v, const void *dataArray, UA_Int32 dataArraySize,
-                                                const UA_NumericRange range);
+UA_StatusCode UA_EXPORT UA_Variant_setRangeCopy(UA_Variant *v, const void *dataArray, UA_Int32 dataArraySize, const UA_NumericRange range);
+
+/* DataValue */
+UA_DataValue UA_EXPORT * UA_DataValue_new(void);
+void UA_EXPORT UA_DataValue_init(UA_DataValue *p);
+void UA_EXPORT UA_DataValue_delete(UA_DataValue *p);
+void UA_EXPORT UA_DataValue_deleteMembers(UA_DataValue *p);
+UA_StatusCode UA_EXPORT UA_DataValue_copy(const UA_DataValue *src, UA_DataValue *dst);
+
+/* DiagnosticInfo */
+UA_DiagnosticInfo UA_EXPORT * UA_DiagnosticInfo_new(void);
+void UA_EXPORT UA_DiagnosticInfo_init(UA_DiagnosticInfo *p);
+void UA_EXPORT UA_DiagnosticInfo_delete(UA_DiagnosticInfo *p);
+void UA_EXPORT UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p);
+UA_StatusCode UA_EXPORT UA_DiagnosticInfo_copy(const UA_DiagnosticInfo *src, UA_DiagnosticInfo *dst);
 
 /****************************/
 /* Structured Type Handling */
@@ -483,35 +559,27 @@ UA_StatusCode UA_EXPORT UA_Variant_setRangeCopy(UA_Variant *v, const void *dataA
 
 #define UA_MAX_TYPE_MEMBERS 13 // Maximum number of members per complex type
 
-#ifndef _WIN32
-# define UA_BITFIELD(SIZE) : SIZE
-#else
-# define UA_BITFIELD(SIZE)
-#endif
-
 #define UA_IS_BUILTIN(ID) (ID <= UA_TYPES_DIAGNOSTICINFO)
 
 typedef struct {
-    UA_UInt16 memberTypeIndex UA_BITFIELD(9); ///< Index of the member in the datatypetable
-    UA_Boolean namespaceZero UA_BITFIELD(1); /**< The type of the member is defined in namespace
-                                                  zero. In this implementation, types from custom
-                                                  namespace may contain members from the same
-                                                  namespace or ns0 only.*/
-    UA_Byte padding UA_BITFIELD(5); /**< How much padding is there before this member element? For
-                                         arrays this is split into 2 bytes padding before the
-                                         length index (max 4 bytes) and 3 bytes padding before the
-                                         pointer (max 8 bytes) */
-    UA_Boolean isArray UA_BITFIELD(1); ///< The member is an array of the given type
+    UA_UInt16 memberTypeIndex; ///< Index of the member in the datatypetable
+    UA_Byte padding; /**< How much padding is there before this member element? For arrays this is
+                          split into 2 bytes padding before the length index (max 4 bytes) and 3
+                          bytes padding before the pointer (max 8 bytes) */
+    UA_Boolean namespaceZero : 1; /**< The type of the member is defined in namespace zero. In this
+                                       implementation, types from custom namespace may contain
+                                       members from the same namespace or ns0 only.*/
+    UA_Boolean isArray : 1; ///< The member is an array of the given type
 } UA_DataTypeMember;
     
 struct UA_DataType {
     UA_NodeId typeId; ///< The nodeid of the type
-    ptrdiff_t memSize UA_BITFIELD(16); ///< Size of the struct in memory
-    UA_UInt16 typeIndex UA_BITFIELD(13); ///< Index of the type in the datatypetable
-    UA_Boolean namespaceZero UA_BITFIELD(1); ///< The type is defined in namespace zero
-    UA_Boolean fixedSize UA_BITFIELD(1); ///< The type (and its members) contains no pointers
-    UA_Boolean zeroCopyable UA_BITFIELD(1); ///< Can the type be copied directly off the stream?
+    UA_UInt16 memSize; ///< Size of the struct in memory
+    UA_UInt16 typeIndex; ///< Index of the type in the datatypetable
     UA_Byte membersSize; ///< How many members does the type have?
+    UA_Boolean namespaceZero : 1; ///< The type is defined in namespace zero
+    UA_Boolean fixedSize : 1; ///< The type (and its members contains no pointers
+    UA_Boolean zeroCopyable : 1; ///< Can the type be copied directly off the stream?
     UA_DataTypeMember members[UA_MAX_TYPE_MEMBERS];
 };
 
@@ -623,6 +691,17 @@ typedef enum {
     UA_ATTRIBUTEID_USEREXECUTABLE          = 22
 } UA_AttributeId;
 
+/***************************/
+/* Random Number Generator */
+/***************************/
+
+/**
+ * If UA_MULTITHREADING is enabled, then the seed is stored in thread local storage. The seed is
+ * initialized for every thread in the server/client.
+ */
+UA_EXPORT void UA_random_seed(UA_UInt64 seed);
+UA_EXPORT UA_UInt32 UA_random(void);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 7 - 0
src/server/ua_nodes.h

@@ -5,6 +5,13 @@
 #include "ua_types_generated.h"
 #include "ua_types_encoding_binary.h"
 
+#define UA_TYPE_HANDLING_FUNCTIONS(TYPE)                             \
+    TYPE UA_EXPORT * TYPE##_new(void);                               \
+    void UA_EXPORT TYPE##_init(TYPE * p);                            \
+    void UA_EXPORT TYPE##_delete(TYPE * p);                          \
+    void UA_EXPORT TYPE##_deleteMembers(TYPE * p);                   \
+    UA_StatusCode UA_EXPORT TYPE##_copy(const TYPE *src, TYPE *dst);
+
 #define UA_STANDARD_NODEMEMBERS                 \
     UA_NodeId nodeId;                           \
     UA_NodeClass nodeClass;                     \

+ 3 - 3
src/server/ua_server.c

@@ -205,7 +205,7 @@ static void getBulidInfo(const UA_Server* server, UA_BuildInfo *buildInfo) {
     buildInfo->buildDate = server->buildDate;
 }
 
-static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
+static UA_StatusCode readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp, const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = UA_TRUE;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
@@ -232,7 +232,7 @@ static UA_StatusCode readStatus(void *handle, UA_Boolean sourceTimeStamp, const
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode readNamespaces(void *handle, UA_Boolean sourceTimestamp, const UA_NumericRange *range, UA_DataValue *value) {
+static UA_StatusCode readNamespaces(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimestamp, const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = UA_TRUE;
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
@@ -250,7 +250,7 @@ static UA_StatusCode readNamespaces(void *handle, UA_Boolean sourceTimestamp, co
     return UA_STATUSCODE_GOOD;
 }
 
-static UA_StatusCode readCurrentTime(void *handle, UA_Boolean sourceTimeStamp,
+static UA_StatusCode readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
                                      const UA_NumericRange *range, UA_DataValue *value) {
     if(range) {
         value->hasStatus = UA_TRUE;

+ 13 - 4
src/server/ua_server_worker.c

@@ -42,8 +42,13 @@
 #define MAXTIMEOUT 50000 // max timeout in microsec until the next main loop iteration
 #define BATCHSIZE 20 // max number of jobs that are dispatched at once to workers
 
-static void processJobs(UA_Server *server, UA_Job *jobs, size_t jobsSize) {
-    for(size_t i = 0; i < jobsSize; i++) {
+/**
+ * server:		UA server context
+ * jobs: 		pointer to array of jobs or NULL if jobsSize == -1
+ * jobsSize: 	nr. of valid jobs or -1
+*/
+static void processJobs(UA_Server *server, UA_Job *jobs, UA_Int32 jobsSize) {
+    for (UA_Int32 i = 0; i < jobsSize; i++) {
         UA_Job *job = &jobs[i];
         switch(job->type) {
         case UA_JOBTYPE_BINARYMESSAGE:
@@ -115,6 +120,9 @@ struct workerStartData {
 
 /** Waits until jobs arrive in the dispatch queue and processes them. */
 static void * workerLoop(struct workerStartData *startInfo) {
+    /* Initialized the (thread local) random seed */
+    UA_random_seed((uintptr_t)startInfo);
+
    	rcu_register_thread();
     UA_UInt32 *c = UA_malloc(sizeof(UA_UInt32));
     uatomic_set(c, 0);
@@ -346,10 +354,11 @@ static UA_UInt16 processRepeatedJobs(UA_Server *server) {
     }
 
     // check if the next repeated job is sooner than the usual timeout
+    // calc in 32 bit must be ok
     struct RepeatedJobs *first = LIST_FIRST(&server->repeatedJobs);
-    UA_UInt16 timeout = MAXTIMEOUT;
+    UA_UInt32 timeout = MAXTIMEOUT;
     if(first) {
-        timeout = (first->nextTime - current)/10;
+        timeout = (UA_UInt32)((first->nextTime - current) / 10);
         if(timeout > MAXTIMEOUT)
             return MAXTIMEOUT;
     }

+ 5 - 5
src/server/ua_services_attribute.c

@@ -219,7 +219,7 @@ void Service_Read_single(UA_Server *server, UA_Session *session, UA_TimestampsTo
                 }
             } else {
                 UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE || timestamps == UA_TIMESTAMPSTORETURN_BOTH);
-                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, sourceTimeStamp, rangeptr, v);
+                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, sourceTimeStamp, rangeptr, v);
             }
 
             if(rangeptr)
@@ -235,7 +235,7 @@ void Service_Read_single(UA_Server *server, UA_Session *session, UA_TimestampsTo
         else {
             UA_DataValue val;
             UA_DataValue_init(&val);
-            retval = vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, UA_NULL, &val);
+            retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId, UA_FALSE, UA_NULL, &val);
             if(retval != UA_STATUSCODE_GOOD)
                 break;
             retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId, &UA_TYPES[UA_TYPES_NODEID]);
@@ -265,7 +265,7 @@ void Service_Read_single(UA_Server *server, UA_Session *session, UA_TimestampsTo
             } else {
                 UA_DataValue val;
                 UA_DataValue_init(&val);
-                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, UA_FALSE, UA_NULL, &val);
+                retval |= vn->value.dataSource.read(vn->value.dataSource.handle, node->nodeId, UA_FALSE, UA_NULL, &val);
                 if(retval != UA_STATUSCODE_GOOD)
                     break;
                 retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions, val.value.arrayDimensionsSize,
@@ -529,9 +529,9 @@ UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session, const
 				goto clean_up_range;
 			}
 			if(hasRange)
-				retval = vn->value.dataSource.write(vn->value.dataSource.handle, &wvalue->value.value, &range);
+				retval = vn->value.dataSource.write(vn->value.dataSource.handle, vn->nodeId, &wvalue->value.value, &range);
 			else
-				retval = vn->value.dataSource.write(vn->value.dataSource.handle, &wvalue->value.value, UA_NULL);
+				retval = vn->value.dataSource.write(vn->value.dataSource.handle, vn->nodeId, &wvalue->value.value, UA_NULL);
 			goto clean_up_range;
 		}
 

+ 1 - 1
src/server/ua_services_view.c

@@ -507,7 +507,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_Node *node, cons
         return UA_STATUSCODE_BADBROWSENAMEINVALID;
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_NodeId *reftypes;
+    UA_NodeId *reftypes = UA_NULL;
     size_t reftypes_count = 1; // all_refs or no subtypes => 1
     UA_Boolean all_refs = UA_FALSE;
     if(UA_NodeId_isNull(&elem->referenceTypeId))

+ 1 - 1
src/server/ua_session_manager.c

@@ -61,7 +61,7 @@ UA_StatusCode UA_SessionManager_createSession(UA_SessionManager *sessionManager,
     sessionManager->currentSessionCount++;
     UA_Session_init(&newentry->session);
     newentry->session.sessionId = UA_NODEID_NUMERIC(1, sessionManager->lastSessionId++);
-    UA_UInt32 randSeed = sessionManager->lastSessionId + UA_DateTime_now();
+    UA_UInt32 randSeed = (UA_UInt32)(sessionManager->lastSessionId + UA_DateTime_now());
     newentry->session.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random(&randSeed));
     if(request->requestedSessionTimeout <= sessionManager->maxSessionLifeTime &&
        request->requestedSessionTimeout > 0)

+ 1 - 1
src/server/ua_session_manager.h

@@ -16,7 +16,7 @@ typedef struct UA_SessionManager {
     UA_UInt32    maxSessionCount;
     UA_Int32     lastSessionId;
     UA_UInt32    currentSessionCount;
-    UA_DateTime  maxSessionLifeTime;
+    UA_DateTime  maxSessionLifeTime;    // time in [ms]
 } UA_SessionManager;
 
 UA_StatusCode UA_SessionManager_init(UA_SessionManager *sessionManager, UA_UInt32 maxSessionCount,

+ 1 - 6
src/server/ua_subscription.c

@@ -294,13 +294,8 @@ UA_StatusCode Subscription_registerUpdateJob(UA_Server *server, UA_Subscription
         return UA_STATUSCODE_BADNOTSUPPORTED;
     
     // Practically enough, the client sends a uint32 in ms, which we store as datetime, which here is required in as uint32 in ms as the interval
-#ifdef _MSC_VER
-    UA_Int32 retval = UA_Server_addRepeatedJob(server, *(sub->timedUpdateJob), sub->publishingInterval,
-                                               &sub->timedUpdateJobGuid);
-#else
     UA_StatusCode retval = UA_Server_addRepeatedJob(server, *sub->timedUpdateJob, sub->publishingInterval,
                                                     &sub->timedUpdateJobGuid);
-#endif
     if(!retval)
         sub->timedUpdateIsRegistered = UA_TRUE;
     return retval;
@@ -437,7 +432,7 @@ UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, cons
                 if(srcAsVariableNode->valueSource != UA_VALUESOURCE_DATASOURCE)
                     break;
                 // todo: handle numeric ranges
-                if(srcAsVariableNode->value.dataSource.read(vsrc->value.dataSource.handle, UA_TRUE, UA_NULL,
+                if(srcAsVariableNode->value.dataSource.read(vsrc->value.dataSource.handle, vsrc->nodeId, UA_TRUE, UA_NULL,
                                                             &sourceDataValue) != UA_STATUSCODE_GOOD)
                     break;
                 UA_Variant_copy(&sourceDataValue.value, dst);

+ 1 - 1
src/ua_session.h

@@ -34,7 +34,7 @@ struct UA_Session {
     UA_NodeId         sessionId;
     UA_UInt32         maxRequestMessageSize;
     UA_UInt32         maxResponseMessageSize;
-    UA_Int64          timeout;
+    UA_Int64          timeout; // [ms]
     UA_DateTime       validTill;
     #ifdef ENABLE_SUBSCRIPTIONS
         UA_SubscriptionManager subscriptionManager;

+ 35 - 67
src/ua_types.c

@@ -3,16 +3,15 @@
 #include "ua_statuscodes.h"
 #include "ua_types_generated.h"
 
+#include "pcg_basic.h"
+
 /*****************/
 /* Helper Macros */
 /*****************/
 
 #define UA_TYPE_DEFAULT(TYPE)            \
     UA_TYPE_NEW_DEFAULT(TYPE)            \
-    UA_TYPE_INIT_DEFAULT(TYPE)           \
-    UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
-    UA_TYPE_DELETE_DEFAULT(TYPE)         \
-    UA_TYPE_COPY_DEFAULT(TYPE)           \
+    UA_TYPE_DELETE_DEFAULT(TYPE)
 
 #define UA_TYPE_NEW_DEFAULT(TYPE)                              \
     TYPE * TYPE##_new() {                                      \
@@ -21,11 +20,6 @@
         return p;                                              \
     }
 
-#define UA_TYPE_INIT_DEFAULT(TYPE) \
-    void TYPE##_init(TYPE * p) {   \
-        *p = (TYPE)0;              \
-    }
-
 #define UA_TYPE_DELETEMEMBERS_NOACTION(TYPE) \
     void TYPE##_deleteMembers(TYPE *p) {    \
     }
@@ -36,11 +30,19 @@
         UA_free(p);                  \
     }
 
-#define UA_TYPE_COPY_DEFAULT(TYPE)                             \
-    UA_StatusCode TYPE##_copy(TYPE const *src, TYPE *dst) {    \
-        *dst = *src;                                           \
-        return UA_STATUSCODE_GOOD;                             \
-    }
+/***************************/
+/* Random Number Generator */
+/***************************/
+
+static UA_THREAD_LOCAL pcg32_random_t rng = PCG32_INITIALIZER;
+
+UA_EXPORT void UA_random_seed(UA_UInt64 seed) {
+    pcg32_srandom_r(&rng, seed, UA_DateTime_now());
+}
+
+UA_EXPORT UA_UInt32 UA_random(void) {
+    return (UA_UInt32)pcg32_random_r(&rng);
+}
 
 /*****************/
 /* Builtin Types */
@@ -160,6 +162,7 @@ UA_Boolean UA_String_equal(const UA_String *string1, const UA_String *string2) {
 }
 
 /* DateTime */
+UA_TYPE_DEFAULT(UA_DateTime)
 #define UNIX_EPOCH_BIAS_SEC 11644473600LL // Number of seconds from 1 Jan. 1601 00:00 to 1 Jan 1970 00:00 UTC
 #define HUNDRED_NANOSEC_PER_USEC 10LL
 #define HUNDRED_NANOSEC_PER_SEC (HUNDRED_NANOSEC_PER_USEC * 1000000LL)
@@ -184,7 +187,7 @@ int gettimeofday(struct timeval *tp, struct timezone *tzp) {
     SystemTimeToFileTime(&st, &ft);
     ul.LowPart  = ft.dwLowDateTime;
     ul.HighPart = ft.dwHighDateTime;
-    tp->tv_sec  = (ul.QuadPart - epoch) / 10000000L;
+    tp->tv_sec  = (long)((ul.QuadPart - epoch) / 10000000L);
     tp->tv_usec = st.wMilliseconds * 1000;
     return 0;
 }
@@ -231,10 +234,7 @@ UA_StatusCode UA_DateTime_toString(UA_DateTime atime, UA_String *timeString) {
 }
 
 /* Guid */
-UA_TYPE_NEW_DEFAULT(UA_Guid)
-UA_TYPE_DELETEMEMBERS_NOACTION(UA_Guid)
-UA_TYPE_DELETE_DEFAULT(UA_Guid)
-
+UA_TYPE_DEFAULT(UA_Guid)
 UA_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) {
     if(memcmp(g1, g2, sizeof(UA_Guid)) == 0)
         return UA_TRUE;
@@ -243,16 +243,16 @@ UA_Boolean UA_Guid_equal(const UA_Guid *g1, const UA_Guid *g2) {
 
 UA_Guid UA_Guid_random(UA_UInt32 *seed) {
     UA_Guid result;
-    result.data1 = RAND(seed);
-    UA_UInt32 r = RAND(seed);
+    result.data1 = (UA_UInt32)pcg32_random_r(&rng);
+    UA_UInt32 r = (UA_UInt32)pcg32_random_r(&rng);
     result.data2 = (UA_UInt16) r;
     result.data3 = (UA_UInt16) (r >> 16);
-    r = RAND(seed);
+    r = (UA_UInt32)pcg32_random_r(&rng);
     result.data4[0] = (UA_Byte)r;
     result.data4[1] = (UA_Byte)(r >> 4);
     result.data4[2] = (UA_Byte)(r >> 8);
     result.data4[3] = (UA_Byte)(r >> 12);
-    r = RAND(seed);
+    r = (UA_UInt32)pcg32_random_r(&rng);
     result.data4[4] = (UA_Byte)r;
     result.data4[5] = (UA_Byte)(r >> 4);
     result.data4[6] = (UA_Byte)(r >> 8);
@@ -260,18 +260,6 @@ UA_Guid UA_Guid_random(UA_UInt32 *seed) {
     return result;
 }
 
-void UA_Guid_init(UA_Guid *p) {
-    p->data1 = 0;
-    p->data2 = 0;
-    p->data3 = 0;
-    memset(p->data4, 0, sizeof(UA_Byte)*8);
-}
-
-UA_StatusCode UA_Guid_copy(UA_Guid const *src, UA_Guid *dst) {
-    UA_memcpy((void *)dst, (const void *)src, sizeof(UA_Guid));
-    return UA_STATUSCODE_GOOD;
-}
-
 /* ByteString */
 UA_StatusCode UA_ByteString_newMembers(UA_ByteString *p, UA_Int32 length) {
     if(length > 0) {
@@ -561,24 +549,14 @@ void UA_DataValue_deleteMembers(UA_DataValue *p) {
 }
 
 void UA_DataValue_init(UA_DataValue *p) {
-    *((UA_Byte*)p) = 0; // zero out the bitfield
-    p->serverPicoseconds = 0;
-    UA_DateTime_init(&p->serverTimestamp);
-    p->sourcePicoseconds = 0;
-    UA_DateTime_init(&p->sourceTimestamp);
-    UA_StatusCode_init(&p->status);
+    UA_memset(p, 0, sizeof(UA_DataValue));
     UA_Variant_init(&p->value);
 }
 
 UA_StatusCode UA_DataValue_copy(UA_DataValue const *src, UA_DataValue *dst) {
-    UA_DataValue_init(dst);
-    *((UA_Byte*)dst) = *((const UA_Byte*)src); // the bitfield
-    UA_StatusCode retval = UA_DateTime_copy(&src->serverTimestamp, &dst->serverTimestamp);
-    retval |= UA_DateTime_copy(&src->sourceTimestamp, &dst->sourceTimestamp);
-    retval |= UA_Variant_copy(&src->value, &dst->value);
-    dst->serverPicoseconds = src->serverPicoseconds;
-    dst->sourcePicoseconds = src->sourcePicoseconds;
-    dst->status = src->status;
+    UA_memcpy(dst, src, sizeof(UA_DataValue));
+    UA_Variant_init(&dst->value);
+    UA_StatusCode retval = UA_Variant_copy(&src->value, &dst->value);
     if(retval) {
         UA_DataValue_deleteMembers(dst);
         UA_DataValue_init(dst);
@@ -745,7 +723,7 @@ UA_StatusCode UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const
         }
     }
 
-    /* Copy the range dimensions*/
+    /* Copy the range dimensions */
     if(src->arrayDimensionsSize > 0) {
         dst->arrayDimensions = UA_malloc(sizeof(UA_Int32) * src->arrayDimensionsSize);
         if(!dst->arrayDimensions) {
@@ -868,24 +846,14 @@ void UA_DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p) {
 }
 
 void UA_DiagnosticInfo_init(UA_DiagnosticInfo *p) {
-	*((UA_Byte*)p) = 0; // zero out the bitfield
-    p->symbolicId          = 0;
-    p->namespaceUri        = 0;
-    p->localizedText       = 0;
-    p->locale              = 0;
+    UA_memset(p, 0, sizeof(UA_DiagnosticInfo));
     UA_String_init(&p->additionalInfo);
-    p->innerDiagnosticInfo = UA_NULL;
-    UA_StatusCode_init(&p->innerStatusCode);
 }
 
 UA_StatusCode UA_DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst) {
-    UA_DiagnosticInfo_init(dst);
-    *((UA_Byte*)dst) = *((const UA_Byte*)src); // the bitfield
-    dst->symbolicId = src->symbolicId;
-    dst->namespaceUri = src->namespaceUri;
-    dst->localizedText = src->localizedText;
-    dst->locale = src->locale;
-    dst->innerStatusCode = src->innerStatusCode;
+    UA_memcpy(dst, src, sizeof(UA_DiagnosticInfo));
+    UA_String_init(&dst->additionalInfo);
+    dst->innerDiagnosticInfo = UA_NULL;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     if(src->hasAdditionalInfo)
        retval = UA_String_copy(&src->additionalInfo, &dst->additionalInfo);
@@ -893,11 +861,11 @@ UA_StatusCode UA_DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_Diagnostic
         if((dst->innerDiagnosticInfo = UA_malloc(sizeof(UA_DiagnosticInfo)))) {
             retval |= UA_DiagnosticInfo_copy(src->innerDiagnosticInfo, dst->innerDiagnosticInfo);
             dst->hasInnerDiagnosticInfo = src->hasInnerDiagnosticInfo;
-        }
-        else
+        } else {
             retval |= UA_STATUSCODE_BADOUTOFMEMORY;
+        }
     }
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_DiagnosticInfo_deleteMembers(dst);
         UA_DiagnosticInfo_init(dst);
     }

+ 30 - 29
src/ua_types_encoding_binary.c

@@ -36,14 +36,15 @@ static UA_StatusCode UA_Array_encodeBinary(const void *src, UA_Int32 noElements,
 }
 
 static UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset,
-                                           UA_Int32 noElements, void **dst, const UA_DataType *dataType) {
-    if(noElements <= 0) {
+                                           UA_Int32 noElements_signed, void **dst, const UA_DataType *dataType) {
+    if(noElements_signed <= 0) {
         *dst = UA_NULL;
         return UA_STATUSCODE_GOOD;
     }
 
-    if((UA_Int32) dataType->memSize * noElements
-            < 0|| dataType->memSize * noElements > MAX_ARRAY_SIZE)
+    size_t noElements = (size_t)noElements_signed; //is guaranteed positive
+
+    if(dataType->memSize * noElements > MAX_ARRAY_SIZE)
         return UA_STATUSCODE_BADOUTOFMEMORY;
 
     /* filter out arrays that can obviously not be parsed, because the message is too small */
@@ -67,7 +68,7 @@ static UA_StatusCode UA_Array_decodeBinary(const UA_ByteString *src, size_t *UA_
 #endif
 
     uintptr_t ptr = (uintptr_t) *dst;
-    UA_Int32 i;
+    size_t i = 0;
     for(i = 0; i < noElements && retval == UA_STATUSCODE_GOOD; i++) {
         retval = UA_decodeBinary(src, offset, (void*) ptr, dataType);
         ptr += dataType->memSize;
@@ -143,7 +144,7 @@ UA_StatusCode UA_UInt16_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRI
 
 #ifdef UA_ALIGNED_MEMORY_ACCESS
     *dst = (UA_UInt16) src->data[(*offset)++] << 0;
-    *dst += (UA_UInt16) src->data[(*offset)++] << 8;
+    *dst |= (UA_UInt16) src->data[(*offset)++] << 8;
 #else
     *dst = *((UA_UInt16*) &src->data[*offset]);
     *offset += 2;
@@ -183,9 +184,9 @@ UA_StatusCode UA_UInt32_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRI
 
 #ifdef UA_ALIGNED_MEMORY_ACCESS
     *dst = (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF));
-    *dst += (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 8);
-    *dst += (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 16);
-    *dst += (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 24);
+    *dst |= (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 8);
+    *dst |= (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 16);
+    *dst |= (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 24);
 #else
     *dst = *((UA_UInt32*) &src->data[*offset]);
     *offset += 4;
@@ -229,13 +230,13 @@ UA_StatusCode UA_UInt64_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRI
 
 #ifdef UA_ALIGNED_MEMORY_ACCESS
     *dst = (UA_UInt64) src->data[(*offset)++];
-    *dst += (UA_UInt64) src->data[(*offset)++] << 8;
-    *dst += (UA_UInt64) src->data[(*offset)++] << 16;
-    *dst += (UA_UInt64) src->data[(*offset)++] << 24;
-    *dst += (UA_UInt64) src->data[(*offset)++] << 32;
-    *dst += (UA_UInt64) src->data[(*offset)++] << 40;
-    *dst += (UA_UInt64) src->data[(*offset)++] << 48;
-    *dst += (UA_UInt64) src->data[(*offset)++] << 56;
+    *dst |= (UA_UInt64) src->data[(*offset)++] << 8;
+    *dst |= (UA_UInt64) src->data[(*offset)++] << 16;
+    *dst |= (UA_UInt64) src->data[(*offset)++] << 24;
+    *dst |= (UA_UInt64) src->data[(*offset)++] << 32;
+    *dst |= (UA_UInt64) src->data[(*offset)++] << 40;
+    *dst |= (UA_UInt64) src->data[(*offset)++] << 48;
+    *dst |= (UA_UInt64) src->data[(*offset)++] << 56;
 #else
     *dst = *((UA_UInt64*) &src->data[*offset]);
     *offset += 8;
@@ -432,7 +433,7 @@ UA_StatusCode UA_NodeId_encodeBinary(UA_NodeId const *src, UA_ByteString * dst,
             /* UA_NODEIDTYPE_FOURBYTE */
             srcByte = UA_NODEIDTYPE_FOURBYTE;
             retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
-            srcByte = src->namespaceIndex;
+            srcByte = (UA_Byte)src->namespaceIndex;
             srcUInt16 = src->identifier.numeric;
             retval |= UA_Byte_encodeBinary(&srcByte, dst, offset);
             retval |= UA_UInt16_encodeBinary(&srcUInt16, dst, offset);
@@ -792,7 +793,7 @@ UA_StatusCode UA_Variant_encodeBinary(UA_Variant const *src, UA_ByteString *dst,
 
 /* The resulting variant always has the storagetype UA_VARIANT_DATA. Currently,
  we only support ns0 types (todo: attach typedescriptions to datatypenodes) */
-UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Variant *dst) {
+UA_StatusCode UA_Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset, UA_Variant *dst) {
     UA_Variant_init(dst);
     UA_Byte encodingByte;
     UA_StatusCode retval = UA_Byte_decodeBinary(src, offset, &encodingByte);
@@ -909,7 +910,7 @@ UA_StatusCode UA_DiagnosticInfo_decodeBinary(UA_ByteString const *src, size_t *U
         dst->innerDiagnosticInfo = UA_malloc(sizeof(UA_DiagnosticInfo));
         if(dst->innerDiagnosticInfo) {
             if(UA_DiagnosticInfo_decodeBinary(src, offset,
-                    dst->innerDiagnosticInfo) != UA_STATUSCODE_GOOD) {
+                                              dst->innerDiagnosticInfo) != UA_STATUSCODE_GOOD) {
                 UA_free(dst->innerDiagnosticInfo);
                 dst->innerDiagnosticInfo = UA_NULL;
                 retval |= UA_STATUSCODE_BADINTERNALERROR;
@@ -1250,22 +1251,22 @@ static size_t UA_DataValue_calcSizeBinary(UA_DataValue const *p) {
     return length;
 }
 
-static size_t UA_DiagnosticInfo_calcSizeBinary(UA_DiagnosticInfo const *ptr) {
+static size_t UA_DiagnosticInfo_calcSizeBinary(UA_DiagnosticInfo const *p) {
     size_t length = sizeof(UA_Byte);
-    if(ptr->hasSymbolicId)
+    if(p->hasSymbolicId)
         length += sizeof(UA_Int32);
-    if(ptr->hasNamespaceUri)
+    if(p->hasNamespaceUri)
         length += sizeof(UA_Int32);
-    if(ptr->hasLocalizedText)
+    if(p->hasLocalizedText)
         length += sizeof(UA_Int32);
-    if(ptr->hasLocale)
+    if(p->hasLocale)
         length += sizeof(UA_Int32);
-    if(ptr->hasAdditionalInfo)
-        length += UA_String_calcSizeBinary(&ptr->additionalInfo);
-    if(ptr->hasInnerStatusCode)
+    if(p->hasAdditionalInfo)
+        length += UA_String_calcSizeBinary(&p->additionalInfo);
+    if(p->hasInnerStatusCode)
         length += sizeof(UA_StatusCode);
-    if(ptr->hasInnerDiagnosticInfo)
-        length += UA_DiagnosticInfo_calcSizeBinary(ptr->innerDiagnosticInfo);
+    if(p->hasInnerDiagnosticInfo)
+        length += UA_DiagnosticInfo_calcSizeBinary(p->innerDiagnosticInfo);
     return length;
 }
 

+ 17 - 6
src/ua_util.h

@@ -74,6 +74,22 @@
 # endif
 #endif
 
+/************************/
+/* Thread Local Storage */
+/************************/
+
+#ifdef UA_MULTITHREADING
+# ifdef __GNUC__
+#  define UA_THREAD_LOCAL __thread
+# elif defined(_MSC_VER)
+#  define UA_THREAD_LOCAL __declspec(thread)
+# else
+#  error No thread local storage keyword defined for this compiler
+# endif
+#else
+# define UA_THREAD_LOCAL
+#endif
+
 /********************/
 /* System Libraries */
 /********************/
@@ -86,13 +102,8 @@
 # include <winsock2.h> //needed for amalgation
 # include <windows.h>
 # undef SLIST_ENTRY
-# define RAND(SEED) (UA_UInt32)rand()
 #else
-  #ifdef __CYGWIN__
-  extern int rand_r (unsigned int *__seed);
-  #endif
-  # include <sys/time.h>
-  # define RAND(SEED) (UA_UInt32)rand_r(SEED)
+# include <sys/time.h>
 #endif
 
 /*************************/

+ 1 - 1
tools/amalgamate.py

@@ -18,7 +18,7 @@ pos = outname.find(".")
 if pos > 0:
     outname = outname[:pos]
 include_re = re.compile("^#include (\".*\").*$")
-guard_re = re.compile("^#(?:(?:ifndef|define) [A-Z_]+_H_|endif /\* [A-Z_]+_H_ \*/)")
+guard_re = re.compile("^#(?:(?:ifndef|define) [A-Z_]+_H_|endif /\* [A-Z_]+_H_ \*/|endif // [A-Z_]+_H_)")
 includes = []
 
 print ("Starting amalgamating file "+ args.outfile)

+ 4 - 4
tools/generate_datatypes.py

@@ -326,13 +326,13 @@ class StructType(object):
         return layout + "}"
 
     def functions_c(self, typeTableName):
-        return '''static UA_INLINE %s * %s_new(void) { return UA_new(%s); }
-static UA_INLINE void %s_init(%s *p) { UA_init(p, %s); }
+        return '''static UA_INLINE void %s_init(%s *p) { UA_init(p, %s); }
 static UA_INLINE void %s_delete(%s *p) { UA_delete(p, %s); }
 static UA_INLINE void %s_deleteMembers(%s *p) { UA_deleteMembers(p, %s); }
+static UA_INLINE %s * %s_new(void) { return (%s *) UA_new(%s); }
 static UA_INLINE UA_StatusCode %s_copy(const %s *src, %s *dst) { return UA_copy(src, dst, %s); }''' % \
-    tuple(list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 4)))
-          + [self.name, self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"])
+    tuple(  list(itertools.chain(*itertools.repeat([self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 3)))
+          + list(itertools.chain(*itertools.repeat([self.name, self.name, self.name, "&"+typeTableName+"[" + typeTableName + "_" + self.name[3:].upper()+"]"], 2))) )
 
     def encoding_h(self, typeTableName):
         return '''static UA_INLINE UA_StatusCode %s_encodeBinary(const %s *src, UA_ByteString *dst, size_t *offset) { return UA_encodeBinary(src, %s, dst, offset); }