Bläddra i källkod

Merge branch 'unsigned_array_size' into simple_nodestore

Conflicts:
	examples/server_readspeed.c
Julius Pfrommer 9 år sedan
förälder
incheckning
78c0891392

+ 2 - 2
CMakeLists.txt

@@ -426,8 +426,8 @@ if(BUILD_EXAMPLES)
 	add_executable(server_datasource ${PROJECT_SOURCE_DIR}/examples/server_datasource.c $<TARGET_OBJECTS:open62541-object>)
 	target_link_libraries(server_datasource ${LIBS})
 
-	add_executable(server_readspeed ${PROJECT_SOURCE_DIR}/examples/server_readspeed.c $<TARGET_OBJECTS:open62541-object>)
-	target_link_libraries(server_readspeed ${LIBS})
+	# add_executable(server_readspeed ${PROJECT_SOURCE_DIR}/examples/server_readspeed.c $<TARGET_OBJECTS:open62541-object>)
+	# target_link_libraries(server_readspeed ${LIBS})
 
 	add_executable(server_firstSteps ${PROJECT_SOURCE_DIR}/examples/server_firstSteps.c $<TARGET_OBJECTS:open62541-object>)
 	target_link_libraries(server_firstSteps ${LIBS})

+ 2 - 2
examples/CMakeLists.txt

@@ -14,8 +14,8 @@ if(ENABLE_MULTITHREADING)
     list(APPEND LIBS urcu-cds urcu urcu-common)
 endif(ENABLE_MULTITHREADING)
 
-add_executable(server_readspeed server_readspeed.c)
-target_link_libraries(server_readspeed ${LIBS})
+# add_executable(server_readspeed server_readspeed.c)
+# target_link_libraries(server_readspeed ${LIBS})
 
 add_executable(server_variable server_variable.c)
 target_link_libraries(server_variable ${LIBS})

+ 8 - 1
examples/networklayer_tcp.c

@@ -498,7 +498,14 @@ ClientNetworkLayerTCP_connect(UA_ConnectionConfig localConf, char *endpointUrl,
     UA_UInt16 port;
     for(port = 0; portpos < urlLength-1; portpos++) {
         if(endpointUrl[portpos] == ':') {
-            port = atoi(&endpointUrl[portpos+1]);
+            char *endPtr = NULL;
+            unsigned long int tempulong = strtoul(&endpointUrl[portpos+1], &endPtr, 10);
+            if (ERANGE != errno &&
+                tempulong < UINT16_MAX &&
+                endPtr != &endpointUrl[portpos+1])
+            {
+                port = (UA_UInt16)tempulong;
+            }
             break;
         }
     }

+ 4 - 7
examples/server_readspeed.c

@@ -7,6 +7,7 @@
 
 #ifdef UA_NO_AMALGAMATION
 # include "ua_types.h"
+# include "ua_types_generated.h"
 # include "ua_server.h"
 # include "logger_stdout.h"
 # include "networklayer_tcp.h"
@@ -16,7 +17,6 @@
 
 #include <time.h>
 #include <stdio.h>
-#include "ua_types_generated.h"
 #include "server/ua_services.h"
 #include "ua_types_encoding_binary.h"
 
@@ -33,7 +33,6 @@ int main(int argc, char** argv) {
 
     UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
     UA_Server_setLogger(server, logger);
-    UA_Server_addNetworkLayer(server, ServerNetworkLayerTCP_new(UA_ConnectionConfig_standard, 16664));
 
     /* add a variable node to the address space */
     UA_VariableAttributes attr;
@@ -75,14 +74,11 @@ int main(int argc, char** argv) {
     UA_ReadRequest rq;
     UA_ReadResponse rr;
 
-    for(int i = 0; i < 800000; i++) {
-        UA_ReadRequest_init(&rq);
-        UA_ReadResponse_init(&rr);
-
+    for(int i = 0; i < 750000; i++) {
         offset = 0;
         retval |= UA_decodeBinary(&request_msg, &offset, &rq, &UA_TYPES[UA_TYPES_READREQUEST]);
-        //assert(retval != UA_STATUSCODE_GOOD);
 
+        UA_ReadResponse_init(&rr);
         Service_Read(server, &adminSession, &rq, &rr);
 
         offset = 0;
@@ -95,6 +91,7 @@ int main(int argc, char** argv) {
     end = clock();
     double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
     printf("duration was %f s\n", time_spent);
+    printf("retval is %i\n", retval);
 
     UA_ByteString_deleteMembers(&request_msg);
     UA_ByteString_deleteMembers(&response_msg);

+ 12 - 3
include/ua_types.h

@@ -100,7 +100,7 @@ UA_EXPORT extern const UA_String UA_STRING_NULL;
 
 static UA_INLINE UA_String UA_STRING(char *chars) {
     UA_String str; str.length = strlen(chars);
-    str.data   = (UA_Byte*)chars; return str; }
+    str.data = (UA_Byte*)chars; return str; }
 
 #define UA_STRING_ALLOC(CHARS) UA_String_fromChars(CHARS)
     
@@ -113,7 +113,7 @@ UA_Boolean UA_EXPORT UA_String_equal(const UA_String *s1, const UA_String *s2);
 /* DateTime: 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). */
+   number of 100 nanosecond intervals since January 1, 1601 (UTC) */
 typedef UA_Int64 UA_DateTime;
 
 UA_DateTime UA_EXPORT UA_DateTime_now(void); ///> The current time
@@ -541,7 +541,8 @@ void UA_EXPORT * UA_new(const UA_DataType *type) UA_FUNC_ATTR_MALLOC;
  * @param p The memory location of the variable
  * @param type The datatype description
  */
-void UA_EXPORT UA_init(void *p, const UA_DataType *type);
+static UA_INLINE void UA_init(void *p, const UA_DataType *type) {
+    memset(p, 0, type->memSize); }
 
 /**
  * Copies the content of two variables. If copying fails (e.g. because no memory was available for
@@ -641,6 +642,14 @@ typedef enum {
     UA_ATTRIBUTEID_USEREXECUTABLE          = 22
 } UA_AttributeId;
 
+typedef enum {
+    UA_ACCESSLEVELMASK_READ = 0x01,
+    UA_ACCESSLEVELMASK_WRITE = 0x02,
+    UA_ACCESSLEVELMASK_HISTORYREAD = 0x4,
+    UA_ACCESSLEVELMASK_HISTORYWRITE = 0x08,
+    UA_ACCESSLEVELMASK_SEMANTICCHANGE = 0x10
+} UA_AccessLevelMask;
+
 /***************************/
 /* Random Number Generator */
 /***************************/

+ 1 - 1
src/client/ua_client.c

@@ -524,7 +524,7 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
     UA_LOG_DEBUG(client->logger, UA_LOGCATEGORY_CLIENT,
                  "Sending a request of type %i", requestType->typeId.identifier.numeric);
     retval = UA_SecureChannel_sendBinaryMessage(&client->channel, requestId, request, requestType);
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         if(retval == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED)
             respHeader->serviceResult = UA_STATUSCODE_BADREQUESTTOOLARGE;
         else

+ 6 - 2
src/client/ua_client_highlevel_subscriptions.c

@@ -282,8 +282,12 @@ void UA_Client_Subscriptions_manuallySendPublishRequest(UA_Client *client) {
         UA_Client_NotificationsAckNumber *ack;
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
             request.subscriptionAcknowledgementsSize++;
-        request.subscriptionAcknowledgements = UA_malloc(sizeof(UA_SubscriptionAcknowledgement) *
-                                                         request.subscriptionAcknowledgementsSize);
+        if(request.subscriptionAcknowledgementsSize > 0) {
+            request.subscriptionAcknowledgements = UA_malloc(sizeof(UA_SubscriptionAcknowledgement) *
+                                                             request.subscriptionAcknowledgementsSize);
+            if(!request.subscriptionAcknowledgements)
+                return;
+        }
         
         int index = 0 ;
         LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry) {

+ 9 - 6
src/server/ua_nodes.c

@@ -19,7 +19,7 @@ static UA_StatusCode UA_Node_copy(const UA_Node *src, UA_Node *dst) {
 	retval |= UA_LocalizedText_copy(&src->description, &dst->description);
 	dst->writeMask = src->writeMask;
 	dst->userWriteMask = src->userWriteMask;
-	if(retval) {
+	if(retval != UA_STATUSCODE_GOOD) {
     	UA_Node_deleteMembers(dst);
         return retval;
     }
@@ -192,6 +192,9 @@ UA_StatusCode UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectType
 void UA_VariableNode_init(UA_VariableNode *p) {
     memset(p, 0, sizeof(UA_VariableNode));
     p->nodeClass = UA_NODECLASS_VARIABLE;
+    p->valueRank = -2; // scalar or array of any dimension
+    p->accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
+    p->userAccessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
 }
 
 UA_VariableNode * UA_VariableNode_new(void) {
@@ -221,7 +224,7 @@ UA_StatusCode UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *
         dst->value.variant.callback = src->value.variant.callback;
     } else
         dst->value.dataSource = src->value.dataSource;
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_VariableNode_deleteMembers(dst);
         return retval;
     }
@@ -264,9 +267,9 @@ UA_StatusCode UA_VariableTypeNode_copy(const UA_VariableTypeNode *src, UA_Variab
     if(src->valueSource == UA_VALUESOURCE_VARIANT){
         UA_Variant_copy(&src->value.variant.value, &dst->value.variant.value);
         dst->value.variant.callback = src->value.variant.callback;
-    }else
+    } else
         dst->value.dataSource = src->value.dataSource;
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_VariableTypeNode_deleteMembers(dst);
         return retval;
     }
@@ -299,10 +302,10 @@ void UA_ReferenceTypeNode_delete(UA_ReferenceTypeNode *p) {
 
 UA_StatusCode UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src, UA_ReferenceTypeNode *dst) {
     UA_StatusCode retval = UA_Node_copy((const UA_Node*)src, (UA_Node*)dst);
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         return retval;
     retval = UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_ReferenceTypeNode_deleteMembers(dst);
         return retval;
     }

+ 66 - 39
src/server/ua_securechannel_manager.c

@@ -2,21 +2,22 @@
 #include "ua_session.h"
 #include "ua_statuscodes.h"
 
-UA_StatusCode
-UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_UInt32 maxChannelCount,
-                             UA_UInt32 tokenLifetime, UA_UInt32 startChannelId,
-                             UA_UInt32 startTokenId) {
+UA_StatusCode UA_SecureChannelManager_init(UA_SecureChannelManager *cm,
+        size_t maxChannelCount, UA_UInt32 tokenLifetime,
+        UA_UInt32 startChannelId, UA_UInt32 startTokenId) {
     LIST_INIT(&cm->channels);
-    cm->lastChannelId      = startChannelId;
-    cm->lastTokenId        = startTokenId;
+    cm->lastChannelId = startChannelId;
+    cm->lastTokenId = startTokenId;
     cm->maxChannelLifetime = tokenLifetime;
-    cm->maxChannelCount    = maxChannelCount;
+    cm->maxChannelCount = maxChannelCount;
+    cm->currentChannelCount = 0;
     return UA_STATUSCODE_GOOD;
 }
 
 void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
     channel_list_entry *entry, *temp;
-    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp) {
+    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp)
+    {
         LIST_REMOVE(entry, pointers);
         UA_SecureChannel_deleteMembersCleanup(&entry->channel);
         UA_free(entry);
@@ -24,16 +25,25 @@ void UA_SecureChannelManager_deleteMembers(UA_SecureChannelManager *cm) {
 }
 
 /* remove channels that were not renewed or who have no connection attached */
-void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm, UA_DateTime now) {
+void UA_SecureChannelManager_cleanupTimedOut(UA_SecureChannelManager *cm,
+        UA_DateTime now) {
     channel_list_entry *entry, *temp;
-    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp) {
-        UA_DateTime timeout = entry->channel.securityToken.createdAt +
-            ((UA_DateTime)entry->channel.securityToken.revisedLifetime * 10000);
-        if(timeout < now || !entry->channel.connection) {
+    LIST_FOREACH_SAFE(entry, &cm->channels, pointers, temp)
+    {
+        UA_DateTime timeout = entry->channel.securityToken.createdAt
+                + ((UA_DateTime) entry->channel.securityToken.revisedLifetime
+                        * 10000);
+        if (timeout < now || !entry->channel.connection) {
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
+#ifndef UA_MULTITHREADING
+            cm->currentChannelCount--;
+#else
+            cm->currentChannelCount = uatomic_add_return(
+                    &cm->currentChannelCount, -1);
+#endif
             UA_free(entry);
-        } else if(entry->channel.nextSecurityToken.tokenId > 0) {
+        } else if (entry->channel.nextSecurityToken.tokenId > 0) {
             UA_SecureChannel_revolveTokens(&entry->channel);
         }
     }
@@ -45,10 +55,16 @@ UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
                              UA_OpenSecureChannelResponse *response) {
     if(request->securityMode != UA_MESSAGESECURITYMODE_NONE)
         return UA_STATUSCODE_BADSECURITYMODEREJECTED;
-
+    if(cm->currentChannelCount >= cm->maxChannelCount)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
     channel_list_entry *entry = UA_malloc(sizeof(channel_list_entry));
-    if(!entry)
+    if (!entry)
         return UA_STATUSCODE_BADOUTOFMEMORY;
+#ifndef UA_MULTITHREADING
+    cm->currentChannelCount++;
+#else
+    cm->currentChannelCount = uatomic_add_return(&cm->currentChannelCount, 1);
+#endif
 
     UA_SecureChannel_init(&entry->channel);
     response->responseHeader.stringTableSize = 0;
@@ -58,75 +74,86 @@ UA_SecureChannelManager_open(UA_SecureChannelManager *cm, UA_Connection *conn,
     entry->channel.securityToken.channelId = cm->lastChannelId++;
     entry->channel.securityToken.tokenId = cm->lastTokenId++;
     entry->channel.securityToken.createdAt = UA_DateTime_now();
-    entry->channel.securityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
-                                                   cm->maxChannelLifetime : request->requestedLifetime;
+    entry->channel.securityToken.revisedLifetime =
+            (request->requestedLifetime > cm->maxChannelLifetime) ?
+                    cm->maxChannelLifetime : request->requestedLifetime;
     /* pragmatic workaround to get clients requesting lifetime of 0 working */
-    if(entry->channel.securityToken.revisedLifetime == 0)
+    if (entry->channel.securityToken.revisedLifetime == 0)
         entry->channel.securityToken.revisedLifetime = cm->maxChannelLifetime;
 
     UA_ByteString_copy(&request->clientNonce, &entry->channel.clientNonce);
-    entry->channel.serverAsymAlgSettings.securityPolicyUri =
-        UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
+    entry->channel.serverAsymAlgSettings.securityPolicyUri = UA_STRING_ALLOC(
+            "http://opcfoundation.org/UA/SecurityPolicy#None");
 
     UA_SecureChannel_generateNonce(&entry->channel.serverNonce);
     UA_ByteString_copy(&entry->channel.serverNonce, &response->serverNonce);
-    UA_ChannelSecurityToken_copy(&entry->channel.securityToken, &response->securityToken);
+    UA_ChannelSecurityToken_copy(&entry->channel.securityToken,
+            &response->securityToken);
 
     UA_Connection_attachSecureChannel(conn, &entry->channel);
     LIST_INSERT_HEAD(&cm->channels, entry, pointers);
     return UA_STATUSCODE_GOOD;
 }
 
-UA_StatusCode
-UA_SecureChannelManager_renew(UA_SecureChannelManager *cm, UA_Connection *conn,
-                              const UA_OpenSecureChannelRequest *request,
-                              UA_OpenSecureChannelResponse *response) {
+UA_StatusCode UA_SecureChannelManager_renew(UA_SecureChannelManager *cm,
+        UA_Connection *conn, const UA_OpenSecureChannelRequest *request,
+        UA_OpenSecureChannelResponse *response) {
     UA_SecureChannel *channel = conn->channel;
-    if(!channel)
+    if (!channel)
         return UA_STATUSCODE_BADINTERNALERROR;
 
     /* if no security token is already issued */
-    if(channel->nextSecurityToken.tokenId == 0) {
+    if (channel->nextSecurityToken.tokenId == 0) {
         channel->nextSecurityToken.channelId = channel->securityToken.channelId;
         //FIXME: UaExpert seems not to use the new tokenid
         channel->nextSecurityToken.tokenId = cm->lastTokenId++;
         //channel->nextSecurityToken.tokenId = channel->securityToken.tokenId;
         channel->nextSecurityToken.createdAt = UA_DateTime_now();
-        channel->nextSecurityToken.revisedLifetime = (request->requestedLifetime > cm->maxChannelLifetime) ?
-                                                 cm->maxChannelLifetime : request->requestedLifetime;
+        channel->nextSecurityToken.revisedLifetime =
+                (request->requestedLifetime > cm->maxChannelLifetime) ?
+                        cm->maxChannelLifetime : request->requestedLifetime;
 
         /* pragmatic workaround to get clients requesting lifetime of 0 working */
-        if(channel->nextSecurityToken.revisedLifetime == 0)
+        if (channel->nextSecurityToken.revisedLifetime == 0)
             channel->nextSecurityToken.revisedLifetime = cm->maxChannelLifetime;
     }
 
-    if(channel->clientNonce.data)
+    if (channel->clientNonce.data)
         UA_ByteString_deleteMembers(&channel->clientNonce);
 
     UA_ByteString_copy(&request->clientNonce, &channel->clientNonce);
     UA_ByteString_copy(&channel->serverNonce, &response->serverNonce);
-    UA_ChannelSecurityToken_copy(&channel->nextSecurityToken, &response->securityToken);
+    UA_ChannelSecurityToken_copy(&channel->nextSecurityToken,
+            &response->securityToken);
     return UA_STATUSCODE_GOOD;
 }
 
 UA_SecureChannel *
 UA_SecureChannelManager_get(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
     channel_list_entry *entry;
-    LIST_FOREACH(entry, &cm->channels, pointers) {
-        if(entry->channel.securityToken.channelId == channelId)
+    LIST_FOREACH(entry, &cm->channels, pointers)
+    {
+        if (entry->channel.securityToken.channelId == channelId)
             return &entry->channel;
     }
     return NULL;
 }
 
-UA_StatusCode
-UA_SecureChannelManager_close(UA_SecureChannelManager *cm, UA_UInt32 channelId) {
+UA_StatusCode UA_SecureChannelManager_close(UA_SecureChannelManager *cm,
+        UA_UInt32 channelId) {
     channel_list_entry *entry;
-    LIST_FOREACH(entry, &cm->channels, pointers) {
-        if(entry->channel.securityToken.channelId == channelId) {
+    LIST_FOREACH(entry, &cm->channels, pointers)
+    {
+        if (entry->channel.securityToken.channelId == channelId) {
             LIST_REMOVE(entry, pointers);
             UA_SecureChannel_deleteMembersCleanup(&entry->channel);
             UA_free(entry);
+#ifndef UA_MULTITHREADING
+            cm->currentChannelCount--;
+#else
+            cm->currentChannelCount = uatomic_add_return(
+                    &cm->currentChannelCount, -1);
+#endif
             return UA_STATUSCODE_GOOD;
         }
     }

+ 3 - 2
src/server/ua_securechannel_manager.h

@@ -13,7 +13,8 @@ typedef struct channel_list_entry {
 
 typedef struct UA_SecureChannelManager {
     LIST_HEAD(channel_list, channel_list_entry) channels; // doubly-linked list of channels
-    UA_Int32    maxChannelCount;
+    size_t    maxChannelCount;
+    size_t currentChannelCount;
     UA_DateTime maxChannelLifetime;
     UA_MessageSecurityMode securityMode;
     UA_DateTime channelLifeTime;
@@ -22,7 +23,7 @@ typedef struct UA_SecureChannelManager {
 } UA_SecureChannelManager;
 
 UA_StatusCode
-UA_SecureChannelManager_init(UA_SecureChannelManager *cm, UA_UInt32 maxChannelCount,
+UA_SecureChannelManager_init(UA_SecureChannelManager *cm, size_t maxChannelCount,
                              UA_UInt32 tokenLifetime, UA_UInt32 startChannelId,
                              UA_UInt32 startTokenId);
 

+ 15 - 18
src/server/ua_server.c

@@ -37,7 +37,7 @@ static const UA_NodeId nodeIdOrganizes = {
 
 static const UA_ExpandedNodeId expandedNodeIdBaseDataVariabletype = {
     .nodeId = {.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC,
-               .identifier.numeric = UA_NS0ID_HASTYPEDEFINITION},
+               .identifier.numeric = UA_NS0ID_BASEDATAVARIABLETYPE},
     .namespaceUri = {.length = -1, .data = NULL}, .serverIndex = 0};
 
 #ifndef ENABLE_GENERATE_NAMESPACE0
@@ -287,7 +287,7 @@ static void UA_Server_cleanup(UA_Server *server, void *nothing) {
 #define SOFTWARE_VERSION TOSTRING(VERSION)
 #define BUILD_NUMBER "0"
 
-static void getBulidInfo(const UA_Server* server, UA_BuildInfo *buildInfo) {
+static void getBuildInfo(const UA_Server* server, UA_BuildInfo *buildInfo) {
     buildInfo->productUri = UA_STRING_ALLOC(PRODUCT_URI);
     buildInfo->manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME);
     buildInfo->productName = UA_STRING_ALLOC(PRODUCT_NAME);
@@ -304,12 +304,13 @@ readStatus(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp,
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_GOOD;
     }
-    
+
+    UA_Server *server = (UA_Server*)handle;
     UA_ServerStatusDataType *status = UA_ServerStatusDataType_new();
-    status->startTime = ((const UA_Server*)handle)->startTime;
+    status->startTime = server->startTime;
     status->currentTime = UA_DateTime_now();
     status->state = UA_SERVERSTATE_RUNNING;
-    getBulidInfo(((const UA_Server*)handle), &status->buildInfo);
+    getBuildInfo(server, &status->buildInfo);
     status->secondsTillShutdown = 0;
 
     value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
@@ -355,16 +356,14 @@ readCurrentTime(void *handle, const UA_NodeId nodeid, UA_Boolean sourceTimeStamp
         value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
         return UA_STATUSCODE_GOOD;
     }
-    UA_DateTime *currentTime = UA_DateTime_new();
-    if(!currentTime)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    *currentTime = UA_DateTime_now();
-    value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
-    value->value.data = currentTime;
+    UA_DateTime currentTime = UA_DateTime_now();
+    UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, &currentTime, &UA_TYPES[UA_TYPES_DATETIME]);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval;
     value->hasValue = UA_TRUE;
     if(sourceTimeStamp) {
         value->hasSourceTimestamp = UA_TRUE;
-        value->sourceTimestamp = *currentTime;
+        value->sourceTimestamp = currentTime;
     }
     return UA_STATUSCODE_GOOD;
 }
@@ -1047,11 +1046,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     serverstatus->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS);
     serverstatus->valueSource = UA_VALUESOURCE_DATASOURCE;
     serverstatus->value.dataSource = (UA_DataSource) {.handle = server, .read = readStatus, .write = NULL};
-    addNodeInternal(server, (UA_Node*)serverstatus, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
-                    nodeIdHasComponent);
-    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS),
-                           nodeIdHasTypeDefinition, UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE),
-                           UA_TRUE);
+    addNodeInternal(server, (UA_Node*)serverstatus, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), nodeIdHasComponent);
+    UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasTypeDefinition,
+                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_SERVERSTATUSTYPE), UA_TRUE);
 
     UA_VariableNode *starttime = UA_VariableNode_new();
     copyNames((UA_Node*)starttime, "StartTime");
@@ -1093,7 +1090,7 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     buildinfo->nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO);
     buildinfo->value.variant.value.data = UA_BuildInfo_new();
     buildinfo->value.variant.value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
-    getBulidInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
+    getBuildInfo(server, (UA_BuildInfo*)buildinfo->value.variant.value.data);
     addNodeInternal(server, (UA_Node*)buildinfo,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), nodeIdHasComponent);
     UA_Server_addReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO),

+ 1 - 2
src/server/ua_services_attribute.c

@@ -51,7 +51,7 @@ UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
     do {
         /* alloc dimensions */
         if(index >= (UA_Int32)dimensionsMax) {
-            struct UA_NumericRangeDimension *newds = UA_realloc(dimensions, dimensionsMax + 2);
+            struct UA_NumericRangeDimension *newds = UA_realloc(dimensions, sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2));
             if(!newds) {
                 retval = UA_STATUSCODE_BADOUTOFMEMORY;
                 break;
@@ -548,7 +548,6 @@ MoveValueIntoNode(UA_Server *server, UA_Session *session, UA_VariableNode *node,
     if(node->value.variant.callback.onWrite)
         node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,
                                              &node->value.variant.value, rangeptr);
-
     if(rangeptr)
         UA_free(range.dimensions);
     return retval;

+ 2 - 1
src/server/ua_services_subscription.c

@@ -168,7 +168,8 @@ void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishReq
         
         response->subscriptionId = sub->subscriptionID;
         Subscription_copyTopNotificationMessage(&response->notificationMessage, sub);
-        if(sub->unpublishedNotifications.lh_first->notification->sequenceNumber > sub->sequenceNumber) {
+        UA_unpublishedNotification *firstUnPublished = LIST_FIRST(&sub->unpublishedNotifications);
+        if(firstUnPublished->notification.sequenceNumber > sub->sequenceNumber) {
             // If this is a keepalive message, its seqNo is the next seqNo to be used for an actual msg.
             response->availableSequenceNumbersSize = 0;
             // .. and must be deleted

+ 2 - 3
src/server/ua_services_view.c

@@ -31,8 +31,7 @@ fillReferenceDescription(UA_NodeStore *ns, const UA_Node *curr, UA_ReferenceNode
             }
         }
     }
-
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         UA_ReferenceDescription_deleteMembers(descr);
     return retval;
 }
@@ -185,7 +184,7 @@ findSubTypes(UA_NodeStore *ns, const UA_NodeId *root, UA_NodeId **reftypes, size
         }
     } while(++index <= last && retval == UA_STATUSCODE_GOOD);
 
-    if(retval) {
+    if(retval != UA_STATUSCODE_GOOD) {
         UA_Array_delete(results, last, &UA_TYPES[UA_TYPES_NODEID]);
         return retval;
     }

+ 28 - 25
src/server/ua_subscription.c

@@ -59,16 +59,14 @@ void Subscription_generateKeepAlive(UA_Subscription *subscription) {
        subscription->keepAliveCount.currentValue <= subscription->keepAliveCount.maxValue)
         return;
 
-    UA_unpublishedNotification *msg = UA_malloc(sizeof(UA_unpublishedNotification));
+    UA_unpublishedNotification *msg = UA_calloc(1,sizeof(UA_unpublishedNotification));
     if(!msg)
         return;
-    msg->notification = NULL;
-    msg->notification = UA_malloc(sizeof(UA_NotificationMessage));
-    msg->notification->notificationData = NULL;
+    msg->notification.notificationData = NULL;
     // KeepAlive uses next message, but does not increment counter
-    msg->notification->sequenceNumber = subscription->sequenceNumber + 1;
-    msg->notification->publishTime    = UA_DateTime_now();
-    msg->notification->notificationDataSize = 0;
+    msg->notification.sequenceNumber = subscription->sequenceNumber + 1;
+    msg->notification.publishTime    = UA_DateTime_now();
+    msg->notification.notificationDataSize = 0;
     LIST_INSERT_HEAD(&subscription->unpublishedNotifications, msg, listEntry);
     subscription->keepAliveCount.currentValue = subscription->keepAliveCount.maxValue;
 }
@@ -112,19 +110,18 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
         return;
     }
     
-    msg = UA_malloc(sizeof(UA_unpublishedNotification));
-    msg->notification = UA_NotificationMessage_new();
-    msg->notification->sequenceNumber = subscription->sequenceNumber++;
-    msg->notification->publishTime    = UA_DateTime_now();
+    msg = UA_calloc(1, sizeof(UA_unpublishedNotification));
+    msg->notification.sequenceNumber = subscription->sequenceNumber++;
+    msg->notification.publishTime    = UA_DateTime_now();
     
     // NotificationData is an array of Change, Status and Event messages, each containing the appropriate
     // list of Queued values from all monitoredItems of that type
-    msg->notification->notificationDataSize = ISNOTZERO(monItemsChangeT);
+    msg->notification.notificationDataSize = !!monItemsChangeT; // 1 if the pointer is not null, else 0
     // + ISNOTZERO(monItemsEventT) + ISNOTZERO(monItemsStatusT);
-    msg->notification->notificationData =
-        UA_Array_new(msg->notification->notificationDataSize, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
+    msg->notification.notificationData =
+        UA_Array_new(msg->notification.notificationDataSize, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
     
-    for(size_t notmsgn = 0; notmsgn < msg->notification->notificationDataSize; notmsgn++) {
+    for(size_t notmsgn = 0; notmsgn < msg->notification.notificationDataSize; notmsgn++) {
         // Set the notification message type and encoding for each of 
         //   the three possible NotificationData Types
         /* msg->notification->notificationData[notmsgn].encoding = 1; // Encoding is always binary */
@@ -145,9 +142,9 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
                 MonitoredItem_ClearQueue(mon);
             }
             changeNotification->monitoredItemsSize = monItemsChangeT;
-            msg->notification->notificationData[notmsgn].encoding = UA_EXTENSIONOBJECT_DECODED;
-            msg->notification->notificationData[notmsgn].content.decoded.type = &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION];
-            msg->notification->notificationData[notmsgn].content.decoded.data = changeNotification;
+            msg->notification.notificationData[notmsgn].encoding = UA_EXTENSIONOBJECT_DECODED;
+            msg->notification.notificationData[notmsgn].content.decoded.type = &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION];
+            msg->notification.notificationData[notmsgn].content.decoded.data = changeNotification;
         } else if(notmsgn == 1) {
             // FIXME: Constructing a StatusChangeNotification is not implemented
         } else if(notmsgn == 2) {
@@ -165,7 +162,7 @@ UA_UInt32 *Subscription_getAvailableSequenceNumbers(UA_Subscription *sub) {
     int i = 0;
     UA_unpublishedNotification *not;
     LIST_FOREACH(not, &sub->unpublishedNotifications, listEntry) {
-        seqArray[i] = not->notification->sequenceNumber;
+        seqArray[i] = not->notification.sequenceNumber;
         i++;
     }
     return seqArray;
@@ -182,7 +179,7 @@ void Subscription_copyTopNotificationMessage(UA_NotificationMessage *dst, UA_Sub
       return;
     }
     
-    UA_NotificationMessage *latest = LIST_FIRST(&sub->unpublishedNotifications)->notification;
+    UA_NotificationMessage *latest = &LIST_FIRST(&sub->unpublishedNotifications)->notification;
     dst->notificationDataSize = latest->notificationDataSize;
     dst->publishTime = latest->publishTime;
     dst->sequenceNumber = latest->sequenceNumber;
@@ -197,11 +194,10 @@ UA_UInt32 Subscription_deleteUnpublishedNotification(UA_UInt32 seqNo, UA_Boolean
     UA_UInt32 deletedItems = 0;
     UA_unpublishedNotification *not, *tmp;
     LIST_FOREACH_SAFE(not, &sub->unpublishedNotifications, listEntry, tmp) {
-        if (!bDeleteAll && not->notification->sequenceNumber != seqNo)
+        if(!bDeleteAll && not->notification.sequenceNumber != seqNo)
             continue;
         LIST_REMOVE(not, listEntry);
-        if(not->notification)
-            UA_NotificationMessage_delete(not->notification);
+        UA_NotificationMessage_deleteMembers(&not->notification);
         UA_free(not);
         deletedItems++;
     }
@@ -230,7 +226,6 @@ static void Subscription_timedUpdateNotificationsJob(UA_Server *server, void *da
     Subscription_updateNotifications(sub);
 }
 
-
 UA_StatusCode Subscription_createdUpdateJob(UA_Server *server, UA_Guid jobId, UA_Subscription *sub) {
     if(server == NULL || sub == NULL)
         return UA_STATUSCODE_BADSERVERINDEXINVALID;
@@ -284,7 +279,7 @@ UA_MonitoredItem *UA_MonitoredItem_new() {
     new->monitoredItemType = MONITOREDITEM_TYPE_CHANGENOTIFY;
     TAILQ_INIT(&new->queue);
     UA_NodeId_init(&new->monitoredNodeId);
-    INITPOINTER(new->lastSampledValue.data );
+    new->lastSampledValue.data = 0;
     return new;
 }
 
@@ -344,30 +339,37 @@ UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, cons
     switch(attributeID) {
     case UA_ATTRIBUTEID_NODEID:
         UA_Variant_setScalarCopy(&dst->value, (const UA_NodeId*)&src->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
+        dst->hasValue = UA_TRUE;
         samplingError = UA_FALSE;
         break;
     case UA_ATTRIBUTEID_NODECLASS:
         UA_Variant_setScalarCopy(&dst->value, (const UA_Int32*)&src->nodeClass, &UA_TYPES[UA_TYPES_INT32]);
+        dst->hasValue = UA_TRUE;
         samplingError = UA_FALSE;
         break;
     case UA_ATTRIBUTEID_BROWSENAME:
         UA_Variant_setScalarCopy(&dst->value, (const UA_String*)&src->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
+        dst->hasValue = UA_TRUE;
         samplingError = UA_FALSE;
         break;
     case UA_ATTRIBUTEID_DISPLAYNAME:
         UA_Variant_setScalarCopy(&dst->value, (const UA_String*)&src->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        dst->hasValue = UA_TRUE;
         samplingError = UA_FALSE;
         break;
     case UA_ATTRIBUTEID_DESCRIPTION:
         UA_Variant_setScalarCopy(&dst->value, (const UA_String*)&src->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
+        dst->hasValue = UA_TRUE;
         samplingError = UA_FALSE;
         break;
     case UA_ATTRIBUTEID_WRITEMASK:
         UA_Variant_setScalarCopy(&dst->value, (const UA_String*)&src->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
+        dst->hasValue = UA_TRUE;
         samplingError = UA_FALSE;
         break;
     case UA_ATTRIBUTEID_USERWRITEMASK:
         UA_Variant_setScalarCopy(&dst->value, (const UA_String*)&src->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
+        dst->hasValue = UA_TRUE;
         samplingError = UA_FALSE;
         break;
     case UA_ATTRIBUTEID_ISABSTRACT:
@@ -385,6 +387,7 @@ UA_Boolean MonitoredItem_CopyMonitoredValueToVariant(UA_UInt32 attributeID, cons
             const UA_VariableNode *vsrc = (const UA_VariableNode*)src;
             if(srcAsVariableNode->valueSource == UA_VALUESOURCE_VARIANT) {
                 UA_Variant_copy(&vsrc->value.variant.value, &dst->value);
+                dst->hasValue = UA_TRUE;
                 //no onRead callback here since triggered by a subscription
                 samplingError = UA_FALSE;
             } else {

+ 1 - 4
src/server/ua_subscription.h

@@ -6,9 +6,6 @@
 #include "ua_types_generated.h"
 #include "ua_nodes.h"
 
-#define INITPOINTER(src) (src) = NULL;
-#define ISNOTZERO(value) ((value == 0) ? 0 : 1)
-
 /*****************/
 /* MonitoredItem */
 /*****************/
@@ -70,7 +67,7 @@ int MonitoredItem_QueueToDataChangeNotifications(UA_MonitoredItemNotification *d
 
 typedef struct UA_unpublishedNotification {
     LIST_ENTRY(UA_unpublishedNotification) listEntry;
-    UA_NotificationMessage *notification;
+    UA_NotificationMessage notification;
 } UA_unpublishedNotification;
 
 typedef struct UA_Subscription {

+ 55 - 50
src/ua_types.c

@@ -65,7 +65,7 @@ struct timezone {
 #endif
 
 #ifdef _WIN32
-static const unsigned __int64 epoch = 116444736000000000;
+static const UA_UInt64 epoch = 116444736000000000;
 int gettimeofday(struct timeval *tp, struct timezone *tzp);
 int gettimeofday(struct timeval *tp, struct timezone *tzp) {
     FILETIME       ft;
@@ -90,13 +90,13 @@ UA_DateTime UA_DateTime_now(void) {
 }
 
 UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
+    /* Calculating the the milli-, micro- and nanoseconds */
     UA_DateTimeStruct dateTimeStruct;
-    //calcualting the the milli-, micro- and nanoseconds
     dateTimeStruct.nanoSec  = (UA_UInt16)((atime % 10) * 100);
     dateTimeStruct.microSec = (UA_UInt16)((atime % 10000) / 10);
     dateTimeStruct.milliSec = (UA_UInt16)((atime % 10000000) / 10000);
 
-    //calculating the unix time with #include <time.h>
+    /* Calculating the unix time with #include <time.h> */
     time_t secSinceUnixEpoch = (atime/10000000) - UNIX_EPOCH_BIAS_SEC;
     struct tm ts = *gmtime(&secSinceUnixEpoch);
     dateTimeStruct.sec    = (UA_UInt16)ts.tm_sec;
@@ -109,15 +109,15 @@ UA_DateTimeStruct UA_DateTime_toStruct(UA_DateTime atime) {
 }
 
 static void printNumber(UA_UInt16 n, UA_Byte *pos, size_t digits) {
-    for(size_t i = 0; i < digits; i++) {
-        pos[digits-i-1] = (n % 10) + '0';
+    for(size_t i = digits; i > 0; i--) {
+        pos[i-1] = (n % 10) + '0';
         n = n / 10;
     }
 }
 
 UA_String UA_DateTime_toString(UA_DateTime time) {
     UA_String str = UA_STRING_NULL;
-    // length of the string is 31 (incl. \0 at the end)
+    // length of the string is 31 (plus \0 at the end)
     if(!(str.data = UA_malloc(32)))
         return str;
     str.length = 31;
@@ -177,7 +177,7 @@ UA_StatusCode UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) {
 }
 
 /* NodeId */
-static void NodeId_deleteMembers(UA_NodeId *p, const UA_DataType *dummy) {
+static void NodeId_deleteMembers(UA_NodeId *p, const UA_DataType *_) {
     switch(p->identifierType) {
     case UA_NODEIDTYPE_STRING:
     case UA_NODEIDTYPE_BYTESTRING:
@@ -188,7 +188,7 @@ static void NodeId_deleteMembers(UA_NodeId *p, const UA_DataType *dummy) {
     }
 }
 
-static UA_StatusCode NodeId_copy(UA_NodeId const *src, UA_NodeId *dst, const UA_DataType *dummy) {
+static UA_StatusCode NodeId_copy(UA_NodeId const *src, UA_NodeId *dst, const UA_DataType *_) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     switch(src->identifierType) {
     case UA_NODEIDTYPE_NUMERIC:
@@ -208,7 +208,7 @@ static UA_StatusCode NodeId_copy(UA_NodeId const *src, UA_NodeId *dst, const UA_
     }
     dst->namespaceIndex = src->namespaceIndex;
     dst->identifierType = src->identifierType;
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         NodeId_deleteMembers(dst, NULL);
     return retval;
 }
@@ -233,7 +233,7 @@ UA_Boolean UA_NodeId_equal(const UA_NodeId *n1, const UA_NodeId *n2) {
 }
 
 /* ExtensionObject */
-static void ExtensionObject_deleteMembers(UA_ExtensionObject *p, const UA_DataType *dummy) {
+static void ExtensionObject_deleteMembers(UA_ExtensionObject *p, const UA_DataType *_) {
     switch(p->encoding) {
     case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
     case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
@@ -257,7 +257,7 @@ static void ExtensionObject_deleteMembers(UA_ExtensionObject *p, const UA_DataTy
 }
 
 static UA_StatusCode
-ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst, const UA_DataType *dummy) {
+ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst, const UA_DataType *_) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     switch(src->encoding) {
     case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
@@ -273,7 +273,8 @@ ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst, con
             return UA_STATUSCODE_BADINTERNALERROR;
         dst->encoding = UA_EXTENSIONOBJECT_DECODED;
         dst->content.decoded.type = src->content.decoded.type;
-        retval = UA_Array_copy(src->content.decoded.data, 1, &dst->content.decoded.data, src->content.decoded.type);
+        retval = UA_Array_copy(src->content.decoded.data, 1,
+            &dst->content.decoded.data, src->content.decoded.type);
         break;
     default:
         break;
@@ -282,7 +283,7 @@ ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst, con
 }
 
 /* Variant */
-static void variant_deleteMembers(UA_Variant *p, const UA_DataType *dummy) {
+static void Variant_deletemembers(UA_Variant *p, const UA_DataType *_) {
     if(p->storageType != UA_VARIANT_DATA)
         return;
     if(p->data >= UA_EMPTY_ARRAY_SENTINEL) {
@@ -300,8 +301,7 @@ static void variant_deleteMembers(UA_Variant *p, const UA_DataType *dummy) {
 }
 
 static UA_StatusCode
-variant_copy(UA_Variant const *src, UA_Variant *dst, const UA_DataType *dummy) {
-    UA_Variant_init(dst);
+Variant_copy(UA_Variant const *src, UA_Variant *dst, const UA_DataType *_) {
     size_t length = src->arrayLength;
     if(UA_Variant_isScalar(src))
         length = 1;
@@ -311,34 +311,34 @@ variant_copy(UA_Variant const *src, UA_Variant *dst, const UA_DataType *dummy) {
     dst->arrayLength = src->arrayLength;
     dst->type = src->type;
     if(src->arrayDimensions) {
-        retval = UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize, (void**)&dst->arrayDimensions,
-                               &UA_TYPES[UA_TYPES_UINT32]);
+        retval = UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize,
+            (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
         if(retval == UA_STATUSCODE_GOOD)
             dst->arrayDimensionsSize = src->arrayDimensionsSize;
         else
-            variant_deleteMembers(dst, NULL);
+            Variant_deletemembers(dst, NULL);
     }
     return retval;
 }
 
 /**
- * Tests if a range is compatible with a variant. If yes, the following values are set:
+ * Test if a range is compatible with a variant. If yes, the following values are set:
  * - total: how many elements are in the range
  * - block: how big is each contiguous block of elements in the variant that maps into the range
  * - stride: how many elements are between the blocks (beginning to beginning)
  * - first: where does the first block begin
  */
 static UA_StatusCode
-testRangeWithVariant(const UA_Variant *v, const UA_NumericRange range, size_t *total,
-                     size_t *block, size_t *stride, size_t *first) {
+processRangeDefinition(const UA_Variant *v, const UA_NumericRange range, size_t *total,
+                       size_t *block, size_t *stride, size_t *first) {
     /* Test the integrity of the source variant dimensions */
-    size_t dims_count = 1;
+    UA_UInt32 dims_count = 1;
+    UA_UInt32 elements = 1;
     UA_UInt32 arrayLength = v->arrayLength;
     const UA_UInt32 *dims = &arrayLength;
     if(v->arrayDimensionsSize > 0) {
         dims_count = v->arrayDimensionsSize;
         dims = v->arrayDimensions;
-        size_t elements = 1;
         for(size_t i = 0; i < dims_count; i++)
             elements *= dims[i];
         if(elements != v->arrayLength)
@@ -358,7 +358,7 @@ testRangeWithVariant(const UA_Variant *v, const UA_NumericRange range, size_t *t
     }
 
     /* Compute the block size and the position of the first element */
-    size_t b = 0, s = 0, f = 0;
+    size_t b = 1, s = elements, f = 0;
     size_t running_dimssize = 1; // elements per block of dimensions k to k_max
     UA_Boolean found_contiguous = UA_FALSE;
     for(size_t k = dims_count - 1; ; k--) {
@@ -382,7 +382,7 @@ testRangeWithVariant(const UA_Variant *v, const UA_NumericRange range, size_t *t
 UA_StatusCode
 UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRange range) {
     size_t count, block, stride, first;
-    UA_StatusCode retval = testRangeWithVariant(src, range, &count, &block, &stride, &first);
+    UA_StatusCode retval = processRangeDefinition(src, range, &count, &block, &stride, &first);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     UA_Variant_init(dst);
@@ -424,7 +424,7 @@ UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRan
     if(src->arrayDimensionsSize > 0) {
         dst->arrayDimensions = UA_Array_new(src->arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
         if(!dst) {
-            variant_deleteMembers(dst, NULL);
+            Variant_deletemembers(dst, NULL);
             return UA_STATUSCODE_BADOUTOFMEMORY;
         }
         dst->arrayDimensionsSize = src->arrayDimensionsSize;
@@ -437,7 +437,7 @@ UA_Variant_copyRange(const UA_Variant *src, UA_Variant *dst, const UA_NumericRan
 UA_StatusCode
 UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, const UA_NumericRange range) {
     size_t count, block, stride, first;
-    UA_StatusCode retval = testRangeWithVariant(v, range, &count, &block, &stride, &first);
+    UA_StatusCode retval = processRangeDefinition(v, range, &count, &block, &stride, &first);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     if(count != arraySize)
@@ -465,7 +465,7 @@ UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array, size_t arraySize, c
 UA_StatusCode
 UA_Variant_setRangeCopy(UA_Variant *v, const void *array, size_t arraySize, const UA_NumericRange range) {
     size_t count, block, stride, first;
-    UA_StatusCode retval = testRangeWithVariant(v, range, &count, &block, &stride, &first);
+    UA_StatusCode retval = processRangeDefinition(v, range, &count, &block, &stride, &first);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     if(count != arraySize)
@@ -536,31 +536,32 @@ UA_Variant_setArrayCopy(UA_Variant *v, const void *array, size_t arraySize, cons
 }
 
 /* DataValue */
-static void DataValue_deleteMembers(UA_DataValue *p, const UA_DataType *dummy) {
-    variant_deleteMembers(&p->value, NULL);
+static void DataValue_deleteMembers(UA_DataValue *p, const UA_DataType *_) {
+    Variant_deletemembers(&p->value, NULL);
 }
 
 static UA_StatusCode
-DataValue_copy(UA_DataValue const *src, UA_DataValue *dst, const UA_DataType *dummy) {
+DataValue_copy(UA_DataValue const *src, UA_DataValue *dst, const UA_DataType *_) {
     memcpy(dst, src, sizeof(UA_DataValue));
     UA_Variant_init(&dst->value);
-    UA_StatusCode retval = variant_copy(&src->value, &dst->value, NULL);
-    if(retval)
+    UA_StatusCode retval = Variant_copy(&src->value, &dst->value, NULL);
+    if(retval != UA_STATUSCODE_GOOD)
         DataValue_deleteMembers(dst, NULL);
     return retval;
 }
 
 /* DiagnosticInfo */
-static void DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p, const UA_DataType *dummy) {
+static void DiagnosticInfo_deleteMembers(UA_DiagnosticInfo *p, const UA_DataType *_) {
     UA_String_deleteMembers(&p->additionalInfo);
     if(p->hasInnerDiagnosticInfo && p->innerDiagnosticInfo) {
-        UA_DiagnosticInfo_delete(p->innerDiagnosticInfo);
+        DiagnosticInfo_deleteMembers(p->innerDiagnosticInfo, _);
+        UA_free(p->innerDiagnosticInfo);
         p->innerDiagnosticInfo = NULL;
     }
 }
 
 static UA_StatusCode
-DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst, const UA_DataType *dummy) {
+DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst, const UA_DataType *_) {
     memcpy(dst, src, sizeof(UA_DiagnosticInfo));
     UA_String_init(&dst->additionalInfo);
     dst->innerDiagnosticInfo = NULL;
@@ -583,10 +584,6 @@ DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst, const
 /* Structure Types */
 /*******************/
 
-void UA_init(void *p, const UA_DataType *type) {
-    memset(p, 0, type->memSize);
-}
-
 void * UA_new(const UA_DataType *type) {
     void *p = UA_calloc(1, type->memSize);
     return p;
@@ -597,6 +594,8 @@ static UA_StatusCode UA_copyFixedSize(const void *src, void *dst, const UA_DataT
     return UA_STATUSCODE_GOOD;
 }
 
+static UA_StatusCode UA_copyNoInit(const void *src, void *dst, const UA_DataType *type);
+
 typedef UA_StatusCode (*UA_copySignature)(const void *src, void *dst, const UA_DataType *type);
 static const UA_copySignature copyJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
     (UA_copySignature)UA_copyFixedSize, // Boolean
@@ -610,24 +609,24 @@ static const UA_copySignature copyJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
     (UA_copySignature)UA_copyFixedSize, // UInt64 
     (UA_copySignature)UA_copyFixedSize, // Float 
     (UA_copySignature)UA_copyFixedSize, // Double 
-    (UA_copySignature)UA_copy, // String
+    (UA_copySignature)UA_copyNoInit, // String
     (UA_copySignature)UA_copyFixedSize, // DateTime
     (UA_copySignature)UA_copyFixedSize, // Guid 
-    (UA_copySignature)UA_copy, // ByteString
-    (UA_copySignature)UA_copy, // XmlElement
+    (UA_copySignature)UA_copyNoInit, // ByteString
+    (UA_copySignature)UA_copyNoInit, // XmlElement
     (UA_copySignature)NodeId_copy,
-    (UA_copySignature)UA_copy, // ExpandedNodeId
+    (UA_copySignature)UA_copyNoInit, // ExpandedNodeId
     (UA_copySignature)UA_copyFixedSize, // StatusCode
-    (UA_copySignature)UA_copy, // QualifiedName
-    (UA_copySignature)UA_copy, // LocalizedText
+    (UA_copySignature)UA_copyNoInit, // QualifiedName
+    (UA_copySignature)UA_copyNoInit, // LocalizedText
     (UA_copySignature)ExtensionObject_copy,
     (UA_copySignature)DataValue_copy,
-    (UA_copySignature)variant_copy,
+    (UA_copySignature)Variant_copy,
     (UA_copySignature)DiagnosticInfo_copy,
-    (UA_copySignature)UA_copy,
+    (UA_copySignature)UA_copyNoInit,
 };
 
-UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *type) {
+static UA_StatusCode UA_copyNoInit(const void *src, void *dst, const UA_DataType *type) {
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     uintptr_t ptrs = (uintptr_t)src;
     uintptr_t ptrd = (uintptr_t)dst;
@@ -663,8 +662,14 @@ UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *type) {
     return retval;
 }
 
+UA_StatusCode UA_copy(const void *src, void *dst, const UA_DataType *type) {
+    memset(dst, 0, type->memSize);
+    return UA_copyNoInit(src, dst, type);
+}
+
 typedef void (*UA_deleteMembersSignature)(void *p, const UA_DataType *type);
 static void nopDeleteMembers(void *p, const UA_DataType *type) { }
+
 static const UA_deleteMembersSignature deleteMembersJumpTable[UA_BUILTIN_TYPES_COUNT + 1] = {
     (UA_deleteMembersSignature)nopDeleteMembers, // Boolean
     (UA_deleteMembersSignature)nopDeleteMembers, // SByte
@@ -689,7 +694,7 @@ static const UA_deleteMembersSignature deleteMembersJumpTable[UA_BUILTIN_TYPES_C
     (UA_deleteMembersSignature)UA_deleteMembers, // LocalizedText
     (UA_deleteMembersSignature)ExtensionObject_deleteMembers,
     (UA_deleteMembersSignature)DataValue_deleteMembers,
-    (UA_deleteMembersSignature)variant_deleteMembers,
+    (UA_deleteMembersSignature)Variant_deletemembers,
     (UA_deleteMembersSignature)DiagnosticInfo_deleteMembers,
     (UA_deleteMembersSignature)UA_deleteMembers,
 };

+ 62 - 51
src/ua_types_encoding_binary.c

@@ -13,6 +13,10 @@ typedef UA_StatusCode (*UA_encodeBinarySignature)(const void *src, const UA_Data
 typedef UA_StatusCode (*UA_decodeBinarySignature) (const UA_ByteString *src, size_t *UA_RESTRICT offset,
                                                    void *dst, const UA_DataType*);
 
+static UA_StatusCode
+UA_decodeBinaryNoInit(const UA_ByteString *src, size_t *UA_RESTRICT offset,
+                      void *dst, const UA_DataType *type);
+
 /*****************/
 /* Integer Types */
 /*****************/
@@ -405,7 +409,7 @@ Array_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset,
 
     uintptr_t ptr = (uintptr_t)*dst;
     for(size_t i = 0; i < length; i++) {
-        UA_StatusCode retval = UA_decodeBinary(src, offset, (void*)ptr, type);
+        UA_StatusCode retval = UA_decodeBinaryNoInit(src, offset, (void*)ptr, type);
         if(retval != UA_STATUSCODE_GOOD) {
             UA_Array_delete(*dst, i, type);
             *dst = NULL;
@@ -441,10 +445,14 @@ String_encodeBinary(UA_String const *src, const UA_DataType *_,
     return retval;
 }
 
+static UA_INLINE UA_StatusCode
+ByteString_encodeBinary(UA_ByteString const *src, const UA_DataType *_,
+                        UA_ByteString *dst, size_t *UA_RESTRICT offset) {
+    return String_encodeBinary((const UA_String*)src, _, dst, offset); }
+
 static UA_StatusCode
 String_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_String *dst, const UA_DataType *_) {
-    UA_String_init(dst);
     UA_Int32 signed_length;
     UA_StatusCode retval = Int32_decodeBinary(src, offset, &signed_length, NULL);
     if(retval != UA_STATUSCODE_GOOD)
@@ -466,6 +474,11 @@ String_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
     return UA_STATUSCODE_GOOD;
 }
 
+static UA_INLINE UA_StatusCode
+ByteString_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
+                        UA_ByteString *dst, const UA_DataType *_) {
+    return String_decodeBinary(src, offset, (UA_ByteString*)dst, _); }
+
 /* Guid */
 static UA_StatusCode
 Guid_encodeBinary(UA_Guid const *src, const UA_DataType *_,
@@ -481,14 +494,12 @@ Guid_encodeBinary(UA_Guid const *src, const UA_DataType *_,
 static UA_StatusCode
 Guid_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                   UA_Guid *dst, const UA_DataType *_) {
-    // This could be done with a single memcpy (if the compiler does no fancy
-    // realigning of structs)
     UA_StatusCode retval = UInt32_decodeBinary(src, offset, &dst->data1, NULL);
     retval |= UInt16_decodeBinary(src, offset, &dst->data2, NULL);
     retval |= UInt16_decodeBinary(src, offset, &dst->data3, NULL);
     for(size_t i = 0; i < 8; i++)
         retval |= Byte_decodeBinary(src, offset, &dst->data4[i], NULL);
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         UA_Guid_deleteMembers(dst);
     return retval;
 }
@@ -532,7 +543,7 @@ NodeId_encodeBinary(UA_NodeId const *src, const UA_DataType *_,
         srcByte = UA_NODEIDTYPE_STRING;
         retval |= Byte_encodeBinary(&srcByte, NULL, dst, offset);
         retval |= UInt16_encodeBinary(&src->namespaceIndex, NULL, dst, offset);
-        retval |= UA_encodeBinary(&src->identifier.string, &UA_TYPES[UA_TYPES_STRING], dst, offset);
+        retval |= String_encodeBinary(&src->identifier.string, NULL, dst, offset);
         break;
     case UA_NODEIDTYPE_GUID:
         srcByte = UA_NODEIDTYPE_GUID;
@@ -544,7 +555,7 @@ NodeId_encodeBinary(UA_NodeId const *src, const UA_DataType *_,
         srcByte = UA_NODEIDTYPE_BYTESTRING;
         retval |= Byte_encodeBinary(&srcByte, NULL, dst, offset);
         retval |= UInt16_encodeBinary(&src->namespaceIndex, NULL, dst, offset);
-        retval |= UA_encodeBinary(&src->identifier.byteString, &UA_TYPES[UA_TYPES_BYTESTRING], dst, offset);
+        retval |= ByteString_encodeBinary(&src->identifier.byteString, NULL, dst, offset);
         break;
     default:
         return UA_STATUSCODE_BADINTERNALERROR;
@@ -555,13 +566,11 @@ NodeId_encodeBinary(UA_NodeId const *src, const UA_DataType *_,
 static UA_StatusCode
 NodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_NodeId *dst, const UA_DataType *_) {
-    UA_NodeId_init(dst);
     UA_Byte dstByte = 0, encodingByte = 0;
     UA_UInt16 dstUInt16 = 0;
     UA_StatusCode retval = Byte_decodeBinary(src, offset, &encodingByte, NULL);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
-
     switch (encodingByte) {
     case UA_NODEIDTYPE_NUMERIC_TWOBYTE:
         dst->identifierType = UA_NODEIDTYPE_NUMERIC;
@@ -584,7 +593,7 @@ NodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
     case UA_NODEIDTYPE_STRING:
         dst->identifierType = UA_NODEIDTYPE_STRING;
         retval |= UInt16_decodeBinary(src, offset, &dst->namespaceIndex, NULL);
-        retval |= UA_decodeBinary(src, offset, &dst->identifier.string, &UA_TYPES[UA_TYPES_STRING]);
+        retval |= String_decodeBinary(src, offset, &dst->identifier.string, NULL);
         break;
     case UA_NODEIDTYPE_GUID:
         dst->identifierType = UA_NODEIDTYPE_GUID;
@@ -594,14 +603,13 @@ NodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
     case UA_NODEIDTYPE_BYTESTRING:
         dst->identifierType = UA_NODEIDTYPE_BYTESTRING;
         retval |= UInt16_decodeBinary(src, offset, &dst->namespaceIndex, NULL);
-        retval |= UA_decodeBinary(src, offset, &dst->identifier.byteString, &UA_TYPES[UA_TYPES_BYTESTRING]);
+        retval |= ByteString_decodeBinary(src, offset, &dst->identifier.byteString, NULL);
         break;
     default:
-        UA_NodeId_init(dst);
         retval |= UA_STATUSCODE_BADINTERNALERROR; // the client sends an encodingByte we do not recognize
         break;
     }
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         UA_NodeId_deleteMembers(dst);
     return retval;
 }
@@ -616,7 +624,7 @@ ExpandedNodeId_encodeBinary(UA_ExpandedNodeId const *src, const UA_DataType *_,
     UA_UInt32 start = *offset;
     UA_StatusCode retval = NodeId_encodeBinary(&src->nodeId, NULL, dst, offset);
     if(src->namespaceUri.length > 0) {
-        retval |= UA_encodeBinary(&src->namespaceUri, &UA_TYPES[UA_TYPES_STRING], dst, offset);
+        retval |= String_encodeBinary(&src->namespaceUri, NULL, dst, offset);
         dst->data[start] |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG;
     }
     if(src->serverIndex > 0) {
@@ -629,7 +637,6 @@ ExpandedNodeId_encodeBinary(UA_ExpandedNodeId const *src, const UA_DataType *_,
 static UA_StatusCode
 ExpandedNodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                             UA_ExpandedNodeId *dst, const UA_DataType *_) {
-    UA_ExpandedNodeId_init(dst);
     if(*offset >= src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
     UA_Byte encodingByte = src->data[*offset];
@@ -638,11 +645,11 @@ ExpandedNodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset
     UA_StatusCode retval = NodeId_decodeBinary(src, offset, &dst->nodeId, NULL);
     if(encodingByte & UA_EXPANDEDNODEID_NAMESPACEURI_FLAG) {
         dst->nodeId.namespaceIndex = 0;
-        retval |= UA_decodeBinary(src, offset, &dst->namespaceUri, &UA_TYPES[UA_TYPES_STRING]);
+        retval |= String_decodeBinary(src, offset, &dst->namespaceUri, NULL);
     }
     if(encodingByte & UA_EXPANDEDNODEID_SERVERINDEX_FLAG)
         retval |= UInt32_decodeBinary(src, offset, &dst->serverIndex, NULL);
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         UA_ExpandedNodeId_deleteMembers(dst);
     return retval;
 }
@@ -661,23 +668,22 @@ LocalizedText_encodeBinary(UA_LocalizedText const *src, const UA_DataType *_,
         encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
     UA_StatusCode retval = Byte_encodeBinary(&encodingMask, NULL, dst, offset);
     if(encodingMask & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE)
-        retval |= UA_encodeBinary(&src->locale, &UA_TYPES[UA_TYPES_STRING], dst, offset);
+        retval |= String_encodeBinary(&src->locale, NULL, dst, offset);
     if(encodingMask & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT)
-        retval |= UA_encodeBinary(&src->text, &UA_TYPES[UA_TYPES_STRING], dst, offset);
+        retval |= String_encodeBinary(&src->text, NULL, dst, offset);
     return retval;
 }
 
 static UA_StatusCode
 LocalizedText_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                            UA_LocalizedText *dst, const UA_DataType *_) {
-    UA_LocalizedText_init(dst);
     UA_Byte encodingMask = 0;
     UA_StatusCode retval = Byte_decodeBinary(src, offset, &encodingMask, NULL);
     if(encodingMask & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE)
-        retval |= UA_decodeBinary(src, offset, &dst->locale, &UA_TYPES[UA_TYPES_STRING]);
+        retval |= String_decodeBinary(src, offset, &dst->locale, NULL);
     if(encodingMask & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT)
-        retval |= UA_decodeBinary(src, offset, &dst->text, &UA_TYPES[UA_TYPES_STRING]);
-    if(retval)
+        retval |= String_decodeBinary(src, offset, &dst->text, NULL);
+    if(retval != UA_STATUSCODE_GOOD)
         UA_LocalizedText_deleteMembers(dst);
     return retval;
 }
@@ -703,7 +709,7 @@ ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_
         retval |= UA_encodeBinary(src->content.decoded.data, src->content.decoded.type, dst, offset);
         UA_Int32 length = *offset - old_offset - 4;
         retval |= Int32_encodeBinary(&length, NULL, dst, &old_offset);
-    } else  {
+    } else {
         retval = NodeId_encodeBinary(&src->content.encoded.typeId, NULL, dst, offset);
         retval |= Byte_encodeBinary(&encoding, NULL, dst, offset);
         switch (src->encoding) {
@@ -711,7 +717,7 @@ ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_
             break;
         case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
         case UA_EXTENSIONOBJECT_ENCODED_XML:
-            retval |= UA_encodeBinary(&src->content.encoded.body, &UA_TYPES[UA_TYPES_BYTESTRING], dst, offset);
+            retval |= ByteString_encodeBinary(&src->content.encoded.body, NULL, dst, offset);
             break;
         default:
             return UA_STATUSCODE_BADINTERNALERROR;
@@ -733,9 +739,9 @@ static UA_StatusCode findDataType(const UA_NodeId *typeId, const UA_DataType **t
 static UA_StatusCode
 ExtensionObject_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                              UA_ExtensionObject *dst, const UA_DataType *_) {
-    UA_ExtensionObject_init(dst);
     UA_Byte encoding = 0;
     UA_NodeId typeId;
+    UA_NodeId_init(&typeId);
     UA_StatusCode retval = NodeId_decodeBinary(src, offset, &typeId, NULL);
     retval |= Byte_decodeBinary(src, offset, &encoding, NULL);
     if(typeId.namespaceIndex != 0 || typeId.identifierType != UA_NODEIDTYPE_NUMERIC)
@@ -752,7 +758,7 @@ ExtensionObject_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offse
     } else if(encoding == UA_EXTENSIONOBJECT_ENCODED_XML) {
         dst->encoding = encoding;
         dst->content.encoded.typeId = typeId;
-        retval = UA_decodeBinary(src, offset, &dst->content.encoded.body, &UA_TYPES[UA_TYPES_BYTESTRING]);
+        retval = ByteString_decodeBinary(src, offset, &dst->content.encoded.body, NULL);
     } else {
         /* try to decode the content */
         size_t oldoffset = *offset;
@@ -767,7 +773,7 @@ ExtensionObject_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offse
         if(type) {
             dst->content.decoded.data = UA_new(type);
             if(dst->content.decoded.data) {
-                retval = UA_decodeBinary(src, offset, dst->content.decoded.data, type);
+                retval = UA_decodeBinaryNoInit(src, offset, dst->content.decoded.data, type);
                 dst->content.decoded.type = type;
                 dst->encoding = UA_EXTENSIONOBJECT_DECODED;
             } else
@@ -777,7 +783,7 @@ ExtensionObject_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offse
                 retval = UA_STATUSCODE_BADDECODINGERROR;
         } else {
             *offset = oldoffset;
-            retval = UA_decodeBinary(src, offset, &dst->content.encoded.body, &UA_TYPES[UA_TYPES_BYTESTRING]);
+            retval = ByteString_decodeBinary(src, offset, &dst->content.encoded.body, NULL);
             dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
             dst->content.encoded.typeId = typeId;
         }
@@ -871,12 +877,10 @@ Variant_encodeBinary(UA_Variant const *src, const UA_DataType *_,
 static UA_StatusCode
 Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                      UA_Variant *dst, const UA_DataType *_) {
-    UA_Variant_init(dst);
     UA_Byte encodingByte;
     UA_StatusCode retval = Byte_decodeBinary(src, offset, &encodingByte, NULL);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
-
     UA_Boolean isArray = encodingByte & UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
     size_t typeIndex = (encodingByte & UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1;
     if(typeIndex > 24) /* must be builtin */
@@ -918,12 +922,15 @@ Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
         UA_NodeId_deleteMembers(&typeId);
 
         /* decode the type */
-        dst->data = UA_malloc(dst->type->memSize);
-        retval = UA_decodeBinary(src, offset, dst->data, dst->type);
-        if(retval != UA_STATUSCODE_GOOD) {
-            UA_free(dst->data);
-            dst->data = NULL;
-        }
+        dst->data = UA_calloc(1,dst->type->memSize);
+        if(dst->data) {
+            retval = UA_decodeBinaryNoInit(src, offset, dst->data, dst->type);
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_free(dst->data);
+                dst->data = NULL;
+            }
+        } else
+            retval = UA_STATUSCODE_BADOUTOFMEMORY;
     }
 
     /* array dimensions */
@@ -959,16 +966,15 @@ DataValue_encodeBinary(UA_DataValue const *src, const UA_DataType *_,
     return retval;
 }
 
-#define MAX_PICO_SECONDS 1000
+#define MAX_PICO_SECONDS 999
 static UA_StatusCode
 DataValue_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                        UA_DataValue *dst, const UA_DataType *_) {
-    UA_DataValue_init(dst);
     UA_StatusCode retval = Byte_decodeBinary(src, offset, (UA_Byte*) dst, NULL);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     if(dst->hasValue)
-        retval |= UA_decodeBinary(src, offset, &dst->value, &UA_TYPES[UA_TYPES_VARIANT]);
+        retval |= Variant_decodeBinary(src, offset, &dst->value, NULL);
     if(dst->hasStatus)
         retval |= StatusCode_decodeBinary(src, offset, &dst->status, NULL);
     if(dst->hasSourceTimestamp)
@@ -985,7 +991,7 @@ DataValue_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
         if(dst->serverPicoseconds > MAX_PICO_SECONDS)
             dst->serverPicoseconds = MAX_PICO_SECONDS;
     }
-    if(retval)
+    if(retval != UA_STATUSCODE_GOOD)
         UA_DataValue_deleteMembers(dst);
     return retval;
 }
@@ -1004,7 +1010,7 @@ DiagnosticInfo_encodeBinary(const UA_DiagnosticInfo *src, const UA_DataType *_,
     if(src->hasLocale)
         retval |= Int32_encodeBinary(&src->locale, NULL, dst, offset);
     if(src->hasAdditionalInfo)
-        retval |= UA_encodeBinary(&src->additionalInfo, &UA_TYPES[UA_TYPES_STRING], dst, offset);
+        retval |= String_encodeBinary(&src->additionalInfo, NULL, dst, offset);
     if(src->hasInnerStatusCode)
         retval |= StatusCode_encodeBinary(&src->innerStatusCode, NULL, dst, offset);
     if(src->hasInnerDiagnosticInfo)
@@ -1015,7 +1021,6 @@ DiagnosticInfo_encodeBinary(const UA_DiagnosticInfo *src, const UA_DataType *_,
 static UA_StatusCode
 DiagnosticInfo_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                             UA_DiagnosticInfo *dst, const UA_DataType *_) {
-    UA_DiagnosticInfo_init(dst);
     UA_StatusCode retval = Byte_decodeBinary(src, offset, (UA_Byte*) dst, NULL);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
@@ -1028,17 +1033,17 @@ DiagnosticInfo_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset
     if(dst->hasLocale)
         retval |= Int32_decodeBinary(src, offset, &dst->locale, NULL);
     if(dst->hasAdditionalInfo)
-        retval |= UA_decodeBinary(src, offset, &dst->additionalInfo, &UA_TYPES[UA_TYPES_STRING]);
+        retval |= String_decodeBinary(src, offset, &dst->additionalInfo, NULL);
     if(dst->hasInnerStatusCode)
         retval |= StatusCode_decodeBinary(src, offset, &dst->innerStatusCode, NULL);
     if(dst->hasInnerDiagnosticInfo) {
         // innerDiagnosticInfo is a pointer to struct, therefore allocate
-        dst->innerDiagnosticInfo = UA_malloc(sizeof(UA_DiagnosticInfo));
+        dst->innerDiagnosticInfo = UA_calloc(1, sizeof(UA_DiagnosticInfo));
         if(dst->innerDiagnosticInfo) {
-            if(DiagnosticInfo_decodeBinary(src, offset, dst->innerDiagnosticInfo, NULL) != UA_STATUSCODE_GOOD) {
+            retval |= DiagnosticInfo_decodeBinary(src, offset, dst->innerDiagnosticInfo, NULL);
+            if(retval != UA_STATUSCODE_GOOD) {
                 UA_free(dst->innerDiagnosticInfo);
                 dst->innerDiagnosticInfo = NULL;
-                retval |= UA_STATUSCODE_BADINTERNALERROR;
             }
         } else
             retval |= UA_STATUSCODE_BADOUTOFMEMORY;
@@ -1125,17 +1130,17 @@ static const UA_decodeBinarySignature decodeBinaryJumpTable[UA_BUILTIN_TYPES_COU
     (UA_decodeBinarySignature)NodeId_decodeBinary,
     (UA_decodeBinarySignature)ExpandedNodeId_decodeBinary,
     (UA_decodeBinarySignature)UInt32_decodeBinary, // StatusCode
-    (UA_decodeBinarySignature)UA_decodeBinary, // QualifiedName
+    (UA_decodeBinarySignature)UA_decodeBinaryNoInit, // QualifiedName
     (UA_decodeBinarySignature)LocalizedText_decodeBinary,
     (UA_decodeBinarySignature)ExtensionObject_decodeBinary,
     (UA_decodeBinarySignature)DataValue_decodeBinary,
     (UA_decodeBinarySignature)Variant_decodeBinary,
     (UA_decodeBinarySignature)DiagnosticInfo_decodeBinary,
-    (UA_decodeBinarySignature)UA_decodeBinary,
+    (UA_decodeBinarySignature)UA_decodeBinaryNoInit,
 };
 
-UA_StatusCode
-UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset, void *dst, const UA_DataType *type) {
+static UA_StatusCode
+UA_decodeBinaryNoInit(const UA_ByteString *src, size_t *UA_RESTRICT offset, void *dst, const UA_DataType *type) {
     uintptr_t ptr = (uintptr_t)dst;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Byte membersSize = type->membersSize;
@@ -1162,3 +1167,9 @@ UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset, void *dst,
         UA_deleteMembers(dst, type);
     return retval;
 }
+
+UA_StatusCode
+UA_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset, void *dst, const UA_DataType *type) {
+    memset(dst, 0, type->memSize); // init
+    return UA_decodeBinaryNoInit(src, offset, dst, type);
+}

+ 42 - 5
tests/check_services_attributes.c

@@ -24,17 +24,33 @@ static UA_Server* makeTestSequence(void) {
     UA_VariableAttributes vattr;
     UA_VariableAttributes_init(&vattr);
     UA_Int32 myInteger = 42;
-    UA_Variant_setScalarCopy(&vattr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
+    UA_Variant_setScalar(&vattr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
     vattr.description = UA_LOCALIZEDTEXT("locale","the answer");
     vattr.displayName = UA_LOCALIZEDTEXT("locale","the answer");
     vattr.valueRank = -2;
-    const UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "the answer");
-    const UA_NodeId myIntegerNodeId = UA_NODEID_STRING(1, "the.answer");
+    UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, "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, myIntegerNodeId, parentNodeId,
                               parentReferenceNodeId, myIntegerName,
                               UA_NODEID_NULL, vattr, NULL);
+    
+    /* VariableNode with array */
+    UA_VariableAttributes_init(&vattr);
+    UA_Int32 myIntegerArray[9] = {1,2,3,4,5,6,7,8,9};
+    UA_Variant_setArray(&vattr.value, &myIntegerArray, 9, &UA_TYPES[UA_TYPES_INT32]);
+    UA_UInt32 myIntegerDimensions[2] = {3,3};
+    vattr.value.arrayDimensions = myIntegerDimensions;
+    vattr.value.arrayDimensionsSize = 2;
+    vattr.displayName = UA_LOCALIZEDTEXT("locale","myarray");
+    myIntegerName = UA_QUALIFIEDNAME(1, "myarray");
+    myIntegerNodeId = UA_NODEID_STRING(1, "myarray");
+    parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
+    parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
+    UA_Server_addVariableNode(server, myIntegerNodeId, parentNodeId,
+                              parentReferenceNodeId, myIntegerName,
+                              UA_NODEID_NULL, vattr, NULL);
 
     /* ObjectNode */
     UA_ObjectAttributes obj_attr;
@@ -114,6 +130,25 @@ START_TEST(ReadSingleAttributeValueWithoutTimestamp) {
     UA_DataValue_deleteMembers(&resp);
 } END_TEST
 
+START_TEST(ReadSingleAttributeValueRangeWithoutTimestamp) {
+    UA_Server *server = makeTestSequence();
+    UA_DataValue resp;
+    UA_DataValue_init(&resp);
+    UA_ReadRequest rReq;
+    UA_ReadRequest_init(&rReq);
+    rReq.nodesToRead = UA_ReadValueId_new();
+    rReq.nodesToReadSize = 1;
+    rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "myarray");
+    rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_VALUE;
+    rReq.nodesToRead[0].indexRange = UA_STRING_ALLOC("2:3,1:2");
+    Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
+    ck_assert_int_eq(4, resp.value.arrayLength);
+    ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
+    UA_Server_delete(server);
+    UA_ReadRequest_deleteMembers(&rReq);
+    UA_DataValue_deleteMembers(&resp);
+} END_TEST
+
 START_TEST(ReadSingleAttributeNodeIdWithoutTimestamp) {
     UA_Server *server = makeTestSequence();
     UA_DataValue resp;
@@ -452,14 +487,15 @@ START_TEST(ReadSingleAttributeUserAccessLevelWithoutTimestamp) {
     rReq.nodesToRead[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
     rReq.nodesToRead[0].attributeId = UA_ATTRIBUTEID_USERACCESSLEVEL;
     Service_Read_single(server, &adminSession, UA_TIMESTAMPSTORETURN_NEITHER, &rReq.nodesToRead[0], &resp);
-    UA_VariableNode* compNode = makeCompareSequence();
+    const UA_VariableNode* compNode =
+        (const UA_VariableNode*)UA_NodeStore_get(server->nodestore, &rReq.nodesToRead[0].nodeId);
     ck_assert_int_eq(0, resp.value.arrayLength);
     ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_BYTE], resp.value.type);
     ck_assert_int_eq(*(UA_Byte*)resp.value.data, compNode->userAccessLevel);
+    UA_NodeStore_release((const UA_Node*)compNode);
     UA_Server_delete(server);
     UA_DataValue_deleteMembers(&resp);
     UA_ReadRequest_deleteMembers(&rReq);
-    UA_VariableNode_delete(compNode);
 } END_TEST
 
 START_TEST(ReadSingleAttributeMinimumSamplingIntervalWithoutTimestamp) {
@@ -895,6 +931,7 @@ static Suite * testSuite_services_attributes(void) {
 
 	TCase *tc_readSingleAttributes = tcase_create("readSingleAttributes");
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeValueWithoutTimestamp);
+	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeValueRangeWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeNodeIdWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeNodeClassWithoutTimestamp);
 	tcase_add_test(tc_readSingleAttributes, ReadSingleAttributeBrowseNameWithoutTimestamp);