Browse Source

Use correct identifier labels and encode bytestring as base64

Stefan Profanter 5 years ago
parent
commit
58c1be4db9

+ 10 - 7
CMakeLists.txt

@@ -380,6 +380,7 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
                      ${PROJECT_SOURCE_DIR}/include/ua_types.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_handling.h
+                     ${PROJECT_SOURCE_DIR}/include/ua_util.h
                      ${PROJECT_SOURCE_DIR}/include/ua_server.h
                      ${PROJECT_SOURCE_DIR}/include/ua_plugin_log.h
                      ${PROJECT_SOURCE_DIR}/include/ua_plugin_network.h
@@ -399,7 +400,8 @@ set(exported_headers ${PROJECT_BINARY_DIR}/src_generated/ua_config.h
 set(internal_headers ${PROJECT_SOURCE_DIR}/deps/queue.h
                      ${PROJECT_SOURCE_DIR}/deps/pcg_basic.h
                      ${PROJECT_SOURCE_DIR}/deps/libc_time.h
-                     ${PROJECT_SOURCE_DIR}/src/ua_util.h
+                     ${PROJECT_SOURCE_DIR}/deps/base64.h
+                     ${PROJECT_SOURCE_DIR}/src/ua_util_internal.h
                      ${PROJECT_SOURCE_DIR}/src/ua_types_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_types_generated_encoding_binary.h
                      ${PROJECT_BINARY_DIR}/src_generated/ua_transport_generated.h
@@ -470,7 +472,8 @@ set(lib_sources ${PROJECT_SOURCE_DIR}/src/ua_types.c
 
                 # dependencies
                 ${PROJECT_SOURCE_DIR}/deps/libc_time.c
-                ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c)
+                ${PROJECT_SOURCE_DIR}/deps/pcg_basic.c
+                ${PROJECT_SOURCE_DIR}/deps/base64.c)
 
 set(default_plugin_headers ${PROJECT_SOURCE_DIR}/plugins/ua_network_tcp.h
                            ${PROJECT_SOURCE_DIR}/plugins/ua_accesscontrol_default.h
@@ -523,11 +526,11 @@ if(UA_ENABLE_DISCOVERY_MULTICAST)
                          ${internal_headers} )
     list(APPEND internal_headers ${PROJECT_SOURCE_DIR}/src/server/ua_mdns_internal.h)
     set(lib_sources ${PROJECT_SOURCE_DIR}/src/server/ua_mdns.c
-                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/1035.c
-                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/xht.c
-                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/sdtxt.c
-                    ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/mdnsd.c
-                    ${lib_sources})
+        ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/1035.c
+        ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/xht.c
+        ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/sdtxt.c
+        ${PROJECT_SOURCE_DIR}/deps/mdnsd/libmdnsd/mdnsd.c
+        ${lib_sources})
 endif()
 
 #########################

+ 179 - 0
deps/base64.c

@@ -0,0 +1,179 @@
+/*
+
+  https://github.com/superwills/NibbleAndAHalf
+  base64.h -- Fast base64 encoding and decoding.
+  version 1.0.0, April 17, 2013 143a
+
+  Copyright (C) 2013 William Sherif
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  William Sherif
+  will.sherif@gmail.com
+
+  YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
+
+*/
+
+#include "base64.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static const char* b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
+
+// maps A=>0,B=>1..
+static const unsigned char unb64[]={
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //10
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //20
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //30
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //40
+    0,   0,   0,  62,   0,   0,   0,  63,  52,  53, //50
+    54,  55,  56,  57,  58,  59,  60,  61,   0,   0, //60
+    0,   0,   0,   0,   0,   0,   1,   2,   3,   4, //70
+    5,   6,   7,   8,   9,  10,  11,  12,  13,  14, //80
+    15,  16,  17,  18,  19,  20,  21,  22,  23,  24, //90
+    25,   0,   0,   0,   0,   0,   0,  26,  27,  28, //100
+    29,  30,  31,  32,  33,  34,  35,  36,  37,  38, //110
+    39,  40,  41,  42,  43,  44,  45,  46,  47,  48, //120
+    49,  50,  51,   0,   0,   0,   0,   0,   0,   0, //130
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //140
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //150
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //160
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //170
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //180
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //190
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //200
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //210
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //220
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //230
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //240
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //250
+    0,   0,   0,   0,   0,   0,
+}; // This array has 256 elements
+
+// Converts binary data of length=len to base64 characters.
+// Length of the resultant string is stored in flen
+// (you must pass pointer flen).
+char* UA_base64( const void* binaryData, int len, int *flen )
+{
+    const unsigned char* bin = (const unsigned char*) binaryData ;
+    char* res ;
+
+    int rc = 0 ; // result counter
+    int byteNo ; // I need this after the loop
+
+    int modulusLen = len % 3 ;
+    int pad = ((modulusLen&1)<<1) + ((modulusLen&2)>>1) ; // 2 gives 1 and 1 gives 2, but 0 gives 0.
+
+    *flen = 4*(len + pad)/3 ;
+    res = (char*) malloc( (size_t)(*flen + 1) ) ; // and one for the null
+    if( !res )
+    {
+        puts( "ERROR: base64 could not allocate enough memory." ) ;
+        puts( "I must stop because I could not get enough" ) ;
+        return 0;
+    }
+
+    for( byteNo = 0 ; byteNo <= len-3 ; byteNo+=3 )
+    {
+        unsigned char BYTE0=bin[byteNo];
+        unsigned char BYTE1=bin[byteNo+1];
+        unsigned char BYTE2=bin[byteNo+2];
+        res[rc++]  = b64[ BYTE0 >> 2 ] ;
+        res[rc++]  = b64[ ((0x3&BYTE0)<<4) + (BYTE1 >> 4) ] ;
+        res[rc++]  = b64[ ((0x0f&BYTE1)<<2) + (BYTE2>>6) ] ;
+        res[rc++]  = b64[ 0x3f&BYTE2 ] ;
+    }
+
+    if( pad==2 )
+    {
+        res[rc++] = b64[ bin[byteNo] >> 2 ] ;
+        res[rc++] = b64[ (0x3&bin[byteNo])<<4 ] ;
+        res[rc++] = '=';
+        res[rc++] = '=';
+    }
+    else if( pad==1 )
+    {
+        res[rc++]  = b64[ bin[byteNo] >> 2 ] ;
+        res[rc++]  = b64[ ((0x3&bin[byteNo])<<4)   +   (bin[byteNo+1] >> 4) ] ;
+        res[rc++]  = b64[ (0x0f&bin[byteNo+1])<<2 ] ;
+        res[rc++] = '=';
+    }
+
+    res[rc]=0; // NULL TERMINATOR! ;)
+    return res ;
+}
+
+unsigned char* UA_unbase64( const char* ascii, int len, int *flen )
+{
+    const unsigned char *safeAsciiPtr = (const unsigned char*)ascii ;
+    unsigned char *bin ;
+    int cb=0;
+    int charNo;
+    int pad = 0 ;
+
+    if( len < 2 ) { // 2 accesses below would be OOB.
+        // catch empty string, return NULL as result.
+        puts( "ERROR: You passed an invalid base64 string (too short). You get NULL back." ) ;
+        *flen=0;
+        return 0 ;
+    }
+    if( safeAsciiPtr[ len-1 ]=='=' )  ++pad ;
+    if( safeAsciiPtr[ len-2 ]=='=' )  ++pad ;
+
+    *flen = 3*len/4 - pad ;
+    bin = (unsigned char*)malloc( (size_t) (*flen) ) ;
+    if( !bin )
+    {
+        puts( "ERROR: unbase64 could not allocate enough memory." ) ;
+        puts( "I must stop because I could not get enough" ) ;
+        return 0;
+    }
+
+    for( charNo=0; charNo <= len - 4 - pad ; charNo+=4 )
+    {
+        int A=unb64[safeAsciiPtr[charNo]];
+        int B=unb64[safeAsciiPtr[charNo+1]];
+        int C=unb64[safeAsciiPtr[charNo+2]];
+        int D=unb64[safeAsciiPtr[charNo+3]];
+
+        bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ;
+        bin[cb++] = (unsigned char)((B<<4) | (C>>2)) ;
+        bin[cb++] = (unsigned char)((C<<6) | (D)) ;
+    }
+
+    if( pad==1 )
+    {
+        int A=unb64[safeAsciiPtr[charNo]];
+        int B=unb64[safeAsciiPtr[charNo+1]];
+        int C=unb64[safeAsciiPtr[charNo+2]];
+
+        bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ;
+        bin[cb++] = (unsigned char)((B<<4) | (C>>2)) ;
+    }
+    else if( pad==2 )
+    {
+        int A=unb64[safeAsciiPtr[charNo]];
+        int B=unb64[safeAsciiPtr[charNo+1]];
+
+        bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ;
+    }
+
+    return bin ;
+}
+

+ 46 - 0
deps/base64.h

@@ -0,0 +1,46 @@
+/*
+
+  https://github.com/superwills/NibbleAndAHalf
+  base64.h -- Fast base64 encoding and decoding.
+  version 1.0.0, April 17, 2013 143a
+
+  Copyright (C) 2013 William Sherif
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  William Sherif
+  will.sherif@gmail.com
+
+  YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz
+
+*/
+#ifndef UA_BASE64_H_
+#define UA_BASE64_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char* UA_base64( const void* binaryData, int len, int *flen );
+
+unsigned char* UA_unbase64( const char* ascii, int len, int *flen );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_BASE64_H_ */

+ 1 - 99
include/ua_plugin_log.h

@@ -18,6 +18,7 @@ extern "C" {
 
 #include "ua_types.h"
 #include "ua_types_generated_handling.h"
+#include "base64.h"
 
 /**
  * Logging Plugin API
@@ -110,105 +111,6 @@ UA_LOG_FATAL(UA_Logger logger, UA_LogCategory category, const char *msg, ...) {
 #endif
 }
 
-/**
- * Convenience macros for complex types
- * ------------------------------------ */
-#define UA_PRINTF_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
-#define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \
-        (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \
-        (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7]
-
-#define UA_PRINTF_STRING_FORMAT "\"%.*s\""
-#define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data
-
-//TODO remove when we merge architectures pull request
-#ifndef UA_snprintf
-# include <stdio.h>
-# if defined(_WIN32)
-#  define UA_snprintf(source, size, string, ...) _snprintf_s(source, size, _TRUNCATE, string, __VA_ARGS__)
-# else
-#  define UA_snprintf snprintf
-# endif
-#endif
-
-static UA_INLINE UA_StatusCode
-UA_ByteString_toString(const UA_ByteString *byteString, UA_String *str) {
-    if (str->length != 0) {
-        UA_free(str->data);
-        str->data = NULL;
-        str->length = 0;
-    }
-    if (byteString == NULL || byteString->data == NULL)
-        return UA_STATUSCODE_GOOD;
-    if (byteString == str)
-        return UA_STATUSCODE_BADINVALIDARGUMENT;
-
-    str->length = byteString->length*2;
-    str->data = (UA_Byte*)UA_malloc(str->length+1);
-    if (str->data == NULL)
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-
-    for (size_t i=0; i<byteString->length; i++)
-        UA_snprintf((char*)&str->data[i*2], 2+1, "%02x", byteString->data[i]);
-    return UA_STATUSCODE_GOOD;
-}
-
-static UA_INLINE UA_StatusCode
-UA_NodeId_toString(const UA_NodeId *nodeId, UA_String *nodeIdStr) {
-    if (nodeIdStr->length != 0) {
-        UA_free(nodeIdStr->data);
-        nodeIdStr->data = NULL;
-        nodeIdStr->length = 0;
-    }
-    if (nodeId == NULL)
-        return UA_STATUSCODE_GOOD;
-
-
-    UA_ByteString byteStr = UA_BYTESTRING_NULL;
-    switch (nodeId->identifierType) {
-        /* for all the lengths below we add the constant for: */
-        /* strlen("ns=XXXXXX;i=")=11 */
-        case UA_NODEIDTYPE_NUMERIC:
-            /* ns (2 byte, 65535) = 5 chars, numeric (4 byte, 4294967295) = 10 chars, delim = 1 , nullbyte = 1-> 17 chars */
-            nodeIdStr->length = 11 + 10 + 1;
-            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
-            if (nodeIdStr->data == NULL)
-                return UA_STATUSCODE_BADOUTOFMEMORY;
-            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;i=%lu",
-                        nodeId->namespaceIndex, (unsigned long )nodeId->identifier.numeric);
-            break;
-        case UA_NODEIDTYPE_STRING:
-            /* ns (16bit) = 5 chars, strlen + nullbyte */
-            nodeIdStr->length = 11 + nodeId->identifier.string.length + 1;
-            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
-            if (nodeIdStr->data == NULL)
-                return UA_STATUSCODE_BADOUTOFMEMORY;
-            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;i=%.*s", nodeId->namespaceIndex,
-                        (int)nodeId->identifier.string.length, nodeId->identifier.string.data);
-            break;
-        case UA_NODEIDTYPE_GUID:
-            /* ns (16bit) = 5 chars + strlen(A123456C-0ABC-1A2B-815F-687212AAEE1B)=36 + nullbyte */
-            nodeIdStr->length = 11 + 36 + 1;
-            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
-            if (nodeIdStr->data == NULL)
-                return UA_STATUSCODE_BADOUTOFMEMORY;
-            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;i=" UA_PRINTF_GUID_FORMAT,
-                        nodeId->namespaceIndex, UA_PRINTF_GUID_DATA(nodeId->identifier.guid));
-            break;
-        case UA_NODEIDTYPE_BYTESTRING:
-            UA_ByteString_toString(&nodeId->identifier.byteString, &byteStr);
-            /* ns (16bit) = 5 chars + LEN + nullbyte */
-            nodeIdStr->length = 11 + byteStr.length + 1;
-            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
-            if (nodeIdStr->data == NULL)
-                return UA_STATUSCODE_BADOUTOFMEMORY;
-            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;i=%.*s", nodeId->namespaceIndex, (int)byteStr.length, byteStr.data);
-            UA_String_deleteMembers(&byteStr);
-            break;
-    }
-    return UA_STATUSCODE_GOOD;
-}
-
 
 #ifdef __cplusplus
 } // extern "C"

+ 0 - 23
include/ua_plugin_network.h

@@ -201,29 +201,6 @@ typedef UA_Connection
 (*UA_ConnectClientConnection)(UA_ConnectionConfig localConf, const char *endpointUrl,
                               const UA_UInt32 timeout, UA_Logger logger);
 
-/**
- * Endpoint URL Parser
- * -------------------
- * The endpoint URL parser is generally useful for the implementation of network
- * layer plugins. */
-
-/* Split the given endpoint url into hostname, port and path. All arguments must
- * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port
- * and path may be omitted (together with the prefix colon and slash).
- *
- * @param endpointUrl The endpoint URL.
- * @param outHostname Set to the parsed hostname. The string points into the
- *        original endpointUrl, so no memory is allocated. If an IPv6 address is
- *        given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]'
- * @param outPort Set to the port of the url or left unchanged.
- * @param outPath Set to the path if one is present in the endpointUrl.
- *        Starting or trailing '/' are NOT included in the path. The string
- *        points into the original endpointUrl, so no memory is allocated.
- * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */
-UA_StatusCode UA_EXPORT
-UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
-                    UA_UInt16 *outPort, UA_String *outPath);
-
 #ifdef __cplusplus
 } // extern "C"
 #endif

+ 94 - 0
include/ua_util.h

@@ -0,0 +1,94 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *    Copyright 2018 (c) Stefan Profanter, fortiss GmbH
+ */
+
+
+#ifndef UA_HELPER_H_
+#define UA_HELPER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ua_config.h"
+#include "ua_types.h"
+
+/**
+* Endpoint URL Parser
+* -------------------
+* The endpoint URL parser is generally useful for the implementation of network
+* layer plugins. */
+
+/* Split the given endpoint url into hostname, port and path. All arguments must
+ * be non-NULL. EndpointUrls have the form "opc.tcp://hostname:port/path", port
+ * and path may be omitted (together with the prefix colon and slash).
+ *
+ * @param endpointUrl The endpoint URL.
+ * @param outHostname Set to the parsed hostname. The string points into the
+ *        original endpointUrl, so no memory is allocated. If an IPv6 address is
+ *        given, hostname contains e.g. '[2001:0db8:85a3::8a2e:0370:7334]'
+ * @param outPort Set to the port of the url or left unchanged.
+ * @param outPath Set to the path if one is present in the endpointUrl.
+ *        Starting or trailing '/' are NOT included in the path. The string
+ *        points into the original endpointUrl, so no memory is allocated.
+ * @return Returns UA_STATUSCODE_BADTCPENDPOINTURLINVALID if parsing failed. */
+UA_StatusCode UA_EXPORT
+UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
+                    UA_UInt16 *outPort, UA_String *outPath);
+
+/**
+ * Convenience macros for complex types
+ * ------------------------------------ */
+#define UA_PRINTF_GUID_FORMAT "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x"
+#define UA_PRINTF_GUID_DATA(GUID) (GUID).data1, (GUID).data2, (GUID).data3, \
+        (GUID).data4[0], (GUID).data4[1], (GUID).data4[2], (GUID).data4[3], \
+        (GUID).data4[4], (GUID).data4[5], (GUID).data4[6], (GUID).data4[7]
+
+#define UA_PRINTF_STRING_FORMAT "\"%.*s\""
+#define UA_PRINTF_STRING_DATA(STRING) (int)(STRING).length, (STRING).data
+
+//TODO remove when we merge architectures pull request
+#ifndef UA_snprintf
+# include <stdio.h>
+# if defined(_WIN32)
+#  define UA_snprintf(source, size, string, ...) _snprintf_s(source, size, _TRUNCATE, string, __VA_ARGS__)
+# else
+#  define UA_snprintf snprintf
+# endif
+#endif
+
+/**
+ * Helper functions for converting data types
+ * ------------------------------------ */
+/*
+ * Converts a bytestring to the corresponding base64 encoded string representation.
+ *
+ * @param byteString the original byte string
+ * @param str the resulting base64 encoded byte string
+ *
+ * @return UA_STATUSCODE_GOOD on success.
+ */
+UA_StatusCode UA_EXPORT
+UA_ByteString_toBase64String(const UA_ByteString *byteString, UA_String *str);
+
+/*
+ * Converts a node id to the corresponding string representation.
+ * It can be one of:
+ * - Numeric: ns=0;i=123
+ * - String: ns=0;s=Some String
+ * - Guid: ns=0;g=A123456C-0ABC-1A2B-815F-687212AAEE1B
+ * - ByteString: ns=0;b=AA==
+ *
+ */
+UA_StatusCode UA_EXPORT
+UA_NodeId_toString(const UA_NodeId *nodeId, UA_String *nodeIdStr);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UA_HELPER_H_ */

+ 1 - 1
plugins/ua_debug_dump_pkgs.c

@@ -5,7 +5,7 @@
  *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
  */
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 
 #include <ctype.h>
 #include <stdio.h>

+ 1 - 0
plugins/ua_network_pubsub_udp.c

@@ -57,6 +57,7 @@
 #include <stdio.h>
 #include "ua_plugin_network.h"
 #include "ua_network_pubsub_udp.h"
+#include "ua_util.h"
 #include "ua_log_stdout.h"
 
 //UDP multicast network layer specific internal data

+ 1 - 0
plugins/ua_network_tcp.c

@@ -39,6 +39,7 @@
 #include "ua_network_tcp.h"
 #include "ua_log_stdout.h"
 #include "../deps/queue.h"
+#include "ua_util.h"
 
 #include <stdio.h> // snprintf
 #include <string.h> // memset

+ 1 - 1
plugins/ua_nodestore_default.c

@@ -8,7 +8,7 @@
 
 #include "ua_nodestore_default.h"
 
-#include "../src/ua_util.h" /* TOOO: Move atomic operations to arch definitions */
+#include "../src/ua_util_internal.h" /* TOOO: Move atomic operations to arch definitions */
 
 /* container_of */
 #define container_of(ptr, type, member) \

+ 1 - 1
src/server/ua_securechannel_manager.h

@@ -15,7 +15,7 @@
 extern "C" {
 #endif
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_server.h"
 #include "ua_securechannel.h"
 #include "../../deps/queue.h"

+ 1 - 1
src/server/ua_server_internal.h

@@ -18,7 +18,7 @@
 extern "C" {
 #endif
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_server.h"
 #include "ua_server_config.h"
 #include "ua_timer.h"

+ 1 - 0
src/server/ua_session.h

@@ -14,6 +14,7 @@ extern "C" {
 
 #include "../deps/queue.h"
 #include "ua_securechannel.h"
+#include "ua_util.h"
 
 #define UA_MAXCONTINUATIONPOINTS 5
 

+ 1 - 1
src/server/ua_session_manager.h

@@ -18,7 +18,7 @@ extern "C" {
 
 #include "../../deps/queue.h"
 #include "ua_server.h"
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_session.h"
 
 typedef struct session_list_entry {

+ 1 - 1
src/server/ua_subscription.h

@@ -14,7 +14,7 @@
 #ifndef UA_SUBSCRIPTION_H_
 #define UA_SUBSCRIPTION_H_
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_types.h"
 #include "ua_types_generated.h"
 #include "ua_session.h"

+ 1 - 1
src/ua_connection.c

@@ -10,7 +10,7 @@
  *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
  */
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_connection_internal.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_generated_encoding_binary.h"

+ 1 - 1
src/ua_securechannel.c

@@ -11,7 +11,7 @@
  *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
  */
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_securechannel.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_generated_encoding_binary.h"

+ 1 - 1
src/ua_timer.c

@@ -6,7 +6,7 @@
  *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
  */
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_timer.h"
 
 /* Only one thread operates on the repeated jobs. This is usually the "main"

+ 1 - 1
src/ua_timer.h

@@ -13,7 +13,7 @@
 extern "C" {
 #endif
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 
 /* An (event) timer triggers callbacks with a recurring interval. Adding,
  * removing and changing repeated callbacks can be done from independent

+ 1 - 1
src/ua_types.c

@@ -14,7 +14,7 @@
  *    Copyright 2016 (c) Lorenz Haas
  */
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_types.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated_handling.h"

+ 1 - 1
src/ua_types_encoding_binary.c

@@ -15,7 +15,7 @@
  *    Copyright 2017 (c) Henrik Norrman
  */
 
-#include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_types_encoding_binary.h"
 #include "ua_types_generated.h"
 #include "ua_types_generated_handling.h"

+ 79 - 0
src/ua_util.c

@@ -8,7 +8,9 @@
  */
 
 #include "ua_util.h"
+#include "ua_util_internal.h"
 #include "ua_plugin_network.h"
+#include "base64.h"
 
 size_t
 UA_readNumber(u8 *buf, size_t buflen, u32 *number) {
@@ -100,3 +102,80 @@ UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
 
     return UA_STATUSCODE_GOOD;
 }
+
+UA_StatusCode UA_ByteString_toBase64String(const UA_ByteString *byteString, UA_String *str) {
+    if (str->length != 0) {
+        UA_free(str->data);
+        str->data = NULL;
+        str->length = 0;
+    }
+    if (byteString == NULL || byteString->data == NULL)
+        return UA_STATUSCODE_GOOD;
+    if (byteString == str)
+        return UA_STATUSCODE_BADINVALIDARGUMENT;
+
+    int resSize = 0;
+    str->data = (UA_Byte*)UA_base64(byteString->data, (int)byteString->length, &resSize);
+    str->length = (size_t) resSize;
+    if (str->data == NULL)
+        return UA_STATUSCODE_BADOUTOFMEMORY;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+UA_StatusCode
+UA_NodeId_toString(const UA_NodeId *nodeId, UA_String *nodeIdStr) {
+    if (nodeIdStr->length != 0) {
+        UA_free(nodeIdStr->data);
+        nodeIdStr->data = NULL;
+        nodeIdStr->length = 0;
+    }
+    if (nodeId == NULL)
+        return UA_STATUSCODE_GOOD;
+
+
+    UA_ByteString byteStr = UA_BYTESTRING_NULL;
+    switch (nodeId->identifierType) {
+        /* for all the lengths below we add the constant for: */
+        /* strlen("ns=XXXXXX;i=")=11 */
+        case UA_NODEIDTYPE_NUMERIC:
+            /* ns (2 byte, 65535) = 5 chars, numeric (4 byte, 4294967295) = 10 chars, delim = 1 , nullbyte = 1-> 17 chars */
+            nodeIdStr->length = 11 + 10 + 1;
+            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
+            if (nodeIdStr->data == NULL)
+                return UA_STATUSCODE_BADOUTOFMEMORY;
+            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;i=%lu",
+                        nodeId->namespaceIndex, (unsigned long )nodeId->identifier.numeric);
+            break;
+        case UA_NODEIDTYPE_STRING:
+            /* ns (16bit) = 5 chars, strlen + nullbyte */
+            nodeIdStr->length = 11 + nodeId->identifier.string.length + 1;
+            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
+            if (nodeIdStr->data == NULL)
+                return UA_STATUSCODE_BADOUTOFMEMORY;
+            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;s=%.*s", nodeId->namespaceIndex,
+                        (int)nodeId->identifier.string.length, nodeId->identifier.string.data);
+            break;
+        case UA_NODEIDTYPE_GUID:
+            /* ns (16bit) = 5 chars + strlen(A123456C-0ABC-1A2B-815F-687212AAEE1B)=36 + nullbyte */
+            nodeIdStr->length = 11 + 36 + 1;
+            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
+            if (nodeIdStr->data == NULL)
+                return UA_STATUSCODE_BADOUTOFMEMORY;
+            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;g=" UA_PRINTF_GUID_FORMAT,
+        nodeId->namespaceIndex, UA_PRINTF_GUID_DATA(nodeId->identifier.guid));
+            break;
+        case UA_NODEIDTYPE_BYTESTRING:
+            UA_ByteString_toBase64String(&nodeId->identifier.byteString, &byteStr);
+            /* ns (16bit) = 5 chars + LEN + nullbyte */
+            nodeIdStr->length = 11 + byteStr.length + 1;
+            nodeIdStr->data = (UA_Byte*)UA_malloc(nodeIdStr->length);
+            if (nodeIdStr->data == NULL)
+                return UA_STATUSCODE_BADOUTOFMEMORY;
+            UA_snprintf((char*)nodeIdStr->data, nodeIdStr->length, "ns=%d;b=%.*s", nodeId->namespaceIndex, (int)byteStr.length, byteStr.data);
+            UA_String_deleteMembers(&byteStr);
+            break;
+    }
+    return UA_STATUSCODE_GOOD;
+}
+

src/ua_util.h → src/ua_util_internal.h


+ 18 - 8
tests/check_utils.c

@@ -7,6 +7,7 @@
 #include "ua_types.h"
 #include "ua_client.h"
 #include "ua_util.h"
+#include "ua_util_internal.h"
 #include "check.h"
 
 START_TEST(EndpointUrl_split) {
@@ -191,11 +192,11 @@ START_TEST(idToStringString) {
 
     n = UA_NODEID_STRING(0,"");
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=0;i=");
+    assertNodeIdString(&str, "ns=0;s=");
 
     n = UA_NODEID_STRING(54321,"Some String");
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=54321;i=Some String");
+    assertNodeIdString(&str, "ns=54321;s=Some String");
 
     UA_String_deleteMembers(&str);
 } END_TEST
@@ -208,7 +209,7 @@ START_TEST(idToStringGuid) {
 
     n = UA_NODEID_GUID(0,UA_GUID_NULL);
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=0;i=00000000-0000-0000-0000-000000000000");
+    assertNodeIdString(&str, "ns=0;g=00000000-0000-0000-0000-000000000000");
 
     g.data1 = 0xA123456C;
     g.data2 = 0x0ABC;
@@ -224,7 +225,7 @@ START_TEST(idToStringGuid) {
 
     n = UA_NODEID_GUID(65535,g);
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=65535;i=a123456c-0abc-1a2b-815f-687212aaee1b");
+    assertNodeIdString(&str, "ns=65535;g=a123456c-0abc-1a2b-815f-687212aaee1b");
 
     g.data1 = 0xFFFFFFFF;
     g.data2 = 0xFFFF;
@@ -240,7 +241,7 @@ START_TEST(idToStringGuid) {
 
     n = UA_NODEID_GUID(65535,g);
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=65535;i=ffffffff-ffff-ffff-ffff-ffffffffffff");
+    assertNodeIdString(&str, "ns=65535;g=ffffffff-ffff-ffff-ffff-ffffffffffff");
 
     UA_String_deleteMembers(&str);
 } END_TEST
@@ -254,17 +255,26 @@ START_TEST(idToStringByte) {
     n.identifier.byteString.data = NULL;
     n.identifier.byteString.length = 0;
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=0;i=");
+    assertNodeIdString(&str, "ns=0;b=");
 
     UA_ByteString bs = UA_BYTESTRING_NULL;
 
+    bs.length = 1;
+    bs.data = (UA_Byte*)UA_malloc(bs.length);
+    bs.data[0] = 0x00;
+    n.identifier.byteString = bs;
+    n.namespaceIndex = 123;
+    UA_NodeId_toString(&n, &str);
+    assertNodeIdString(&str, "ns=123;b=AA==");
+    UA_free(bs.data);
+
     bs.length = 1;
     bs.data = (UA_Byte*)UA_malloc(bs.length);
     bs.data[0] = 0x2C;
     n.identifier.byteString = bs;
     n.namespaceIndex = 123;
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=123;i=2c");
+    assertNodeIdString(&str, "ns=123;b=LA==");
     UA_free(bs.data);
 
     bs.length = 5;
@@ -277,7 +287,7 @@ START_TEST(idToStringByte) {
     n.identifier.byteString = bs;
     n.namespaceIndex = 599;
     UA_NodeId_toString(&n, &str);
-    assertNodeIdString(&str, "ns=599;i=2183e05478");
+    assertNodeIdString(&str, "ns=599;b=IYPgVHg=");
     UA_free(bs.data);
 
     UA_String_deleteMembers(&str);