Parcourir la source

Fix #769: Wrong NodeIDs offset for BinaryEncoding (#770)

* Fix #769: Wrong NodeIDs offset for BinaryEncoding

* Avoid double loops for finding correct node id

* Remove findDataType

* Disable xmlEncodingId for now
Stefan Profanter il y a 8 ans
Parent
commit
99522b216c

+ 0 - 8
include/ua_constants.h

@@ -95,14 +95,6 @@ typedef enum {
 #define UA_WRITEMASK_WRITEMASK                  1<<20
 #define UA_WRITEMASK_VALUEFORVARIABLETYPE       1<<21
 
-/**
- * Encoding Offsets
- * ----------------
- * Subtract from the typeid of the encoding nodeids to get to the type
- * definition. */
-#define UA_ENCODINGOFFSET_XML 1
-#define UA_ENCODINGOFFSET_BINARY 2
-
 /**
  * .. _statuscodes:
  *

+ 2 - 0
include/ua_types.h

@@ -745,6 +745,8 @@ struct UA_DataType {
                                     pointers */
     UA_Boolean overlayable  : 1; /* The type has the identical memory layout in
                                     memory and on the binary stream. */
+    //UA_UInt16  xmlEncodingId;    /* NodeId of datatype when encoded as XML */
+    UA_UInt16  binaryEncodingId;    /* NodeId of datatype when encoded as binary */
     UA_DataTypeMember *members;
 };
 

+ 5 - 7
src/client/ua_client.c

@@ -212,7 +212,7 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     asymHeader.securityPolicyUri = UA_STRING_ALLOC("http://opcfoundation.org/UA/SecurityPolicy#None");
 
     /* id of opensecurechannelrequest */
-    UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
+    UA_NodeId requestType = UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId);
 
     UA_OpenSecureChannelRequest opnSecRq;
     UA_OpenSecureChannelRequest_init(&opnSecRq);
@@ -277,8 +277,7 @@ static UA_StatusCode SecureChannelHandshake(UA_Client *client, UA_Boolean renew)
     UA_AsymmetricAlgorithmSecurityHeader_decodeBinary(&reply, &offset, &asymHeader);
     UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
     UA_NodeId_decodeBinary(&reply, &offset, &requestType);
-    UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE +
-                                                  UA_ENCODINGOFFSET_BINARY);
+    UA_NodeId expectedRequest = UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId);
     if(!UA_NodeId_equal(&requestType, &expectedRequest)) {
         UA_ByteString_deleteMembers(&reply);
         UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(&asymHeader);
@@ -522,7 +521,7 @@ static UA_StatusCode CloseSecureChannel(UA_Client *client) {
     seqHeader.sequenceNumber = ++channel->sendSequenceNumber;
     seqHeader.requestId = ++client->requestId;
 
-    UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CLOSESECURECHANNELREQUEST + UA_ENCODINGOFFSET_BINARY);
+    UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST].binaryEncodingId);
 
     UA_ByteString message;
     UA_Connection *c = client->connection;
@@ -733,8 +732,7 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
     retval |= UA_SequenceHeader_decodeBinary(&reply, &offset, &seqHeader);
     UA_NodeId responseId;
     retval |= UA_NodeId_decodeBinary(&reply, &offset, &responseId);
-    UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->typeId.identifier.numeric +
-                                                 UA_ENCODINGOFFSET_BINARY);
+    UA_NodeId expectedNodeId = UA_NODEID_NUMERIC(0, responseType->binaryEncodingId);
 
     if(retval != UA_STATUSCODE_GOOD)
         goto finish;
@@ -750,7 +748,7 @@ void __UA_Client_Service(UA_Client *client, const void *r, const UA_DataType *re
 
     /* Todo: we need to demux responses since a publish responses may come at any time */
     if(!UA_NodeId_equal(&responseId, &expectedNodeId) || seqHeader.requestId != requestId) {
-        if(responseId.identifier.numeric != UA_NS0ID_SERVICEFAULT + UA_ENCODINGOFFSET_BINARY) {
+        if(responseId.identifier.numeric != UA_TYPES[UA_TYPES_SERVICEFAULT].binaryEncodingId) {
             UA_LOG_ERROR(client->config.logger, UA_LOGCATEGORY_CLIENT,
                          "Reply answers the wrong request. Expected ns=%i,i=%i. But retrieved ns=%i,i=%i",
                          expectedNodeId.namespaceIndex, expectedNodeId.identifier.numeric,

+ 59 - 5
src/server/ua_server_binary.c

@@ -67,66 +67,90 @@ static void
 getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
                    const UA_DataType **responseType, UA_Service *service,
                    UA_Boolean *requiresSession) {
-    switch(requestTypeId - UA_ENCODINGOFFSET_BINARY) {
+    switch(requestTypeId) {
     case UA_NS0ID_GETENDPOINTSREQUEST:
+    case UA_NS0ID_GETENDPOINTSREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_GETENDPOINTSREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_GetEndpoints;
         *requestType = &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE];
         *requiresSession = false;
         break;
     case UA_NS0ID_FINDSERVERSREQUEST:
+    case UA_NS0ID_FINDSERVERSREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_FINDSERVERSREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_FindServers;
         *requestType = &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE];
         *requiresSession = false;
         break;
     case UA_NS0ID_CREATESESSIONREQUEST:
+    case UA_NS0ID_CREATESESSIONREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_CREATESESSIONREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_CreateSession;
         *requestType = &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE];
         *requiresSession = false;
         break;
     case UA_NS0ID_ACTIVATESESSIONREQUEST:
+    case UA_NS0ID_ACTIVATESESSIONREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_ACTIVATESESSIONREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_ActivateSession;
         *requestType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE];
         break;
     case UA_NS0ID_CLOSESESSIONREQUEST:
+    case UA_NS0ID_CLOSESESSIONREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_CLOSESESSIONREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_CloseSession;
         *requestType = &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE];
         break;
     case UA_NS0ID_READREQUEST:
+    case UA_NS0ID_READREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_READREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_Read;
         *requestType = &UA_TYPES[UA_TYPES_READREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_READRESPONSE];
         break;
     case UA_NS0ID_WRITEREQUEST:
+    case UA_NS0ID_WRITEREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_WRITEREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_Write;
         *requestType = &UA_TYPES[UA_TYPES_WRITEREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_WRITERESPONSE];
         break;
     case UA_NS0ID_BROWSEREQUEST:
+    case UA_NS0ID_BROWSEREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_BROWSEREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_Browse;
         *requestType = &UA_TYPES[UA_TYPES_BROWSEREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_BROWSERESPONSE];
         break;
     case UA_NS0ID_BROWSENEXTREQUEST:
+    case UA_NS0ID_BROWSENEXTREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_BROWSENEXTREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_BrowseNext;
         *requestType = &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE];
         break;
     case UA_NS0ID_REGISTERNODESREQUEST:
+    case UA_NS0ID_REGISTERNODESREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_REGISTERNODESREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_RegisterNodes;
         *requestType = &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE];
         break;
     case UA_NS0ID_UNREGISTERNODESREQUEST:
+    case UA_NS0ID_UNREGISTERNODESREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_UNREGISTERNODESREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_UnregisterNodes;
         *requestType = &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE];
         break;
     case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST:
+    case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_TranslateBrowsePathsToNodeIds;
         *requestType = &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE];
@@ -134,50 +158,70 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
 
 #ifdef UA_ENABLE_SUBSCRIPTIONS
     case UA_NS0ID_CREATESUBSCRIPTIONREQUEST:
+    case UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_CreateSubscription;
         *requestType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE];
         break;
     case UA_NS0ID_PUBLISHREQUEST:
+    case UA_NS0ID_PUBLISHREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_PUBLISHREQUEST_ENCODING_DEFAULTBINARY:
         *requestType = &UA_TYPES[UA_TYPES_PUBLISHREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_PUBLISHRESPONSE];
         break;
     case UA_NS0ID_REPUBLISHREQUEST:
+    case UA_NS0ID_REPUBLISHREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_REPUBLISHREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_Republish;
         *requestType = &UA_TYPES[UA_TYPES_REPUBLISHREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE];
         break;
     case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST:
+    case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_ModifySubscription;
         *requestType = &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE];
         break;
     case UA_NS0ID_SETPUBLISHINGMODEREQUEST:
+    case UA_NS0ID_SETPUBLISHINGMODEREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_SETPUBLISHINGMODEREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_SetPublishingMode;
         *requestType = &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE];
         break;
     case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST:
+    case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_DELETESUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_DeleteSubscriptions;
         *requestType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE];
         break;
     case UA_NS0ID_CREATEMONITOREDITEMSREQUEST:
+    case UA_NS0ID_CREATEMONITOREDITEMSREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_CREATEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_CreateMonitoredItems;
         *requestType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE];
         break;
     case UA_NS0ID_DELETEMONITOREDITEMSREQUEST:
+    case UA_NS0ID_DELETEMONITOREDITEMSREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_DELETEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_DeleteMonitoredItems;
         *requestType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE];
         break;
     case UA_NS0ID_MODIFYMONITOREDITEMSREQUEST:
+    case UA_NS0ID_MODIFYMONITOREDITEMSREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_MODIFYMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_ModifyMonitoredItems;
         *requestType = &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE];
         break;
     case UA_NS0ID_SETMONITORINGMODEREQUEST:
+    case UA_NS0ID_SETMONITORINGMODEREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_SETMONITORINGMODEREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_SetMonitoringMode;
         *requestType = &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE];
@@ -186,6 +230,8 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
 
 #ifdef UA_ENABLE_METHODCALLS
     case UA_NS0ID_CALLREQUEST:
+    case UA_NS0ID_CALLREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_CALLREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_Call;
         *requestType = &UA_TYPES[UA_TYPES_CALLREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_CALLRESPONSE];
@@ -194,21 +240,29 @@ getServicePointers(UA_UInt32 requestTypeId, const UA_DataType **requestType,
 
 #ifdef UA_ENABLE_NODEMANAGEMENT
     case UA_NS0ID_ADDNODESREQUEST:
+    case UA_NS0ID_ADDNODESREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_ADDNODESREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_AddNodes;
         *requestType = &UA_TYPES[UA_TYPES_ADDNODESREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_ADDNODESRESPONSE];
         break;
     case UA_NS0ID_ADDREFERENCESREQUEST:
+    case UA_NS0ID_ADDREFERENCESREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_ADDREFERENCESREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_AddReferences;
         *requestType = &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE];
         break;
     case UA_NS0ID_DELETENODESREQUEST:
+    case UA_NS0ID_DELETENODESREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_DELETENODESREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_DeleteNodes;
         *requestType = &UA_TYPES[UA_TYPES_DELETENODESREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_DELETENODESRESPONSE];
         break;
     case UA_NS0ID_DELETEREFERENCESREQUEST:
+    case UA_NS0ID_DELETEREFERENCESREQUEST_ENCODING_DEFAULTXML:
+    case UA_NS0ID_DELETEREFERENCESREQUEST_ENCODING_DEFAULTBINARY:
         *service = (UA_Service)Service_DeleteReferences;
         *requestType = &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST];
         *responseType = &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE];
@@ -352,7 +406,7 @@ processOPN(UA_Connection *connection, UA_Server *server,
 #endif
     retval |= UA_AsymmetricAlgorithmSecurityHeader_encodeBinary(&asymHeader, &resp_msg, &tmpPos); // just mirror back
     retval |= UA_SequenceHeader_encodeBinary(&seqHeader, &resp_msg, &tmpPos);
-    UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE + UA_ENCODINGOFFSET_BINARY);
+    UA_NodeId responseType = UA_NODEID_NUMERIC(0, UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE].binaryEncodingId);
     retval |= UA_NodeId_encodeBinary(&responseType, &resp_msg, &tmpPos);
     retval |= UA_OpenSecureChannelResponse_encodeBinary(&p, &resp_msg, &tmpPos);
 
@@ -419,7 +473,7 @@ processRequest(UA_SecureChannel *channel, UA_Server *server,
                                 "but those are not enabled in the build");
         } else {
             UA_LOG_INFO_CHANNEL(server->config.logger, channel, "Unknown request %i",
-                                requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY);
+                                requestTypeId.identifier.numeric);
         }
         sendError(channel, msg, requestPos, &UA_TYPES[UA_TYPES_SERVICEFAULT],
                   requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
@@ -479,7 +533,7 @@ processRequest(UA_SecureChannel *channel, UA_Server *server,
         if(sessionRequired) {
             UA_LOG_INFO_CHANNEL(server->config.logger, channel,
                                 "Service request %i without a valid session",
-                                requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY);
+                                requestType->binaryEncodingId);
             sendError(channel, msg, requestPos, responseType,
                       requestId, UA_STATUSCODE_BADSESSIONIDINVALID);
             UA_deleteMembers(request, requestType);
@@ -495,7 +549,7 @@ processRequest(UA_SecureChannel *channel, UA_Server *server,
     if(sessionRequired && !session->activated) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
                             "Calling service %i on a non-activated session",
-                            requestTypeId.identifier.numeric - UA_ENCODINGOFFSET_BINARY);
+                            requestType->binaryEncodingId);
         sendError(channel, msg, requestPos, responseType,
                   requestId, UA_STATUSCODE_BADSESSIONNOTACTIVATED);
         UA_SessionManager_removeSession(&server->sessionManager,

+ 1 - 1
src/ua_securechannel.c

@@ -219,7 +219,7 @@ UA_SecureChannel_sendBinaryMessage(UA_SecureChannel *channel, UA_UInt32 requestI
     /* Encode the message type */
     size_t messagePos = 0;
     UA_NodeId typeId = contentType->typeId; /* always numeric */
-    typeId.identifier.numeric += UA_ENCODINGOFFSET_BINARY;
+    typeId.identifier.numeric = contentType->binaryEncodingId;
     UA_NodeId_encodeBinary(&typeId, &message, &messagePos);
 
     /* Encode with the chunking callback */

+ 13 - 15
src/ua_types_encoding_binary.c

@@ -697,6 +697,16 @@ LocalizedText_decodeBinary(UA_LocalizedText *dst, const UA_DataType *_) {
     return retval;
 }
 
+static UA_StatusCode findDataTypeByBinary(const UA_NodeId *typeId, const UA_DataType **findtype) {
+    for(size_t i = 0; i < UA_TYPES_COUNT; i++) {
+        if (UA_TYPES[i].binaryEncodingId == typeId->identifier.numeric) {
+            *findtype = &UA_TYPES[i];
+            return UA_STATUSCODE_GOOD;
+        }
+    }
+    return UA_STATUSCODE_BADNODEIDUNKNOWN;
+}
+
 /* ExtensionObject */
 static UA_StatusCode
 ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_) {
@@ -708,7 +718,7 @@ ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_
         UA_NodeId typeId = src->content.decoded.type->typeId;
         if(typeId.identifierType != UA_NODEIDTYPE_NUMERIC)
             return UA_STATUSCODE_BADENCODINGERROR;
-        typeId.identifier.numeric += UA_ENCODINGOFFSET_BINARY;
+        typeId.identifier.numeric= src->content.decoded.type->binaryEncodingId;
         encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
         retval = NodeId_encodeBinary(&typeId, NULL);
         retval |= Byte_encodeBinary(&encoding, NULL);
@@ -740,16 +750,6 @@ ExtensionObject_encodeBinary(UA_ExtensionObject const *src, const UA_DataType *_
     return retval;
 }
 
-static UA_StatusCode findDataType(const UA_NodeId *typeId, const UA_DataType **findtype) {
-    for(size_t i = 0; i < UA_TYPES_COUNT; i++) {
-        if(UA_NodeId_equal(typeId, &UA_TYPES[i].typeId)) {
-            *findtype = &UA_TYPES[i];
-            return UA_STATUSCODE_GOOD;
-        }
-    }
-    return UA_STATUSCODE_BADNODEIDUNKNOWN;
-}
-
 static UA_StatusCode
 ExtensionObject_decodeBinary(UA_ExtensionObject *dst, const UA_DataType *_) {
     UA_Byte encoding = 0;
@@ -778,8 +778,7 @@ ExtensionObject_decodeBinary(UA_ExtensionObject *dst, const UA_DataType *_) {
         /* helping clang analyzer, typeId is numeric */
         UA_assert(typeId.identifier.byteString.data == NULL);
         UA_assert(typeId.identifier.string.data == NULL);
-        typeId.identifier.numeric -= UA_ENCODINGOFFSET_BINARY;
-        findDataType(&typeId, &type);
+        findDataTypeByBinary(&typeId, &type);
         if(type) {
             pos += 4; /* jump over the length (todo: check if length matches) */
             dst->content.decoded.data = UA_new(type);
@@ -924,8 +923,7 @@ Variant_decodeBinary(UA_Variant *dst, const UA_DataType *_) {
         if(typeId.namespaceIndex == 0 && typeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
            eo_encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
             UA_assert(typeId.identifier.byteString.data == NULL); /* for clang analyzer <= 3.7 */
-            typeId.identifier.numeric -= UA_ENCODINGOFFSET_BINARY;
-            if(findDataType(&typeId, &dst->type) == UA_STATUSCODE_GOOD)
+            if(findDataTypeByBinary(&typeId, &dst->type) == UA_STATUSCODE_GOOD)
                 pos += 4; /* jump over the length (todo: check if length matches) */
             else
                 pos = old_pos; /* jump back and decode as extensionobject */

+ 20 - 0
tools/generate_datatypes.py

@@ -75,9 +75,13 @@ class Type(object):
                 break
 
     def datatype_c(self):
+        xmlEncodingId = "0"
+        binaryEncodingId = "0"
         if self.name in typedescriptions:
             description = typedescriptions[self.name]
             typeid = "{.namespaceIndex = %s, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = %s}" % (description.namespaceid, description.nodeid)
+            xmlEncodingId = description.xmlEncodingId
+            binaryEncodingId = description.binaryEncodingId
         else:
             typeid = "{.namespaceIndex = 0, .identifierType = UA_NODEIDTYPE_NUMERIC, .identifier.numeric = 0}"
         return "{ .typeId = " + typeid + \
@@ -87,8 +91,10 @@ class Type(object):
             ",\n  .builtin = " + self.builtin + \
             ",\n  .fixedSize = " + self.fixed_size + \
             ",\n  .overlayable = " + self.overlayable + \
+            ",\n  .binaryEncodingId = " + binaryEncodingId + \
             ",\n  .membersSize = " + str(len(self.members)) + \
             ",\n  .members = %s_members" % self.name + " }"
+            #",\n  .xmlEncodingId = " + xmlEncodingId + \ Not used for now
 
     def members_c(self):
         members = "static UA_DataTypeMember %s_members[%s] = {" % (self.name, len(self.members))
@@ -291,6 +297,8 @@ class TypeDescription(object):
         self.name = name
         self.nodeid = nodeid
         self.namespaceid = namespaceid
+        self.xmlEncodingId = "0"
+        self.binaryEncodingId = "0"
 
 def parseTypeDescriptions(filename, namespaceid):
     definitions = {}
@@ -301,6 +309,18 @@ def parseTypeDescriptions(filename, namespaceid):
     for index, row in enumerate(rows):
         if len(row) < 3:
             continue
+        if row[2] == "Object":
+            # Check if node name ends with _Encoding_(DefaultXml|DefaultBinary) and store the node id in the corresponding DataType
+            m = re.match('(.*?)_Encoding_Default(Xml|Binary)$',row[0])
+            if (m):
+                baseType = m.group(1)
+                if baseType not in types:
+                    continue
+                if m.group(2) == "Xml":
+                    definitions[baseType].xmlEncodingId = row[1]
+                else:
+                    definitions[baseType].binaryEncodingId = row[1]
+            continue
         if row[2] != "DataType":
             continue
         if row[0] == "BaseDataType":

+ 0 - 2
tools/generate_nodeids.py

@@ -23,8 +23,6 @@ def useNodeId(row):
         return False
     if "Type_" in row[0]:
         return False
-    if "_Encoding_Default" in row[0]:
-        return False
     return True
 
 f = open(args.nodeids)