Browse Source

Merge branch 'unsigned_array_size' into simple_nodestore

Julius Pfrommer 9 years ago
parent
commit
1740e4d8eb

+ 10 - 10
examples/client.c

@@ -14,8 +14,7 @@
 
 #include <stdio.h>
 
-void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value);
-void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value) {
+static void handler_TheAnswerChanged(UA_UInt32 handle, UA_DataValue *value) {
     printf("The Answer has changed!\n");
     return;
 }
@@ -42,18 +41,19 @@ int main(int argc, char *argv[]) {
 
     UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
     printf("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
-    for (int i = 0; i < bResp.resultsSize; ++i) {
-        for (int j = 0; j < bResp.results[i].referencesSize; ++j) {
+    for (size_t i = 0; i < bResp.resultsSize; ++i) {
+        for (size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
             UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
             if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC) {
                 printf("%-9d %-16d %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
-                       ref->nodeId.nodeId.identifier.numeric, ref->browseName.name.length,
-                       ref->browseName.name.data, ref->displayName.text.length, ref->displayName.text.data);
+                       ref->nodeId.nodeId.identifier.numeric, (int)ref->browseName.name.length,
+                       ref->browseName.name.data, (int)ref->displayName.text.length,
+                       ref->displayName.text.data);
             } else if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_STRING) {
                 printf("%-9d %-16.*s %-16.*s %-16.*s\n", ref->browseName.namespaceIndex,
-                       ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data,
-                       ref->browseName.name.length, ref->browseName.name.data, ref->displayName.text.length,
-                       ref->displayName.text.data);
+                       (int)ref->nodeId.nodeId.identifier.string.length, ref->nodeId.nodeId.identifier.string.data,
+                       (int)ref->browseName.name.length, ref->browseName.name.data,
+                       (int)ref->displayName.text.length, ref->displayName.text.data);
             }
             //TODO: distinguish further types
         }
@@ -149,7 +149,7 @@ int main(int argc, char *argv[]) {
                             UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
     if(retval == UA_STATUSCODE_GOOD) {
         printf("Method call was successfull, and %i returned values available.\n", outputSize);
-        UA_Array_delete(output, &UA_TYPES[UA_TYPES_VARIANT], outputSize);
+        UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
     } else {
         printf("Method call was unsuccessfull, and %x returned values available.\n", retval);
     }

+ 1 - 1
examples/server_method.c

@@ -38,7 +38,7 @@ static UA_StatusCode
 IncInt32ArrayValuesMethod(const UA_NodeId objectId, const UA_Variant *input,
                           UA_Variant *output, void *handle) {
 	UA_Variant_setArrayCopy(output, input->data, 5, &UA_TYPES[UA_TYPES_INT32]);
-	for(int i = 0; i< input->arrayLength; i++)
+	for(size_t i = 0; i< input->arrayLength; i++)
 		((UA_Int32*)output->data)[i] = ((UA_Int32*)input->data)[i] + 1;
 	return UA_STATUSCODE_GOOD;
 }

+ 1 - 0
src/client/ua_client_highlevel.c

@@ -2,6 +2,7 @@
 #include "ua_nodeids.h"
 #include "ua_client_highlevel.h"
 #include "ua_types_encoding_binary.h"
+#include "ua_util.h"
 
 UA_StatusCode UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri, UA_UInt16 *namespaceIndex){
 	UA_ReadRequest ReadRequest;

+ 33 - 40
src/client/ua_client_highlevel_subscriptions.c

@@ -197,16 +197,15 @@ UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
     // Check if the server has acknowledged any of our ACKS
     // Note that a list of serverside status codes may be send without valid publish data, i.e. 
     // during keepalives or no data availability
-    UA_Client_NotificationsAckNumber *tmpAck = client->pendingNotificationsAcks.lh_first;
-    UA_Client_NotificationsAckNumber *nxtAck = tmpAck;
-    for(int i=0; i<response.resultsSize && nxtAck != NULL; i++) {
-        tmpAck = nxtAck;
-        nxtAck = tmpAck->listEntry.le_next;
+    UA_Client_NotificationsAckNumber *ack, *tmpAck;
+    size_t i = 0;
+    LIST_FOREACH_SAFE(ack, &client->pendingNotificationsAcks, listEntry, tmpAck) {
         if(response.results[i] == UA_STATUSCODE_GOOD ||
-            response.results[i] == UA_STATUSCODE_BADSEQUENCENUMBERINVALID) {
-            LIST_REMOVE(tmpAck, listEntry);
-            UA_free(tmpAck);
+           response.results[i] == UA_STATUSCODE_BADSEQUENCENUMBERINVALID) {
+            LIST_REMOVE(ack, listEntry);
+            UA_free(ack);
         }
+        i++;
     }
     
     if(response.subscriptionId == 0)
@@ -221,44 +220,38 @@ UA_Client_processPublishRx(UA_Client *client, UA_PublishResponse response) {
         return UA_FALSE;
     
     UA_NotificationMessage msg = response.notificationMessage;
-    UA_DataChangeNotification dataChangeNotification;
-    UA_StatusCode retval = UA_STATUSCODE_GOOD;
     UA_Client_MonitoredItem *mon;
-    size_t decodingOffset = 0;
-    for(int k = 0; k < msg.notificationDataSize; k++) {
-        if(msg.notificationData[k].encoding == UA_EXTENSIONOBJECT_ENCODINGMASK_BODYISBYTESTRING) {
-            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
-                msg.notificationData[k].typeId.identifier.numeric == 811 ) {
-                // This is a dataChangeNotification
-                retval |= UA_DataChangeNotification_decodeBinary(&msg.notificationData[k].body,
-                                                                 &decodingOffset, &dataChangeNotification);
-                UA_MonitoredItemNotification *mitemNot;
-                for(int i = 0; i < dataChangeNotification.monitoredItemsSize; i++) {
-                    mitemNot = &dataChangeNotification.monitoredItems[i];
-                    // find this client handle
-                    LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
-                        if(mon->ClientHandle == mitemNot->clientHandle) {
-                            mon->handler(mitemNot->clientHandle, &mitemNot->value);
-                            break;
-                        }
+    for(size_t k = 0; k < msg.notificationDataSize; k++) {
+        if(msg.notificationData[k].encoding != UA_EXTENSIONOBJECT_DECODED)
+            continue;
+        
+        if(msg.notificationData[k].content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
+            // This is a dataChangeNotification
+            UA_DataChangeNotification *dataChangeNotification = msg.notificationData[k].content.decoded.data;
+            for(size_t i = 0; i < dataChangeNotification->monitoredItemsSize; i++) {
+            UA_MonitoredItemNotification *mitemNot = &dataChangeNotification->monitoredItems[i];
+                // find this client handle
+                LIST_FOREACH(mon, &sub->MonitoredItems, listEntry) {
+                    if(mon->ClientHandle == mitemNot->clientHandle) {
+                        mon->handler(mitemNot->clientHandle, &mitemNot->value);
+                        break;
                     }
                 }
-                UA_DataChangeNotification_deleteMembers(&dataChangeNotification);
-                continue;
             }
+            continue;
+        }
 
-            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
-               msg.notificationData[k].typeId.identifier.numeric == 820 ) {
-                //FIXME: This is a statusChangeNotification (not supported yet)
-                continue;
-            }
+        /* if(msg.notificationData[k].typeId.namespaceIndex == 0 && */
+        /*    msg.notificationData[k].typeId.identifier.numeric == 820 ) { */
+        /*     //FIXME: This is a statusChangeNotification (not supported yet) */
+        /*     continue; */
+        /* } */
 
-            if(msg.notificationData[k].typeId.namespaceIndex == 0 &&
-               msg.notificationData[k].typeId.identifier.numeric == 916 ) {
-                //FIXME: This is an EventNotification
-                continue;
-            }
-        }
+        /* if(msg.notificationData[k].typeId.namespaceIndex == 0 && */
+        /*    msg.notificationData[k].typeId.identifier.numeric == 916 ) { */
+        /*     //FIXME: This is an EventNotification */
+        /*     continue; */
+        /* } */
     }
     
     /* We processed this message, add it to the list of pending acks (but make

+ 41 - 55
src/server/ua_services_call.c

@@ -5,16 +5,15 @@
 #include "ua_nodestore.h"
 #include "ua_nodes.h"
 
-static const UA_VariableNode
-*getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
-                          UA_String withBrowseName) {
-    const UA_Node *refTarget;
+static const UA_VariableNode *
+getArgumentsVariableNode(UA_Server *server, const UA_MethodNode *ofMethod,
+                         UA_String withBrowseName) {
     UA_NodeId hasProperty = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
-    
-    for(UA_Int32 i = 0; i < ofMethod->referencesSize; i++) {
+    for(size_t i = 0; i < ofMethod->referencesSize; i++) {
         if(ofMethod->references[i].isInverse == UA_FALSE && 
             UA_NodeId_equal(&hasProperty, &ofMethod->references[i].referenceTypeId)) {
-            refTarget = UA_NodeStore_get(server->nodestore, &ofMethod->references[i].targetId.nodeId);
+            const UA_Node *refTarget =
+                UA_NodeStore_get(server->nodestore, &ofMethod->references[i].targetId.nodeId);
             if(!refTarget)
                 continue;
             if(refTarget->nodeClass == UA_NODECLASS_VARIABLE && 
@@ -29,16 +28,16 @@ static const UA_VariableNode
 }
 
 static UA_StatusCode
-statisfySignature(UA_Variant *var, UA_Argument arg) {
-    if(!UA_NodeId_equal(&var->type->typeId, &arg.dataType) )
+satisfySignature(const UA_Variant *var, const UA_Argument *arg) {
+    if(!UA_NodeId_equal(&var->type->typeId, &arg->dataType) )
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     
     // Note: The namespace compiler will compile nodes with their actual array dimensions, never -1
-    if(arg.arrayDimensionsSize > 0 && var->arrayDimensionsSize > 0)
-        if(var->arrayDimensionsSize != arg.arrayDimensionsSize) 
+    if(arg->arrayDimensionsSize > 0 && var->arrayDimensionsSize > 0)
+        if(var->arrayDimensionsSize != arg->arrayDimensionsSize) 
             return UA_STATUSCODE_BADINVALIDARGUMENT;
         
-        // Continue with jpfr's statisfySignature from here on
+        // Continue with jpfr's satisfySignature from here on
         /* ValueRank Semantics
          *  n >= 1: the value is an array with the specified number of dimens*ions.
          *  n = 0: the value is an array with one or more dimensions.
@@ -46,27 +45,27 @@ statisfySignature(UA_Variant *var, UA_Argument arg) {
          *  n = -2: the value can be a scalar or an array with any number of dimensions.
          *  n = -3:  the value can be a scalar or a one dimensional array. */
         UA_Boolean scalar = UA_Variant_isScalar(var);
-        if(arg.valueRank == 0 && scalar)
+        if(arg->valueRank == 0 && scalar)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-        if(arg.valueRank == -1 && !scalar)
+        if(arg->valueRank == -1 && !scalar)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-        if(arg.valueRank == -3 && var->arrayDimensionsSize > 1)
+        if(arg->valueRank == -3 && var->arrayDimensionsSize > 1)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-        if(arg.valueRank > 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
+        if(arg->valueRank > 1 && var->arrayDimensionsSize != arg->arrayDimensionsSize)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
         
         //variants do not always encode the dimension flag (e.g. 1d array)
-       if(!var->arrayDimensions && arg.arrayDimensionsSize == 1 &&
-          arg.arrayDimensions[0] == var->arrayLength) {
+       if(!var->arrayDimensions && arg->arrayDimensionsSize == 1 &&
+          arg->arrayDimensions[0] == var->arrayLength) {
     	   return UA_STATUSCODE_GOOD;
        } else {
-         if(arg.valueRank >= 1 && var->arrayDimensionsSize != arg.arrayDimensionsSize)
+         if(arg->valueRank >= 1 && var->arrayDimensionsSize != arg->arrayDimensionsSize)
             return UA_STATUSCODE_BADINVALIDARGUMENT;
-         if(arg.arrayDimensionsSize >= 1) {
-            if(arg.arrayDimensionsSize != var->arrayDimensionsSize)
+         if(arg->arrayDimensionsSize >= 1) {
+            if(arg->arrayDimensionsSize != var->arrayDimensionsSize)
                 return UA_STATUSCODE_BADINVALIDARGUMENT;
-            for(size_t i = 0; i < arg.arrayDimensionsSize; i++) {
-                if(arg.arrayDimensions[i] != var->arrayDimensions[i])
+            for(size_t i = 0; i < arg->arrayDimensionsSize; i++) {
+                if(arg->arrayDimensions[i] != var->arrayDimensions[i])
                     return UA_STATUSCODE_BADINVALIDARGUMENT;
             }
          }
@@ -86,25 +85,14 @@ argConformsToDefinition(UA_CallMethodRequest *rs, const UA_VariableNode *argDefi
        rs->inputArgumentsSize > argDefinition->value.variant.value.arrayLength)
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     
-    const UA_ExtensionObject *thisArgDefExtObj;
-    UA_Variant *var;
-    UA_Argument arg;
-    size_t decodingOffset = 0;
+    if(argDefinition->value.variant.value.type != &UA_TYPES[UA_TYPES_ARGUMENT])
+        return UA_STATUSCODE_BADINTERNALERROR;
+
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    UA_NodeId ArgumentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ARGUMENT + UA_ENCODINGOFFSET_BINARY);
-    for(int i = 0; i<rs->inputArgumentsSize; i++) {
-        var = &rs->inputArguments[i];
-        if(argDefinition->value.variant.value.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) {
-            thisArgDefExtObj = &((const UA_ExtensionObject *) (argDefinition->value.variant.value.data))[i];
-            decodingOffset = 0;
-            
-            if(!UA_NodeId_equal(&ArgumentNodeId, &thisArgDefExtObj->typeId))
-                return UA_STATUSCODE_BADINTERNALERROR;
-                
-            retval |= UA_decodeBinary(&thisArgDefExtObj->body, &decodingOffset, &arg, &UA_TYPES[UA_TYPES_ARGUMENT]);
-        } else if(argDefinition->value.variant.value.type == &UA_TYPES[UA_TYPES_ARGUMENT])
-            arg = ((UA_Argument *) argDefinition->value.variant.value.data)[i];
-        retval |= statisfySignature(var, arg);
+    for(size_t i = 0; i < argDefinition->value.variant.value.arrayLength; i++) {
+        UA_Variant *var = &rs->inputArguments[i];
+        UA_Argument *arg = &((UA_Argument*)argDefinition->value.variant.value.data)[i];
+        retval |= satisfySignature(var, arg);
     }
     return retval;
 }
@@ -138,7 +126,7 @@ callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request
     // Object must have a hasComponent reference (or any inherited referenceType from sayd reference) 
     // to be valid for a methodCall...
     result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
-    for(UA_Int32 i = 0; i < withObject->referencesSize; i++) {
+    for(size_t i = 0; i < withObject->referencesSize; i++) {
         if(withObject->references[i].referenceTypeId.identifier.numeric == UA_NS0ID_HASCOMPONENT) {
             // FIXME: Not checking any subtypes of HasComponent at the moment
             if(UA_NodeId_equal(&withObject->references[i].targetId.nodeId, &methodCalled->nodeId)) {
@@ -157,32 +145,30 @@ callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request
     }
 
     /* Verify Input Argument count, types and sizes */
-    const UA_VariableNode *inputArguments = getArgumentsVariableNode(server, methodCalled,
-                                                                     UA_STRING("InputArguments"));
+    const UA_VariableNode *inputArguments =
+        getArgumentsVariableNode(server, methodCalled, UA_STRING("InputArguments"));
     if(inputArguments) {
-        // Expects arguments
         result->statusCode = argConformsToDefinition(request, inputArguments);
         UA_NodeStore_release((const UA_Node*)inputArguments);
         if(result->statusCode != UA_STATUSCODE_GOOD)
             goto releaseBothReturn;
     } else if(request->inputArgumentsSize > 0) {
-        // Expects no arguments, but got some
         result->statusCode = UA_STATUSCODE_BADINVALIDARGUMENT;
         goto releaseBothReturn;
     }
 
-    const UA_VariableNode *outputArguments = getArgumentsVariableNode(server, methodCalled,
-                                                                      UA_STRING("OutputArguments"));
+    const UA_VariableNode *outputArguments =
+        getArgumentsVariableNode(server, methodCalled, UA_STRING("OutputArguments"));
     if(!outputArguments) {
         // A MethodNode must have an OutputArguments variable (which may be empty)
         result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
         goto releaseBothReturn;
     }
     
-    // Call method if available
+    /* Call method if available */
     if(methodCalled->attachedMethod) {
-        result->outputArguments = UA_Array_new(&UA_TYPES[UA_TYPES_VARIANT],
-                                               outputArguments->value.variant.value.arrayLength);
+        result->outputArguments = UA_Array_new(outputArguments->value.variant.value.arrayLength,
+                                               &UA_TYPES[UA_TYPES_VARIANT]);
         result->outputArgumentsSize = outputArguments->value.variant.value.arrayLength;
         result->statusCode = methodCalled->attachedMethod(withObject->nodeId, request->inputArguments,
                                                           result->outputArguments, methodCalled->methodHandle);
@@ -190,7 +176,7 @@ callMethod(UA_Server *server, UA_Session *session, UA_CallMethodRequest *request
     else
         result->statusCode = UA_STATUSCODE_BADNOTWRITABLE; // There is no NOTEXECUTABLE?
     
-    /* FIXME: Verify Output Argument count, types and sizes */
+    /* TODO: Verify Output Argument count, types and sizes */
     if(outputArguments)
         UA_NodeStore_release((const UA_Node*)outputArguments);
 
@@ -207,14 +193,14 @@ void Service_Call(UA_Server *server, UA_Session *session, const UA_CallRequest *
         return;
     }
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_CALLMETHODRESULT],
-                                     request->methodsToCallSize);
+    response->results = UA_Array_new(request->methodsToCallSize,
+                                     &UA_TYPES[UA_TYPES_CALLMETHODRESULT]);
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
     response->resultsSize = request->methodsToCallSize;
     
-    for(UA_Int32 i = 0; i < request->methodsToCallSize;i++)
+    for(size_t i = 0; i < request->methodsToCallSize;i++)
         callMethod(server, session, &request->methodsToCall[i], &response->results[i]);
 }

+ 57 - 49
src/server/ua_services_session.c

@@ -46,30 +46,27 @@ void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
                              const UA_ActivateSessionRequest *request,
                              UA_ActivateSessionResponse *response) {
     // make the channel know about the session
-	UA_Session *foundSession =
-        UA_SessionManager_getSession(&server->sessionManager,
-                                     (const UA_NodeId*)&request->requestHeader.authenticationToken);
+	UA_Session *foundSession = UA_SessionManager_getSession(&server->sessionManager,
+                                                            &request->requestHeader.authenticationToken);
 
-	if(foundSession == NULL) {
+	if(!foundSession) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
                      "Processing ActivateSessionRequest on SecureChannel %i, but no session found for the authentication token",
                      channel->securityToken.channelId);
         return;
-	} else if(foundSession->validTill < UA_DateTime_now()) {
+	}
+
+    if(foundSession->validTill < UA_DateTime_now()) {
         UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
                      "Processing ActivateSessionRequest on SecureChannel %i, but the session has timed out",
                      channel->securityToken.channelId);
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
         return;
 	}
-    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
-                 "Processing ActivateSessionRequest on SecureChannel %i for Session (ns=%i,i=%i)",
-                 channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
-                 foundSession->sessionId.identifier.numeric);
 
     if(request->userIdentityToken.encoding < UA_EXTENSIONOBJECT_DECODED ||
-       (request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERIDENTITYTOKEN] &&
+       (request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] &&
         request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])) {
         UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
                      "Invalided UserIdentityToken on SecureChannel %i for Session (ns=%i,i=%i)",
@@ -78,62 +75,73 @@ void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
         response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
         return;
     }
-    const UA_UserIdentityToken token = *(const UA_UserIdentityToken*)request->userIdentityToken.content.decoded.data;
+
+    UA_LOG_DEBUG(server->logger, UA_LOGCATEGORY_SESSION,
+                 "Processing ActivateSessionRequest on SecureChannel %i for Session (ns=%i,i=%i)",
+                 channel->securityToken.channelId, foundSession->sessionId.namespaceIndex,
+                 foundSession->sessionId.identifier.numeric);
 
     UA_String ap = UA_STRING(ANONYMOUS_POLICY);
     UA_String up = UA_STRING(USERNAME_POLICY);
-    //(Compatibility notice)
-    //Siemens OPC Scout v10 provides an empty policyId, this is not okay
-    //For compatibility we will assume that empty policyId == ANONYMOUS_POLICY
-    //if(token.policyId.data == NULL) {
-    //    /* 1) no policy defined */
-    //    response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-    //} else
-    //(End Compatibility notice)
-    if(server->config.Login_enableAnonymous && (token.policyId.data == NULL || UA_String_equal(&token.policyId, &ap))) {
-        /* 2) anonymous logins */
+
+    /* Compatibility notice: Siemens OPC Scout v10 provides an empty policyId,
+       this is not okay For compatibility we will assume that empty policyId ==
+       ANONYMOUS_POLICY
+       if(token.policyId->data == NULL)
+           response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+    */
+
+    /* anonymous login */
+    if(server->config.Login_enableAnonymous &&
+       request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
+        const UA_AnonymousIdentityToken *token = request->userIdentityToken.content.decoded.data;
+        if(token->policyId.data && !UA_String_equal(&token->policyId, &ap)) {
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+            return;
+        }
         if(foundSession->channel && foundSession->channel != channel)
             UA_SecureChannel_detachSession(foundSession->channel, foundSession);
         UA_SecureChannel_attachSession(channel, foundSession);
         foundSession->activated = UA_TRUE;
         UA_Session_updateLifetime(foundSession);
-    } else if(server->config.Login_enableUsernamePassword && UA_String_equal(&token.policyId, &up) &&
-              request->userIdentityToken.content.decoded.type != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
-        /* 3) username logins */
-        const UA_UserNameIdentityToken username_token =
-            *(const UA_UserNameIdentityToken*)request->userIdentityToken.content.decoded.data;
+        return;
+    }
 
-        if(username_token.encryptionAlgorithm.data != NULL) {
-            /* 3.1) we only support encryption */
+    /* username login */
+    if(server->config.Login_enableUsernamePassword &&
+       request->userIdentityToken.content.decoded.type == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
+        const UA_UserNameIdentityToken *token = request->userIdentityToken.content.decoded.data;
+        if(!UA_String_equal(&token->policyId, &up)) {
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
-        } else  if(username_token.userName.data == NULL && username_token.password.data == NULL){
-            /* 3.2) empty username and password */
+            return;
+        }
+        if(token->encryptionAlgorithm.data) {
+            /* we don't support encryption */
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+        } else  if(!token->userName.data && !token->password.data) {
+            /* empty username and password */
             response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
         } else {
-            /* 3.3) ok, trying to match the username */
-            size_t i = 0;
-            for(; i < server->config.Login_loginsCount; ++i) {
+            /* ok, trying to match the username */
+            for(size_t i = 0; i < server->config.Login_loginsCount; ++i) {
                 UA_String user = UA_STRING(server->config.Login_usernames[i]);
                 UA_String pw = UA_STRING(server->config.Login_passwords[i]);
-                if(UA_String_equal(&username_token.userName, &user) &&
-                   UA_String_equal(&username_token.password, &pw)) {
-                    /* success - activate */
-                    if(foundSession->channel && foundSession->channel != channel)
-                        UA_SecureChannel_detachSession(foundSession->channel, foundSession);
-                    UA_SecureChannel_attachSession(channel, foundSession);
-                    foundSession->activated = UA_TRUE;
-                    UA_Session_updateLifetime(foundSession);
-                    break;
-                }
+                if(!UA_String_equal(&token->userName, &user) || !UA_String_equal(&token->password, &pw))
+                    continue;
+                /* success - activate */
+                if(foundSession->channel && foundSession->channel != channel)
+                    UA_SecureChannel_detachSession(foundSession->channel, foundSession);
+                UA_SecureChannel_attachSession(channel, foundSession);
+                foundSession->activated = UA_TRUE;
+                UA_Session_updateLifetime(foundSession);
+                return;
             }
-            /* no username/pass matched */
-            if(i >= server->config.Login_loginsCount)
-                response->responseHeader.serviceResult = UA_STATUSCODE_BADUSERACCESSDENIED;
+            /* no match */
+            response->responseHeader.serviceResult = UA_STATUSCODE_BADUSERACCESSDENIED;
         }
-    } else {
-        response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
+        return;
     }
-    return;
+    response->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
 }
 
 void Service_CloseSession(UA_Server *server, UA_Session *session, const UA_CloseSessionRequest *request,

+ 11 - 9
src/server/ua_services_subscription.c

@@ -119,14 +119,14 @@ void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
         return;
     }
 
-    response->results = UA_Array_new(&UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], request->itemsToCreateSize);
+    response->results = UA_Array_new(request->itemsToCreateSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]);
     if(!response->results) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
         return;
     }
     response->resultsSize = request->itemsToCreateSize;
 
-    for(UA_Int32 i = 0; i<request->itemsToCreateSize; i++)
+    for(size_t i = 0; i < request->itemsToCreateSize; i++)
         createMonitoredItems(server, session, sub, &request->itemsToCreate[i], &response->results[i]);
 }
 
@@ -139,7 +139,7 @@ void Service_Publish(UA_Server *server, UA_Session *session, const UA_PublishReq
     // Delete Acknowledged Subscription Messages
     response->resultsSize = request->subscriptionAcknowledgementsSize;
     response->results     = UA_malloc(sizeof(UA_StatusCode)*(response->resultsSize));
-    for(UA_Int32 i = 0; i < request->subscriptionAcknowledgementsSize; i++) {
+    for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; i++) {
         response->results[i] = UA_STATUSCODE_GOOD;
         UA_Subscription *sub =
             SubscriptionManager_getSubscriptionByID(&session->subscriptionManager,
@@ -248,9 +248,10 @@ void Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
     }
     response->resultsSize = request->subscriptionIdsSize;
 
-    for(UA_Int32 i = 0; i < request->subscriptionIdsSize; i++)
-        response->results[i] = SubscriptionManager_deleteSubscription(server, &session->subscriptionManager,
-                                                                      request->subscriptionIds[i]);
+    for(size_t i = 0; i < request->subscriptionIdsSize; i++)
+        response->results[i] =
+            SubscriptionManager_deleteSubscription(server, &session->subscriptionManager,
+                                                   request->subscriptionIds[i]);
 } 
 
 void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
@@ -270,7 +271,8 @@ void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
     }
     response->resultsSize = request->monitoredItemIdsSize;
 
-    for(UA_Int32 i = 0; i < request->monitoredItemIdsSize; i++)
-        response->results[i] = SubscriptionManager_deleteMonitoredItem(manager, sub->subscriptionID,
-                                                                       request->monitoredItemIds[i]);
+    for(size_t i = 0; i < request->monitoredItemIdsSize; i++)
+        response->results[i] =
+            SubscriptionManager_deleteMonitoredItem(manager, sub->subscriptionID,
+                                                    request->monitoredItemIds[i]);
 }

+ 20 - 57
src/server/ua_subscription.c

@@ -22,13 +22,12 @@ UA_Subscription *UA_Subscription_new(UA_Int32 subscriptionID) {
 }
 
 void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *server) {
-    UA_MonitoredItem *mon, *tmp_mon;
-    
     // Just in case any parallel process attempts to access this subscription
     // while we are deleting it... make it vanish.
     subscription->subscriptionID = 0;
     
     // Delete monitored Items
+    UA_MonitoredItem *mon, *tmp_mon;
     LIST_FOREACH_SAFE(mon, &subscription->MonitoredItems, listEntry, tmp_mon) {
         LIST_REMOVE(mon, listEntry);
         MonitoredItem_delete(mon);
@@ -38,7 +37,7 @@ void UA_Subscription_deleteMembers(UA_Subscription *subscription, UA_Server *ser
     Subscription_deleteUnpublishedNotification(0, true, subscription);
     
     // Unhook/Unregister any timed work assiociated with this subscription
-    if(subscription->timedUpdateJob != NULL){
+    if(subscription->timedUpdateJob) {
         Subscription_unregisterUpdateJob(server, subscription);
         UA_free(subscription->timedUpdateJob);
     }
@@ -79,8 +78,6 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
     //MonitoredItem_queuedValue *queuedValue;
     UA_unpublishedNotification *msg;
     UA_UInt32 monItemsChangeT = 0, monItemsStatusT = 0, monItemsEventT = 0;
-    UA_DataChangeNotification *changeNotification;
-    size_t notificationOffset;
     
     if(!subscription || subscription->lastPublished + subscription->publishingInterval > UA_DateTime_now())
         return;
@@ -115,9 +112,8 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
         return;
     }
     
-    msg = (UA_unpublishedNotification *) UA_malloc(sizeof(UA_unpublishedNotification));
-    msg->notification = UA_malloc(sizeof(UA_NotificationMessage));
-    INITPOINTER(msg->notification->notificationData);
+    msg = UA_malloc(sizeof(UA_unpublishedNotification));
+    msg->notification = UA_NotificationMessage_new();
     msg->notification->sequenceNumber = subscription->sequenceNumber++;
     msg->notification->publishTime    = UA_DateTime_now();
     
@@ -125,22 +121,18 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
     // list of Queued values from all monitoredItems of that type
     msg->notification->notificationDataSize = ISNOTZERO(monItemsChangeT);
     // + ISNOTZERO(monItemsEventT) + ISNOTZERO(monItemsStatusT);
-    msg->notification->notificationData = UA_Array_new(&UA_TYPES[UA_TYPES_EXTENSIONOBJECT], 
-                                                       msg->notification->notificationDataSize);
+    msg->notification->notificationData =
+        UA_Array_new(msg->notification->notificationDataSize, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
     
-    for(int 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
-        msg->notification->notificationData[notmsgn].typeId = UA_NODEID_NUMERIC(0, 811);
+        /* msg->notification->notificationData[notmsgn].encoding = 1; // Encoding is always binary */
+        /* msg->notification->notificationData[notmsgn].typeId = UA_NODEID_NUMERIC(0, 811); */
       
         if(notmsgn == 0) {
-            // Construct a DataChangeNotification
-            changeNotification = UA_malloc(sizeof(UA_DataChangeNotification));
-	
-            // Create one DataChangeNotification for each queue item held in each monitoredItems queue:
-            changeNotification->monitoredItems = UA_Array_new(&UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION],
-                                                              monItemsChangeT);
+            UA_DataChangeNotification *changeNotification = UA_DataChangeNotification_new();
+            changeNotification->monitoredItems = UA_Array_new(monItemsChangeT, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]);
 	
             // Scan all monitoredItems in this subscription and have their queue transformed into an Array of
             // the propper NotificationMessageType (Status, Change, Event)
@@ -152,29 +144,10 @@ void Subscription_updateNotifications(UA_Subscription *subscription) {
                 monItemsChangeT += MonitoredItem_QueueToDataChangeNotifications(&changeNotification->monitoredItems[monItemsChangeT], mon);
                 MonitoredItem_ClearQueue(mon);
             }
-            
-            changeNotification->monitoredItemsSize  = monItemsChangeT;
-            changeNotification->diagnosticInfosSize = 0;
-            changeNotification->diagnosticInfos     = NULL;
-        
-            msg->notification->notificationData[notmsgn].body.length =
-                UA_calcSizeBinary(changeNotification, &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]);
-            msg->notification->notificationData[notmsgn].body.data   =
-                UA_calloc(msg->notification->notificationData[notmsgn].body.length, sizeof(UA_Byte));
-        
-            notificationOffset = 0;
-            UA_StatusCode retval = UA_encodeBinary(changeNotification, &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION],
-                                                   &msg->notification->notificationData[notmsgn].body, &notificationOffset);
-            if(retval != UA_STATUSCODE_GOOD)
-                UA_ByteString_deleteMembers(&msg->notification->notificationData[notmsgn].body);
-	
-            // FIXME: Not properly freed!
-            for(unsigned int i=0; i<monItemsChangeT; i++) {
-                UA_MonitoredItemNotification *thisNotification = &(changeNotification->monitoredItems[i]);
-                UA_DataValue_deleteMembers(&(thisNotification->value));
-            }
-            UA_free(changeNotification->monitoredItems);
-            UA_free(changeNotification);
+            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;
         } else if(notmsgn == 1) {
             // FIXME: Constructing a StatusChangeNotification is not implemented
         } else if(notmsgn == 2) {
@@ -216,12 +189,8 @@ void Subscription_copyTopNotificationMessage(UA_NotificationMessage *dst, UA_Sub
     
     if(latest->notificationDataSize == 0)
         return;
-    
-    dst->notificationData = (UA_ExtensionObject *) UA_malloc(sizeof(UA_ExtensionObject));
-    dst->notificationData->encoding = latest->notificationData->encoding;
-    dst->notificationData->typeId   = latest->notificationData->typeId;
-    UA_ByteString_copy(&latest->notificationData->body,
-                       &dst->notificationData->body);
+    dst->notificationData = UA_ExtensionObject_new();
+    UA_ExtensionObject_copy(latest->notificationData, dst->notificationData);
 }
 
 UA_UInt32 Subscription_deleteUnpublishedNotification(UA_UInt32 seqNo, UA_Boolean bDeleteAll, UA_Subscription *sub) {
@@ -231,14 +200,8 @@ UA_UInt32 Subscription_deleteUnpublishedNotification(UA_UInt32 seqNo, UA_Boolean
         if (!bDeleteAll && not->notification->sequenceNumber != seqNo)
             continue;
         LIST_REMOVE(not, listEntry);
-        if(not->notification) {
-            if(not->notification->notificationData) {
-                if(not->notification->notificationData->body.data)
-                    UA_free(not->notification->notificationData->body.data);
-                UA_free(not->notification->notificationData);
-            }
-            UA_free(not->notification);
-        }
+        if(not->notification)
+            UA_NotificationMessage_delete(not->notification);
         UA_free(not);
         deletedItems++;
     }
@@ -519,7 +482,7 @@ void MonitoredItem_QueuePushDataValue(UA_Server *server, UA_MonitoredItem *monit
     }
   
     // encode the data to find if its different to the previous
-    newValueAsByteString.length = UA_calcSizeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE]);
+    newValueAsByteString.length = 512; // Todo: Hack! We should make a copy of the value, not encode it. UA_calcSizeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE]);
     newValueAsByteString.data   = UA_malloc(newValueAsByteString.length);
     UA_StatusCode retval = UA_encodeBinary(&newvalue->value, &UA_TYPES[UA_TYPES_DATAVALUE], &newValueAsByteString, &encodingOffset);
     if(retval != UA_STATUSCODE_GOOD)

+ 72 - 90
src/ua_types_encoding_binary.c

@@ -65,7 +65,6 @@ UInt16_encodeBinary(UA_UInt16 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt16) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
-
 #if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     UA_UInt16 le_uint16 = htole16(*src);
     src = &le_uint16;
@@ -91,7 +90,6 @@ UInt16_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_UInt16 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt16) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-
 #ifdef UA_ALIGNED_MEMORY_ACCESS
     *dst = (UA_UInt16) src->data[(*offset)++] << 0;
     *dst |= (UA_UInt16) src->data[(*offset)++] << 8;
@@ -117,7 +115,6 @@ UInt32_encodeBinary(UA_UInt32 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt32) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
-
 #if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     UA_UInt32 le_uint32 = htole32(*src);
     src = &le_uint32;
@@ -150,7 +147,6 @@ UInt32_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_UInt32 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt32) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-
 #ifdef UA_ALIGNED_MEMORY_ACCESS
     *dst = (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF));
     *dst |= (UA_UInt32)((UA_Byte)(src->data[(*offset)++] & 0xFF) << 8);
@@ -184,7 +180,6 @@ UInt64_encodeBinary(UA_UInt64 const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_UInt64) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
-
 #if defined(UA_NON_LITTLEENDIAN_ARCHITECTURE) && !defined(UA_ALIGNED_MEMORY_ACCESS)
     UA_UInt64 le_uint64 = htole64(*src);
     src = &le_uint64;
@@ -221,7 +216,6 @@ UInt64_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                     UA_UInt64 *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_UInt64) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-
 #ifdef UA_ALIGNED_MEMORY_ACCESS
     *dst  = (UA_UInt64) src->data[(*offset)++];
     *dst |= (UA_UInt64) src->data[(*offset)++] << 8;
@@ -269,7 +263,6 @@ Float_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Float *dst, cons
     UA_Float sign;
     if(memcmp(&src->data[*offset], UA_FLOAT_ZERO, 4) == 0)
         return Int32_decodeBinary(src, offset, (UA_Int32*) dst, NULL);
-
     mantissa = (UA_Float)(src->data[*offset] & 0xFF); // bits 0-7
     mantissa = (mantissa / 256.0) + (UA_Float)(src->data[*offset + 1] & 0xFF); // bits 8-15
     mantissa = (mantissa / 256.0) + (UA_Float)(src->data[*offset + 2] & 0x7F); // bits 16-22
@@ -277,15 +270,16 @@ Float_decodeBinary(UA_ByteString const *src, size_t *offset, UA_Float *dst, cons
     biasedExponent |= (src->data[*offset + 3] & 0x7F) << 1; // bits 24-30
     sign = (src->data[*offset + 3] & 0x80) ? -1.0 : 1.0; // bit 31
     if(biasedExponent >= 127)
-        *dst = (UA_Float)sign * (1 << (biasedExponent - 127)) * (1.0 + mantissa / 128.0);
+        *dst = (UA_Float)sign*(1<<(biasedExponent-127))*(1.0+mantissa/128.0);
     else
-        *dst = (UA_Float)sign * 2.0 * (1.0 + mantissa / 128.0) / ((UA_Float)(biasedExponent - 127));
+        *dst = (UA_Float)sign*2.0*(1.0+mantissa/128.0)/((UA_Float)(biasedExponent-127));
     *offset += 4;
     return UA_STATUSCODE_GOOD;
 }
 
 static UA_StatusCode
-Float_encodeBinary(UA_Float const *src, const UA_DataType *_, UA_ByteString *dst, size_t *UA_RESTRICT offset) {
+Float_encodeBinary(UA_Float const *src, const UA_DataType *_,
+                   UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_Float) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
     UA_Float srcFloat = *src;
@@ -297,13 +291,13 @@ Float_encodeBinary(UA_Float const *src, const UA_DataType *_, UA_ByteString *dst
 }
 
 /* Double */
+// Todo: Architecture agnostic de- and encoding, like float has it
 UA_Byte UA_DOUBLE_ZERO[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 static UA_StatusCode
 Double_decodeBinary(UA_ByteString const *src, size_t *offset,
                     UA_Double *dst, const UA_DataType *_) {
     if(*offset + sizeof(UA_Double) > src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
-
     UA_Byte *dstBytes = (UA_Byte*)dst;
     UA_Double db = 0;
     memcpy(&db, &(src->data[*offset]),sizeof(UA_Double));
@@ -315,31 +309,6 @@ Double_decodeBinary(UA_ByteString const *src, size_t *offset,
     dstBytes[1] = src->data[(*offset)++];
     dstBytes[2] = src->data[(*offset)++];
     dstBytes[3] = src->data[(*offset)++];
-
-/*
-    UA_Double sign;
-    UA_Double mantissa;
-    UA_UInt32 biasedExponent;
-    if(memcmp(&src->data[*offset], UA_DOUBLE_ZERO, 8) == 0)
-        return Int64_decodeBinary(src, offset, (UA_Int64 *) dst, NULL);
-    mantissa = (UA_Double) (src->data[*offset] & 0xFF); // bits 0-7
-    mantissa = (mantissa / 256.0) + (UA_Double) (src->data[*offset + 1] & 0xFF); // bits 8-15
-    mantissa = (mantissa / 256.0) + (UA_Double) (src->data[*offset + 2] & 0xFF); // bits 16-23
-    mantissa = (mantissa / 256.0) + (UA_Double) (src->data[*offset + 3] & 0xFF); // bits 24-31
-    mantissa = (mantissa / 256.0) + (UA_Double) (src->data[*offset + 4] & 0xFF); // bits 32-39
-    mantissa = (mantissa / 256.0) + (UA_Double) (src->data[*offset + 5] & 0xFF); // bits 40-47
-    mantissa = (mantissa / 256.0) + (UA_Double) (src->data[*offset + 6] & 0x0F); // bits 48-51
-    biasedExponent = (src->data[*offset + 6] & 0xF0) >> 4; // bits 52-55
-    biasedExponent |= ((UA_UInt32) (src->data[*offset + 7] & 0x7F)) << 4; // bits 56-62
-    sign = (src->data[*offset + 7] & 0x80) ? -1.0 : 1.0; // bit 63
-    if(biasedExponent >= 1023)
-        *dst = (UA_Double) sign * (1 << (biasedExponent - 1023))
-                * (1.0 + mantissa / 8.0);
-    else
-        *dst = (UA_Double) sign * 2.0 * (1.0 + mantissa / 8.0)
-                / ((UA_Double) (biasedExponent - 1023));
-    *offset += 8;
-    *offset */
     return UA_STATUSCODE_GOOD;
 }
 
@@ -349,7 +318,6 @@ Double_encodeBinary(UA_Double const *src, const UA_DataType *_,
                     UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     if(*offset + sizeof(UA_Double) > dst->length)
         return UA_STATUSCODE_BADENCODINGERROR;
-
     /* ARM7TDMI Half Little Endian Byte order for Double 3 2 1 0 7 6 5 4 */
     UA_Byte srcDouble[sizeof(UA_Double)];
     memcpy(&srcDouble,src,sizeof(UA_Double));
@@ -400,8 +368,9 @@ Array_encodeBinary(const void *src, size_t length, const UA_DataType *type,
 }
 
 static UA_StatusCode
-Array_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset, UA_Int32 signed_length,
-                   void **dst, size_t *out_length, const UA_DataType *type) {
+Array_decodeBinary(const UA_ByteString *src, size_t *UA_RESTRICT offset,
+                   UA_Int32 signed_length, void **dst, size_t *out_length,
+                   const UA_DataType *type) {
     size_t length = signed_length;
     *out_length = 0;
     if(signed_length <= 0) {
@@ -644,19 +613,16 @@ NodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 static UA_StatusCode
 ExpandedNodeId_encodeBinary(UA_ExpandedNodeId const *src, const UA_DataType *_,
                             UA_ByteString *dst, size_t *UA_RESTRICT offset) {
-    UA_Byte flags = 0;
     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);
-        flags |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG;
+        dst->data[start] |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG;
     }
     if(src->serverIndex > 0) {
         retval |= UInt32_encodeBinary(&src->serverIndex, NULL, dst, offset);
-        flags |= UA_EXPANDEDNODEID_SERVERINDEX_FLAG;
+        dst->data[start] |= UA_EXPANDEDNODEID_SERVERINDEX_FLAG;
     }
-    if(flags != 0)
-        dst->data[start] |= flags;
     return retval;
 }
 
@@ -667,8 +633,8 @@ ExpandedNodeId_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset
     if(*offset >= src->length)
         return UA_STATUSCODE_BADDECODINGERROR;
     UA_Byte encodingByte = src->data[*offset];
-    src->data[*offset] = encodingByte & ~(UA_EXPANDEDNODEID_NAMESPACEURI_FLAG |
-    UA_EXPANDEDNODEID_SERVERINDEX_FLAG);
+    src->data[*offset] = encodingByte &
+        ~(UA_EXPANDEDNODEID_NAMESPACEURI_FLAG | UA_EXPANDEDNODEID_SERVERINDEX_FLAG);
     UA_StatusCode retval = NodeId_decodeBinary(src, offset, &dst->nodeId, NULL);
     if(encodingByte & UA_EXPANDEDNODEID_NAMESPACEURI_FLAG) {
         dst->nodeId.namespaceIndex = 0;
@@ -689,12 +655,10 @@ static UA_StatusCode
 LocalizedText_encodeBinary(UA_LocalizedText const *src, const UA_DataType *_,
                            UA_ByteString *dst, size_t *UA_RESTRICT offset) {
     UA_Byte encodingMask = 0;
-    if(src->locale.data != NULL)
-        encodingMask |=
-        UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
-    if(src->text.data != NULL)
-        encodingMask |=
-        UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;
+    if(src->locale.data)
+        encodingMask |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
+    if(src->text.data)
+        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);
@@ -727,10 +691,18 @@ ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_
     if(encoding > UA_EXTENSIONOBJECT_ENCODED_XML) {
         if(!src->content.decoded.type || !src->content.decoded.data)
             return UA_STATUSCODE_BADENCODINGERROR;
+        UA_NodeId typeId = src->content.decoded.type->typeId;
+        if(typeId.identifierType != UA_NODEIDTYPE_NUMERIC)
+            return UA_STATUSCODE_BADENCODINGERROR;
+        typeId.identifier.numeric += UA_ENCODINGOFFSET_BINARY;
         encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
-        retval = NodeId_encodeBinary(&src->content.decoded.type->typeId, NULL, dst, offset);
+        retval = NodeId_encodeBinary(&typeId, NULL, dst, offset);
         retval |= Byte_encodeBinary(&encoding, NULL, dst, offset);
+        size_t old_offset = *offset; // jump back to encode the length
+        *offset += 4;
         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  {
         retval = NodeId_encodeBinary(&src->content.encoded.typeId, NULL, dst, offset);
         retval |= Byte_encodeBinary(&encoding, NULL, dst, offset);
@@ -748,6 +720,16 @@ ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_
     return retval;
 }
 
+static UA_StatusCode findDataType(const UA_NodeId *typeId, const UA_DataType **type) {
+    for(size_t i = 0; i < UA_TYPES_COUNT; i++) {
+        if(UA_NodeId_equal(typeId, &UA_TYPES[i].typeId)) {
+            *type = &UA_TYPES[i];
+            return UA_STATUSCODE_GOOD;
+        }
+    }
+    return UA_STATUSCODE_BADNODEIDUNKNOWN;
+}
+
 static UA_StatusCode
 ExtensionObject_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
                              UA_ExtensionObject *dst, const UA_DataType *_) {
@@ -756,51 +738,57 @@ ExtensionObject_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offse
     UA_NodeId 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)
+        retval = UA_STATUSCODE_BADDECODINGERROR;
     if(retval != UA_STATUSCODE_GOOD) {
         UA_NodeId_deleteMembers(&typeId);
         return retval;
     }
+
     if(encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
         dst->encoding = encoding;
         dst->content.encoded.typeId = typeId;
         dst->content.encoded.body = UA_BYTESTRING_NULL;
-        return UA_STATUSCODE_GOOD;
     } 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]);
-        if(!retval)
-            UA_ExtensionObject_deleteMembers(dst);
-        return retval;
-    }
+    } else {
+        /* try to decode the content */
+        size_t oldoffset = *offset;
+        UA_Int32 length = 0;
+        retval |= Int32_decodeBinary(src, offset, &length, NULL);
+        if(retval != UA_STATUSCODE_GOOD)
+            return retval;
 
-    /* binary encoded content. try to find the matching type */
-    const UA_DataType *type = NULL;
-    for(size_t typeIndex = 0; typeIndex < UA_TYPES_COUNT; typeIndex++) {
-        if(UA_NodeId_equal(&typeId, &UA_TYPES[typeIndex].typeId)) {
-            type = &UA_TYPES[typeIndex];
-            break;
+        const UA_DataType *type = NULL;
+        typeId.identifier.numeric -= UA_ENCODINGOFFSET_BINARY;
+        findDataType(&typeId, &type);
+        if(type) {
+            dst->content.decoded.data = UA_new(type);
+            if(dst->content.decoded.data) {
+                retval = UA_decodeBinary(src, offset, dst->content.decoded.data, type);
+                dst->content.decoded.type = type;
+                dst->encoding = UA_EXTENSIONOBJECT_DECODED;
+            } else
+                retval = UA_STATUSCODE_BADOUTOFMEMORY;
+            /* check if the decoded length was as announced */
+            if(*offset != oldoffset + 4 + length)
+                retval = UA_STATUSCODE_BADDECODINGERROR;
+        } else {
+            *offset = oldoffset;
+            retval = UA_decodeBinary(src, offset, &dst->content.encoded.body, &UA_TYPES[UA_TYPES_BYTESTRING]);
+            dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
+            dst->content.encoded.typeId = typeId;
         }
     }
-
-    if(type) {
-        retval = UA_decodeBinary(src, offset, &dst->content.decoded.data, type);
-        dst->content.decoded.type = type;
-        dst->encoding = UA_EXTENSIONOBJECT_DECODED;
-    } else {
-        retval = UA_decodeBinary(src, offset, &dst->content.encoded.body, &UA_TYPES[UA_TYPES_BYTESTRING]);
-        dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
-        dst->content.encoded.typeId = typeId;
-    }
-
-    if(!retval)
+    if(retval != UA_STATUSCODE_GOOD)
         UA_ExtensionObject_deleteMembers(dst);
     return retval;
 }
 
 /* Variant */
-/* We can store all data types in a variant internally. But for communication we wrap them in an
- * ExtensionObject if they are not builtin. */
+/* Types that are not builtin get wrapped in an ExtensionObject */
 
 enum UA_VARIANT_ENCODINGMASKTYPE {
     UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3F,        // bits 0:5
@@ -825,11 +813,11 @@ Variant_encodeBinary(UA_Variant const *src, const UA_DataType *_,
 
     UA_NodeId typeId;
     UA_NodeId_init(&typeId);
-    if(isBuiltin)
+    if(isBuiltin) {
         /* Do an extra lookup. Enums are encoded as UA_UInt32. */
         encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK &
             (UA_Byte) UA_TYPES[src->type->typeIndex].typeId.identifier.numeric;
-    else {
+    } else {
         /* wrap the datatype in an extensionobject */
         encodingByte |= UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (UA_Byte) 22;
         typeId = src->type->typeId;
@@ -874,7 +862,7 @@ Variant_encodeBinary(UA_Variant const *src, const UA_DataType *_,
     }
     if(hasDimensions)
         retval |= Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsSize,
-                                        &UA_TYPES[UA_TYPES_INT32], dst, offset);
+                                     &UA_TYPES[UA_TYPES_INT32], dst, offset);
     return retval;
 }
 
@@ -924,15 +912,9 @@ Variant_decodeBinary(UA_ByteString const *src, size_t *UA_RESTRICT offset,
 
         /* search for the datatype. use extensionobject if nothing is found */
         dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
-        if(typeId.namespaceIndex == 0 && eo_encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
-            for(typeIndex = 0;typeIndex < UA_TYPES_COUNT; typeIndex++) {
-                if(UA_NodeId_equal(&typeId, &UA_TYPES[typeIndex].typeId)) {
-                    dst->type = &UA_TYPES[typeIndex];
-                    *offset = intern_offset;
-                    break;
-                }
-            }
-        }
+        if(typeId.namespaceIndex == 0 && eo_encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING &&
+           findDataType(&typeId, &dst->type) == UA_STATUSCODE_GOOD)
+            *offset = intern_offset;
         UA_NodeId_deleteMembers(&typeId);
 
         /* decode the type */

+ 0 - 29
src/ua_types_encoding_binary.h

@@ -2,40 +2,11 @@
 #define UA_TYPES_ENCODING_BINARY_H_
 
 #include "ua_types.h"
-#include "ua_types_generated.h"
-#include "ua_util.h"
 
-/**
- * @ingroup types
- *
- * @defgroup encoding_binary Binary Encoding
- *
- * @brief Functions for binary en- and decoding of built-in datatypes as defined
- * in the standard. The encoding of the remaining datatypes is autogenerated
- * from XML descriptions.
- *
- * All datatypes have similar functions with a common postfix. DO NOT CALL THESE
- * FUNCTIONS WITH NULL-POINTERS IF IT IS NOT EXPLICITLY PERMITTED.
- *
- * - _encode: Encodes a variable into a bytestring. If an error occurs
- *   (indicated by the return value), the bytestring may be left in an
- *   inconsistent state.
- *
- * - _decode: Decodes a variable stored in a bytestring. The destination is
- *   cleaned up (init) before decoding into it. If an error occurs (indicated by
- *   the return value), the destination is cleaned up (deleteMembers, but no
- *   init) before returning.
- *
- * @{
- */
-
-/* Generic Types */
 UA_StatusCode UA_encodeBinary(const void *src, const UA_DataType *type, UA_ByteString *dst,
                               size_t *UA_RESTRICT offset) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
 UA_StatusCode UA_decodeBinary(const UA_ByteString *src, size_t * UA_RESTRICT offset, void *dst,
                               const UA_DataType *type) UA_FUNC_ATTR_WARN_UNUSED_RESULT;
 
-/// @}
-
 #endif /* UA_TYPES_ENCODING_BINARY_H_ */

+ 2 - 2
tools/generate_datatypes.py

@@ -234,11 +234,11 @@ class EnumerationType(Type):
         else:
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}, " % (description.namespaceid, description.nodeid)
         return (("{.typeName = \"" + self.name[3:] + "\", ") if typeintrospection else "{") + ".typeId = " + typeid + \
-            ".memSize = sizeof(" + self.name + "), .builtin = UA_FALSE, " + \
+            ".memSize = sizeof(" + self.name + "), .builtin = UA_TRUE, " + \
             ".fixedSize = UA_TRUE, .zeroCopyable = UA_TRUE, " + \
             ".membersSize = 1,\n\t.members = {{.memberTypeIndex = UA_TYPES_INT32, " + \
             (".memberName = \"\", " if typeintrospection else "") + \
-            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = %s }" % (outname.upper() + "_" + self.name[3:].upper())
+            ".namespaceZero = UA_TRUE, .padding = 0, .isArray = UA_FALSE }}, .typeIndex = UA_TYPES_INT32 }"
 
 class OpaqueType(Type):
     def fixed_size(self):