summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSachin Agrawal <sachin.agrawal@intel.com>2015-10-08 09:20:54 -0700
committerYoungjae Shin <yj99.shin@samsung.com>2016-01-15 13:26:13 +0900
commitd38beaea16946810ff07a4bdd3b3bca67127d460 (patch)
tree8a86562aa2726b7434e3a4ed33bc906f1afad4ed
parentf85d7e7587daa4ddb99f5aa2bdb6bde5a999e5d9 (diff)
downloadiotivity-d38beaea16946810ff07a4bdd3b3bca67127d460.tar.gz
iotivity-d38beaea16946810ff07a4bdd3b3bca67127d460.tar.bz2
iotivity-d38beaea16946810ff07a4bdd3b3bca67127d460.zip
Currently byte strings in CBOR wrapper are achieved by using int arrays. Drawbacks with this approach is in-efficient memory consumption and 3rd Party tools cannot properly decode the CBOR generated in this fashion. Updated code in CBOR wrapper and also added unit tests. Change-Id: I4ed1adc891be84e800c833df404914a335150ded Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com> Reviewed-on: https://gerrit.iotivity.org/gerrit/2337 Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
-rw-r--r--resource/csdk/stack/include/payload_logging.h10
-rw-r--r--resource/csdk/stack/src/ocpayloadconvert.c11
-rw-r--r--resource/csdk/stack/src/ocpayloadparse.c31
-rw-r--r--resource/csdk/stack/test/SConscript3
-rw-r--r--resource/csdk/stack/test/cbortests.cpp222
5 files changed, 276 insertions, 1 deletions
diff --git a/resource/csdk/stack/include/payload_logging.h b/resource/csdk/stack/include/payload_logging.h
index 4c4dfbbae..69cb45f7b 100644
--- a/resource/csdk/stack/include/payload_logging.h
+++ b/resource/csdk/stack/include/payload_logging.h
@@ -91,6 +91,10 @@ static inline void OCPayloadLogRep(LogLevel level, OCRepPayload* payload)
case OCREP_PROP_STRING:
OC_LOG_V(level, PL_TAG, "\t\t%s(string):%s", val->name, val->str);
break;
+ case OCREP_PROP_BYTE_STRING:
+ OC_LOG_V(level, PL_TAG, "\t\t%s(binary):", val->name);
+ OC_LOG_BUFFER(level, PL_TAG, val->ocByteStr.bytes, val->ocByteStr.len);
+ break;
case OCREP_PROP_OBJECT:
// Note: Only prints the URI (if available), to print further, you'll
// need to dig into the object better!
@@ -123,6 +127,12 @@ static inline void OCPayloadLogRep(LogLevel level, OCRepPayload* payload)
val->arr.dimensions[0], val->arr.dimensions[1],
val->arr.dimensions[2]);
break;
+ case OCREP_PROP_BYTE_STRING:
+ OC_LOG_V(level, PL_TAG, "\t\t%s(byte array):%lld x %lld x %lld",
+ val->name,
+ val->arr.dimensions[0], val->arr.dimensions[1],
+ val->arr.dimensions[2]);
+ break;
case OCREP_PROP_OBJECT:
OC_LOG_V(level, PL_TAG, "\t\t%s(OCRep array):%lld x %lld x %lld",
val->name,
diff --git a/resource/csdk/stack/src/ocpayloadconvert.c b/resource/csdk/stack/src/ocpayloadconvert.c
index 7b46b36da..85a36ce76 100644
--- a/resource/csdk/stack/src/ocpayloadconvert.c
+++ b/resource/csdk/stack/src/ocpayloadconvert.c
@@ -560,6 +560,17 @@ static int64_t OCConvertArrayItem(CborEncoder* array, const OCRepPayloadValueArr
strlen(valArray->strArray[index]));
}
break;
+ case OCREP_PROP_BYTE_STRING:
+ if (!valArray->strArray[index])
+ {
+ err = err | cbor_encode_null(array);
+ }
+ else
+ {
+ err = err | cbor_encode_byte_string(array, valArray->ocByteStrArray[index].bytes,
+ valArray->ocByteStrArray[index].len);
+ }
+ break;
case OCREP_PROP_OBJECT:
if (!valArray->objArray[index])
{
diff --git a/resource/csdk/stack/src/ocpayloadparse.c b/resource/csdk/stack/src/ocpayloadparse.c
index 4dc71ee22..c045e14e4 100644
--- a/resource/csdk/stack/src/ocpayloadparse.c
+++ b/resource/csdk/stack/src/ocpayloadparse.c
@@ -614,6 +614,8 @@ static OCRepPayloadPropType DecodeCborType(CborType type)
return OCREP_PROP_BOOL;
case CborTextStringType:
return OCREP_PROP_STRING;
+ case CborByteStringType:
+ return OCREP_PROP_BYTE_STRING;
case CborMapType:
return OCREP_PROP_OBJECT;
case CborArrayType:
@@ -694,6 +696,8 @@ static size_t getAllocSize(OCRepPayloadPropType type)
return sizeof (bool);
case OCREP_PROP_STRING:
return sizeof (char*);
+ case OCREP_PROP_BYTE_STRING:
+ return sizeof (OCByteString);
case OCREP_PROP_OBJECT:
return sizeof (OCRepPayload*);
default:
@@ -719,6 +723,7 @@ static bool OCParseArrayFillArray(const CborValue* parent, size_t dimensions[MAX
size_t i = 0;
char* tempStr = NULL;
+ OCByteString ocByteStr = { .bytes = NULL, .len = 0};
size_t tempLen = 0;
OCRepPayload* tempPl = NULL;
@@ -792,6 +797,21 @@ static bool OCParseArrayFillArray(const CborValue* parent, size_t dimensions[MAX
);
}
break;
+ case OCREP_PROP_BYTE_STRING:
+ if (dimensions[1] == 0)
+ {
+ err = err || cbor_value_dup_byte_string(&insideArray,
+ &(ocByteStr.bytes), &(ocByteStr.len), NULL);
+ ((OCByteString*)targetArray)[i] = ocByteStr;
+ }
+ else
+ {
+ err = err || OCParseArrayFillArray(&insideArray, newdim,
+ type,
+ &(((OCByteString*)targetArray)[arrayStep(dimensions, i)])
+ );
+ }
+ break;
case OCREP_PROP_OBJECT:
if (dimensions[1] == 0)
{
@@ -889,6 +909,17 @@ static bool OCParseArray(OCRepPayload* out, const char* name, CborValue* contain
err = true;
}
break;
+ case OCREP_PROP_BYTE_STRING:
+ if (err || !OCRepPayloadSetByteStringArrayAsOwner(out, name, (OCByteString*)arr, dimensions))
+ {
+ for (size_t i = 0; i < dimTotal; ++i)
+ {
+ OICFree(((OCByteString*)arr)[i].bytes);
+ }
+ OICFree(arr);
+ err = true;
+ }
+ break;
case OCREP_PROP_OBJECT:
if (err || !OCRepPayloadSetPropObjectArrayAsOwner(out, name, (OCRepPayload**)arr, dimensions))
{
diff --git a/resource/csdk/stack/test/SConscript b/resource/csdk/stack/test/SConscript
index d75d459b0..507f011f5 100644
--- a/resource/csdk/stack/test/SConscript
+++ b/resource/csdk/stack/test/SConscript
@@ -69,8 +69,9 @@ if env.get('LOGGING'):
# Source files and Targets
######################################################################
stacktests = stacktest_env.Program('stacktests', ['stacktests.cpp'])
+cbortests = stacktest_env.Program('cbortests', ['cbortests.cpp'])
-Alias("test", [stacktests])
+Alias("test", [stacktests, cbortests])
env.AppendTarget('test')
if env.get('TEST') == '1':
diff --git a/resource/csdk/stack/test/cbortests.cpp b/resource/csdk/stack/test/cbortests.cpp
new file mode 100644
index 000000000..2e4a20249
--- /dev/null
+++ b/resource/csdk/stack/test/cbortests.cpp
@@ -0,0 +1,222 @@
+//******************************************************************
+//
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+
+extern "C"
+{
+ #include "ocstack.h"
+ #include "ocpayload.h"
+ #include "ocpayloadcbor.h"
+ #include "logger.h"
+ #include "oic_malloc.h"
+}
+
+#include "gtest/gtest.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+//-----------------------------------------------------------------------------
+// Includes
+//-----------------------------------------------------------------------------
+#include <stdio.h>
+#include <string.h>
+
+#include <iostream>
+#include <stdint.h>
+
+#include "gtest_helper.h"
+
+class CborByteStringTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ // Create Payload
+ payload_in = OCRepPayloadCreate();
+ ASSERT_TRUE(payload_in != NULL);
+ }
+
+ virtual void TearDown() {
+ OCPayloadDestroy((OCPayload*)payload_in);
+ }
+
+ OCRepPayload* payload_in;
+};
+
+TEST_F(CborByteStringTest, ByteStringSetGetTest)
+{
+ OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+ OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+ uint8_t binval[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0xA, 0xB, 0xC,
+ 0xD, 0xE, 0xF};
+ OCByteString quakedata_in = { binval, sizeof(binval)};
+
+ EXPECT_EQ(true, OCRepPayloadSetPropByteString(payload_in, "quakedata", quakedata_in));
+
+ OCByteString quakedata_out = { NULL, 0};
+ ASSERT_EQ(true, OCRepPayloadGetPropByteString(payload_in, "quakedata", &quakedata_out));
+
+ EXPECT_EQ(quakedata_in.len, quakedata_out.len);
+ EXPECT_EQ(0, memcmp(quakedata_in.bytes, quakedata_out.bytes, quakedata_in.len));
+
+ // Cleanup
+ OICFree(quakedata_out.bytes);
+}
+
+TEST_F(CborByteStringTest, ByteStringConvertParseTest)
+{
+ OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+ OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+ uint8_t binval[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0x0, 0xA, 0xB, 0xC,
+ 0xD, 0xE, 0xF};
+ OCByteString quakedata_in = { binval, sizeof(binval)};
+
+ // Set ByteString in Payload
+ EXPECT_EQ(true, OCRepPayloadSetPropByteString(payload_in, "quakedata", quakedata_in));
+
+ // Convert OCPayload to CBOR
+ uint8_t *payload_cbor = NULL;
+ size_t payload_cbor_size = 0;
+ EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*) payload_in, &payload_cbor, &payload_cbor_size));
+
+#ifdef CBOR_BIN_STRING_DEBUG
+ FILE *fp = fopen("binstring.cbor", "wb+");
+ if (fp)
+ {
+ fwrite(payload_cbor, 1, payload_cbor_size, fp);
+ fclose(fp);
+ }
+#endif //CBOR_BIN_STRING_DEBUG
+
+ // Parse CBOR back to OCPayload
+ OCPayload* payload_out = NULL;
+ EXPECT_EQ(OC_STACK_OK, OCParsePayload(&payload_out, PAYLOAD_TYPE_REPRESENTATION,
+ payload_cbor, payload_cbor_size));
+
+ OCByteString quakedata_out = {NULL, 0};
+ ASSERT_EQ(true, OCRepPayloadGetPropByteString((OCRepPayload*)payload_out, "quakedata", &quakedata_out));
+
+ // Compare input and output data
+ EXPECT_EQ(quakedata_in.len, quakedata_out.len);
+ EXPECT_EQ(0, memcmp(quakedata_in.bytes, quakedata_out.bytes, quakedata_in.len));
+
+ // Cleanup
+ OICFree(payload_cbor);
+ OICFree(quakedata_out.bytes);
+ OCPayloadDestroy((OCPayload*)payload_out);
+}
+
+TEST_F(CborByteStringTest, ByteStringArraySetGetTest )
+{
+ OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+ OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+ size_t dimensions_in[MAX_REP_ARRAY_DEPTH] = { 3, 0, 0};
+ uint8_t binval1[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19};
+ uint8_t binval2[] = {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
+ uint8_t binval3[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
+
+ OCByteString quakedata_in[3] = {{binval1, sizeof(binval1)},
+ {binval2, sizeof(binval2)},
+ {binval3, sizeof(binval3)}};
+
+ EXPECT_EQ(true, OCRepPayloadSetByteStringArray(payload_in, "quakedata",
+ quakedata_in, dimensions_in));
+
+ OCByteString* quakedata_out = NULL;
+ size_t dimensions_out[MAX_REP_ARRAY_DEPTH] = {0};
+ ASSERT_EQ(true, OCRepPayloadGetByteStringArray(payload_in, "quakedata",
+ &quakedata_out, dimensions_out));
+
+ for(size_t i = 0; i < dimensions_in[0]; i++)
+ {
+ EXPECT_EQ(quakedata_in[i].len, quakedata_out[i].len);
+ EXPECT_EQ(0, memcmp(quakedata_in[i].bytes, quakedata_out[i].bytes, quakedata_in[i].len));
+ }
+
+ // Cleanup
+ for(size_t i = 0; i < dimensions_out[0]; i++)
+ {
+ OICFree(quakedata_out[i].bytes);
+ }
+ OICFree(quakedata_out);
+}
+
+
+TEST_F(CborByteStringTest, ByteStringArrayConvertParseTest )
+{
+ OCRepPayloadSetUri(payload_in, "/a/quake_sensor");
+ OCRepPayloadSetPropInt(payload_in, "scale", 4);
+
+ size_t dimensions_in[MAX_REP_ARRAY_DEPTH] = { 3, 0, 0};
+ uint8_t binval1[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19};
+ uint8_t binval2[] = {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29};
+ uint8_t binval3[] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
+
+ OCByteString quakedata_in[3] = {{binval1, sizeof(binval1)},
+ {binval2, sizeof(binval2)},
+ {binval3, sizeof(binval3)}};
+
+ EXPECT_EQ(true, OCRepPayloadSetByteStringArray(payload_in, "quakedata",
+ quakedata_in, dimensions_in));
+
+ // Convert OCPayload to CBOR
+ uint8_t *payload_cbor = NULL;
+ size_t payload_cbor_size = 0;
+ EXPECT_EQ(OC_STACK_OK, OCConvertPayload((OCPayload*) payload_in, &payload_cbor, &payload_cbor_size));
+#ifdef CBOR_BIN_STRING_DEBUG
+ FILE *fp = fopen("binstringarr.cbor", "wb+");
+ if (fp)
+ {
+ fwrite(payload_cbor, 1, payload_cbor_size, fp);
+ fclose(fp);
+ }
+#endif //CBOR_BIN_STRING_DEBUG
+
+ // Parse CBOR back to OCPayload
+ OCPayload* payload_out = NULL;
+ EXPECT_EQ(OC_STACK_OK, OCParsePayload(&payload_out, PAYLOAD_TYPE_REPRESENTATION,
+ payload_cbor, payload_cbor_size));
+
+ OCByteString* quakedata_out = NULL;
+ size_t dimensions_out[MAX_REP_ARRAY_DEPTH] = {0};
+ ASSERT_EQ(true, OCRepPayloadGetByteStringArray((OCRepPayload*)payload_out, "quakedata",
+ &quakedata_out, dimensions_out));
+
+ for(size_t i = 0; i < dimensions_in[0]; i++)
+ {
+ EXPECT_EQ(quakedata_in[i].len, quakedata_out[i].len);
+ EXPECT_EQ(0, memcmp(quakedata_in[i].bytes, quakedata_out[i].bytes, quakedata_in[i].len));
+ }
+
+ // Cleanup
+ OICFree(payload_cbor);
+ for(size_t i = 0; i < dimensions_out[0]; i++)
+ {
+ OICFree(quakedata_out[i].bytes);
+ }
+ OICFree(quakedata_out);
+
+ OCPayloadDestroy((OCPayload*)payload_out);
+}