From 49705576d8779e3fa2b3efc4294bc03261f76935 Mon Sep 17 00:00:00 2001 From: Francis Deslauriers Date: Fri, 20 Mar 2020 12:12:30 -0400 Subject: [PATCH] Add `libmsgpack` for serializing captures Signed-off-by: Francis Deslauriers Signed-off-by: Mathieu Desnoyers Change-Id: Ice8ed791a0452ea9e659ffcaf9e081f47288e8d5 --- Makefile.am | 1 + configure.ac | 2 + libmsgpack/Makefile.am | 9 + libmsgpack/msgpack.c | 517 +++++++++++++++++++++++++++ libmsgpack/msgpack.h | 61 ++++ tests/Makefile.am | 1 + tests/unit/Makefile.am | 1 + tests/unit/libmsgpack/Makefile.am | 9 + tests/unit/libmsgpack/test_msgpack.c | 386 ++++++++++++++++++++ 9 files changed, 987 insertions(+) create mode 100644 libmsgpack/Makefile.am create mode 100644 libmsgpack/msgpack.c create mode 100644 libmsgpack/msgpack.h create mode 100644 tests/unit/libmsgpack/Makefile.am create mode 100644 tests/unit/libmsgpack/test_msgpack.c diff --git a/Makefile.am b/Makefile.am index cc923c1d..a13c6e31 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = . include snprintf libringbuffer liblttng-ust-comm \ + libmsgpack \ liblttng-ust \ liblttng-ust-ctl \ liblttng-ust-fd \ diff --git a/configure.ac b/configure.ac index 14f297de..032bb731 100644 --- a/configure.ac +++ b/configure.ac @@ -504,6 +504,7 @@ AC_CONFIG_FILES([ include/Makefile include/lttng/ust-version.h snprintf/Makefile + libmsgpack/Makefile libringbuffer/Makefile liblttng-ust-comm/Makefile liblttng-ust/Makefile @@ -539,6 +540,7 @@ AC_CONFIG_FILES([ tests/compile/test-app-ctx/Makefile tests/benchmark/Makefile tests/unit/gcc-weak-hidden/Makefile + tests/unit/libmsgpack/Makefile tests/unit/Makefile tests/unit/libringbuffer/Makefile tests/unit/pthread_name/Makefile diff --git a/libmsgpack/Makefile.am b/libmsgpack/Makefile.am new file mode 100644 index 00000000..b157e674 --- /dev/null +++ b/libmsgpack/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include +AM_CFLAGS += -fno-strict-aliasing + +noinst_LTLIBRARIES = libmsgpack.la + +libmsgpack_la_SOURCES = \ + msgpack.c msgpack.h + +libmsgpack_la_CFLAGS = -DUST_COMPONENT="libmsgpack" $(AM_CFLAGS) diff --git a/libmsgpack/msgpack.c b/libmsgpack/msgpack.c new file mode 100644 index 00000000..0803bc65 --- /dev/null +++ b/libmsgpack/msgpack.c @@ -0,0 +1,517 @@ +/* + * msgpack.c + * + * Copyright (C) 2020 Francis Deslauriers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#define _LGPL_SOURCE +#include + +#define MSGPACK_FIXSTR_ID_MASK 0xA0 +#define MSGPACK_FIXMAP_ID_MASK 0x80 +#define MSGPACK_FIXARRAY_ID_MASK 0x90 + +#define MSGPACK_NIL_ID 0xC0 +#define MSGPACK_FALSE_ID 0xC2 +#define MSGPACK_TRUE_ID 0xC3 +#define MSGPACK_MAP16_ID 0xDE +#define MSGPACK_ARRAY16_ID 0xDC + +#define MSGPACK_UINT8_ID 0xCC +#define MSGPACK_UINT16_ID 0xCD +#define MSGPACK_UINT32_ID 0xCE +#define MSGPACK_UINT64_ID 0xCF + +#define MSGPACK_INT8_ID 0xD0 +#define MSGPACK_INT16_ID 0xD1 +#define MSGPACK_INT32_ID 0xD2 +#define MSGPACK_INT64_ID 0xD3 + +#define MSGPACK_FLOAT64_ID 0xCB +#define MSGPACK_STR16_ID 0xDA + +#define MSGPACK_FIXINT_MAX ((1 << 7) - 1) +#define MSGPACK_FIXINT_MIN -(1 << 5) +#define MSGPACK_FIXMAP_MAX_COUNT 15 +#define MSGPACK_FIXARRAY_MAX_COUNT 15 +#define MSGPACK_FIXSTR_MAX_LENGTH 31 + +#ifdef __KERNEL__ +#include +#include +#include + +#include + +#define INT8_MIN (-128) +#define INT16_MIN (-32767-1) +#define INT32_MIN (-2147483647-1) +#define INT8_MAX (127) +#define INT16_MAX (32767) +#define INT32_MAX (2147483647) +#define UINT8_MAX (255) +#define UINT16_MAX (65535) +#define UINT32_MAX (4294967295U) + +#define byteswap_host_to_be16(_tmp) cpu_to_be16(_tmp) +#define byteswap_host_to_be32(_tmp) cpu_to_be32(_tmp) +#define byteswap_host_to_be64(_tmp) cpu_to_be64(_tmp) + +#define lttng_msgpack_assert(cond) WARN_ON(!(cond)) + +#else /* __KERNEL__ */ + +#include +#include +#include + +#include "msgpack.h" + +#define byteswap_host_to_be16(_tmp) htobe16(_tmp) +#define byteswap_host_to_be32(_tmp) htobe32(_tmp) +#define byteswap_host_to_be64(_tmp) htobe64(_tmp) + +#define lttng_msgpack_assert(cond) ({ \ + if (!(cond)) \ + fprintf(stderr, "Assertion failed. %s:%d\n", __FILE__, __LINE__); \ + }) +#endif /* __KERNEL__ */ + +static inline int lttng_msgpack_append_buffer( + struct lttng_msgpack_writer *writer, + const uint8_t *buf, + size_t length) +{ + int ret = 0; + + lttng_msgpack_assert(buf); + + /* Ensure we are not trying to write after the end of the buffer. */ + if (writer->write_pos + length > writer->end_write_pos) { + ret = -1; + goto end; + } + + memcpy(writer->write_pos, buf, length); + writer->write_pos += length; +end: + return ret; +} + +static inline int lttng_msgpack_append_u8( + struct lttng_msgpack_writer *writer, uint8_t value) +{ + return lttng_msgpack_append_buffer(writer, &value, sizeof(value)); +} + +static inline int lttng_msgpack_append_u16( + struct lttng_msgpack_writer *writer, uint16_t value) +{ + value = byteswap_host_to_be16(value); + + return lttng_msgpack_append_buffer(writer, (uint8_t *) &value, sizeof(value)); +} + +static inline int lttng_msgpack_append_u32( + struct lttng_msgpack_writer *writer, uint32_t value) +{ + value = byteswap_host_to_be32(value); + + return lttng_msgpack_append_buffer(writer, (uint8_t *) &value, sizeof(value)); +} + +static inline int lttng_msgpack_append_u64( + struct lttng_msgpack_writer *writer, uint64_t value) +{ + value = byteswap_host_to_be64(value); + + return lttng_msgpack_append_buffer(writer, (uint8_t *) &value, sizeof(value)); +} + +static inline int lttng_msgpack_append_f64( + struct lttng_msgpack_writer *writer, double value) +{ + + union { + double d; + uint64_t u; + } u; + + u.d = value; + + return lttng_msgpack_append_u64(writer, u.u); +} + +static inline int lttng_msgpack_append_i8( + struct lttng_msgpack_writer *writer, int8_t value) +{ + return lttng_msgpack_append_u8(writer, (uint8_t) value); +} + +static inline int lttng_msgpack_append_i16( + struct lttng_msgpack_writer *writer, int16_t value) +{ + return lttng_msgpack_append_u16(writer, (uint16_t) value); +} + +static inline int lttng_msgpack_append_i32( + struct lttng_msgpack_writer *writer, int32_t value) +{ + return lttng_msgpack_append_u32(writer, (uint32_t) value); +} + +static inline int lttng_msgpack_append_i64( + struct lttng_msgpack_writer *writer, int64_t value) +{ + return lttng_msgpack_append_u64(writer, (uint64_t) value); +} + +static inline int lttng_msgpack_encode_f64( + struct lttng_msgpack_writer *writer, double value) +{ + int ret; + + ret = lttng_msgpack_append_u8(writer, MSGPACK_FLOAT64_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_f64(writer, value); + if (ret) + goto end; + +end: + return ret; +} + +static inline int lttng_msgpack_encode_fixmap( + struct lttng_msgpack_writer *writer, uint8_t count) +{ + int ret = 0; + + lttng_msgpack_assert(count <= MSGPACK_FIXMAP_MAX_COUNT); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_FIXMAP_ID_MASK | count); + if (ret) + goto end; + +end: + return ret; +} + +static inline int lttng_msgpack_encode_map16( + struct lttng_msgpack_writer *writer, uint16_t count) +{ + int ret; + + lttng_msgpack_assert(count > MSGPACK_FIXMAP_MAX_COUNT); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_MAP16_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u16(writer, count); + if (ret) + goto end; + +end: + return ret; +} + +static inline int lttng_msgpack_encode_fixarray( + struct lttng_msgpack_writer *writer, uint8_t count) +{ + int ret = 0; + + lttng_msgpack_assert(count <= MSGPACK_FIXARRAY_MAX_COUNT); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_FIXARRAY_ID_MASK | count); + if (ret) + goto end; + +end: + return ret; +} + +static inline int lttng_msgpack_encode_array16( + struct lttng_msgpack_writer *writer, uint16_t count) +{ + int ret; + + lttng_msgpack_assert(count > MSGPACK_FIXARRAY_MAX_COUNT); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_ARRAY16_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u16(writer, count); + if (ret) + goto end; + +end: + return ret; +} + +static inline int lttng_msgpack_encode_fixstr( + struct lttng_msgpack_writer *writer, + const char *str, + uint8_t len) +{ + int ret; + + lttng_msgpack_assert(len <= MSGPACK_FIXSTR_MAX_LENGTH); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_FIXSTR_ID_MASK | len); + if (ret) + goto end; + + ret = lttng_msgpack_append_buffer(writer, (uint8_t *) str, len); + if (ret) + goto end; + +end: + return ret; +} + +static inline int lttng_msgpack_encode_str16( + struct lttng_msgpack_writer *writer, + const char *str, + uint16_t len) +{ + int ret; + + lttng_msgpack_assert(len > MSGPACK_FIXSTR_MAX_LENGTH); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_STR16_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u16(writer, len); + if (ret) + goto end; + + ret = lttng_msgpack_append_buffer(writer, (uint8_t *) str, len); + if (ret) + goto end; + +end: + return ret; +} + +int lttng_msgpack_begin_map(struct lttng_msgpack_writer *writer, size_t count) +{ + int ret; + + if (count < 0 || count >= (1 << 16)) { + ret = -1; + goto end; + } + + if (count <= MSGPACK_FIXMAP_MAX_COUNT) + ret = lttng_msgpack_encode_fixmap(writer, count); + else + ret = lttng_msgpack_encode_map16(writer, count); + + writer->map_nesting++; +end: + return ret; +} + +int lttng_msgpack_end_map(struct lttng_msgpack_writer *writer) +{ + lttng_msgpack_assert(writer->map_nesting > 0); + writer->map_nesting--; + return 0; +} + +int lttng_msgpack_begin_array( + struct lttng_msgpack_writer *writer, size_t count) +{ + int ret; + + if (count < 0 || count >= (1 << 16)) { + ret = -1; + goto end; + } + + if (count <= MSGPACK_FIXARRAY_MAX_COUNT) + ret = lttng_msgpack_encode_fixarray(writer, count); + else + ret = lttng_msgpack_encode_array16(writer, count); + + writer->array_nesting++; +end: + return ret; +} + +int lttng_msgpack_end_array(struct lttng_msgpack_writer *writer) +{ + lttng_msgpack_assert(writer->array_nesting > 0); + writer->array_nesting--; + return 0; +} + +int lttng_msgpack_write_str(struct lttng_msgpack_writer *writer, + const char *str) +{ + int ret; + size_t length = strlen(str); + if (length < 0 || length >= (1 << 16)) { + ret = -1; + goto end; + } + + if (length <= MSGPACK_FIXSTR_MAX_LENGTH) + ret = lttng_msgpack_encode_fixstr(writer, str, length); + else + ret = lttng_msgpack_encode_str16(writer, str, length); + +end: + return ret; +} + +int lttng_msgpack_write_nil(struct lttng_msgpack_writer *writer) +{ + return lttng_msgpack_append_u8(writer, MSGPACK_NIL_ID); +} + +int lttng_msgpack_write_true(struct lttng_msgpack_writer *writer) +{ + return lttng_msgpack_append_u8(writer, MSGPACK_TRUE_ID); +} + +int lttng_msgpack_write_false(struct lttng_msgpack_writer *writer) +{ + return lttng_msgpack_append_u8(writer, MSGPACK_FALSE_ID); +} + +int lttng_msgpack_write_unsigned_integer( + struct lttng_msgpack_writer *writer, uint64_t value) +{ + int ret = 0; + + if (value <= MSGPACK_FIXINT_MAX) { + ret = lttng_msgpack_append_u8(writer, (uint8_t) value); + if (ret) + goto end; + } else if (value <= UINT8_MAX) { + ret = lttng_msgpack_append_u8(writer, MSGPACK_UINT8_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u8(writer, (uint8_t) value); + if (ret) + goto end; + } else if (value <= UINT16_MAX) { + ret = lttng_msgpack_append_u8(writer, MSGPACK_UINT16_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u16(writer, (uint16_t) value); + if (ret) + goto end; + } else if (value <= UINT32_MAX) { + ret = lttng_msgpack_append_u8(writer, MSGPACK_UINT32_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u32(writer, (uint32_t) value); + if (ret) + goto end; + } else { + ret = lttng_msgpack_append_u8(writer, MSGPACK_UINT64_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u64(writer, value); + if (ret) + goto end; + } + +end: + return ret; +} + +int lttng_msgpack_write_signed_integer(struct lttng_msgpack_writer *writer, int64_t value) +{ + int ret; + + if (value >= MSGPACK_FIXINT_MIN && value <= MSGPACK_FIXINT_MAX){ + ret = lttng_msgpack_append_i8(writer, (int8_t) value); + if (ret) + goto end; + } else if (value >= INT8_MIN && value <= INT8_MAX) { + ret = lttng_msgpack_append_u8(writer, MSGPACK_INT8_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_i8(writer, (int8_t) value); + if (ret) + goto end; + } else if (value >= INT16_MIN && value <= INT16_MAX) { + ret = lttng_msgpack_append_u8(writer, MSGPACK_INT16_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_i16(writer, (int16_t) value); + if (ret) + goto end; + } else if (value >= INT32_MIN && value <= INT32_MAX) { + ret = lttng_msgpack_append_u8(writer, MSGPACK_INT32_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_i32(writer, (int32_t) value); + if (ret) + goto end; + } else { + ret = lttng_msgpack_append_u8(writer, MSGPACK_INT64_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_i64(writer, value); + if (ret) + goto end; + } + +end: + return ret; +} + +int lttng_msgpack_write_double(struct lttng_msgpack_writer *writer, double value) +{ + return lttng_msgpack_encode_f64(writer, value); +} + +void lttng_msgpack_writer_init(struct lttng_msgpack_writer *writer, + uint8_t *buffer, size_t size) +{ + lttng_msgpack_assert(buffer); + lttng_msgpack_assert(size >= 0); + + writer->buffer = buffer; + writer->write_pos = buffer; + writer->end_write_pos = buffer + size; + + writer->array_nesting = 0; + writer->map_nesting = 0; +} + +void lttng_msgpack_writer_fini(struct lttng_msgpack_writer *writer) +{ + memset(writer, 0, sizeof(*writer)); +} diff --git a/libmsgpack/msgpack.h b/libmsgpack/msgpack.h new file mode 100644 index 00000000..e5c011ea --- /dev/null +++ b/libmsgpack/msgpack.h @@ -0,0 +1,61 @@ +#ifndef _LTTNG_UST_MSGPACK_H +#define _LTTNG_UST_MSGPACK_H + +/* + * msgpack.h + * + * Copyright (C) 2020 Francis Deslauriers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#ifdef __KERNEL__ +#include +#else /* __KERNEL__ */ +#include +#endif /* __KERNEL__ */ + +struct lttng_msgpack_writer { + uint8_t *buffer; + uint8_t *write_pos; + const uint8_t *end_write_pos; + uint8_t array_nesting; + uint8_t map_nesting; +}; + +void lttng_msgpack_writer_init( + struct lttng_msgpack_writer *writer, + uint8_t *buffer, size_t size); + +void lttng_msgpack_writer_fini(struct lttng_msgpack_writer *writer); + +int lttng_msgpack_write_nil(struct lttng_msgpack_writer *writer); +int lttng_msgpack_write_true(struct lttng_msgpack_writer *writer); +int lttng_msgpack_write_false(struct lttng_msgpack_writer *writer); +int lttng_msgpack_write_unsigned_integer( + struct lttng_msgpack_writer *writer, uint64_t value); +int lttng_msgpack_write_signed_integer( + struct lttng_msgpack_writer *writer, int64_t value); +int lttng_msgpack_write_double(struct lttng_msgpack_writer *writer, double value); +int lttng_msgpack_write_str(struct lttng_msgpack_writer *writer, + const char *value); +int lttng_msgpack_begin_map(struct lttng_msgpack_writer *writer, size_t count); +int lttng_msgpack_end_map(struct lttng_msgpack_writer *writer); +int lttng_msgpack_begin_array( + struct lttng_msgpack_writer *writer, size_t count); +int lttng_msgpack_end_array(struct lttng_msgpack_writer *writer); + +#endif /* _LTTNG_UST_MSGPACK_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 6792b0b9..9023d053 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,6 +7,7 @@ LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ TESTS = \ unit/libringbuffer/test_shm \ unit/gcc-weak-hidden/test_gcc_weak_hidden \ + unit/libmsgpack/test_msgpack \ unit/pthread_name/test_pthread_name \ unit/snprintf/test_snprintf \ unit/ust-elf/test_ust_elf diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index b1de13a1..0c984a70 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -1,5 +1,6 @@ SUBDIRS = \ gcc-weak-hidden \ + libmsgpack \ libringbuffer \ pthread_name \ snprintf \ diff --git a/tests/unit/libmsgpack/Makefile.am b/tests/unit/libmsgpack/Makefile.am new file mode 100644 index 00000000..784c3ef5 --- /dev/null +++ b/tests/unit/libmsgpack/Makefile.am @@ -0,0 +1,9 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/tests/utils + +noinst_PROGRAMS = test_msgpack +test_msgpack_SOURCES = test_msgpack.c +test_msgpack_LDADD = \ + $(top_builddir)/libmsgpack/libmsgpack.la \ + $(top_builddir)/tests/utils/libtap.a + +test_msgpack_CFLAGS = $(AM_CFLAGS) diff --git a/tests/unit/libmsgpack/test_msgpack.c b/tests/unit/libmsgpack/test_msgpack.c new file mode 100644 index 00000000..a8cd144c --- /dev/null +++ b/tests/unit/libmsgpack/test_msgpack.c @@ -0,0 +1,386 @@ +/* + * test_msgpack.c + * + * Copyright (C) 2020 Francis Deslauriers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include "tap.h" + +#include "../../libmsgpack/msgpack.h" + +#define BUFFER_SIZE 4096 +#define NUM_TESTS 23 + + +/* + * echo 'null' | json2msgpack | xxd -i + */ +static const uint8_t NIL_EXPECTED[] = { 0xc0 }; + +/* + * echo '"bye"' | json2msgpack | xxd -i + */ +static const uint8_t STRING_BYE_EXPECTED[] = { 0xa3, 0x62, 0x79, 0x65 }; + +/* + * echo '1337' | json2msgpack | xxd -i + */ +static const uint8_t UINT_1337_EXPECTED[] = { 0xcd, 0x05, 0x39 }; + +/* + * echo '127' | json2msgpack | xxd -i + */ +static const uint8_t UINT_127_EXPECTED[] = { 0x7f }; + +/* + * echo '128' | json2msgpack | xxd -i + */ +static const uint8_t UINT_128_EXPECTED[] = { 0xcc, 0x80 }; + +/* + * echo '256' | json2msgpack | xxd -i + */ +static const uint8_t UINT_256_EXPECTED[] = { 0xcd, 0x01, 0x00 }; + +/* + * echo '65535' | json2msgpack | xxd -i + */ +static const uint8_t UINT_65535_EXPECTED[] = { 0xcd, 0xff, 0xff }; + +/* + * echo '65536' | json2msgpack | xxd -i + */ +static const uint8_t UINT_65536_EXPECTED[] = { 0xce, 0x00, 0x01, 0x00, 0x00 }; + +/* + * echo '4294967295' | json2msgpack | xxd -i + */ +static const uint8_t UINT_4294967295_EXPECTED[] = { 0xce, 0xff, 0xff, 0xff, 0xff }; + +/* + * echo '4294967296' | json2msgpack | xxd -i + */ +static const uint8_t UINT_4294967296_EXPECTED[] = { 0xcf, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }; + +/* + * echo '-32' | json2msgpack | xxd -i + */ +static const uint8_t INT_NEG_32_EXPECTED[] = { 0xe0 }; + +/* + * echo '-33' | json2msgpack | xxd -i + */ +static const uint8_t INT_NEG_33_EXPECTED[] = { 0xd0, 0xdf }; + +/* + * echo '-129' | json2msgpack | xxd -i + */ +static const uint8_t INT_NEG_129_EXPECTED[] = { 0xd1, 0xff, 0x7f}; + +/* + * echo '-32768' | json2msgpack | xxd -i + */ +static const uint8_t INT_NEG_32768_EXPECTED[] = { 0xd1, 0x80, 0x00 }; + +/* + * echo '-32769' | json2msgpack | xxd -i + */ +static const uint8_t INT_NEG_32769_EXPECTED[] = { 0xd2, 0xff, 0xff, 0x7f, + 0xff }; + +/* + * echo '-2147483648' | json2msgpack | xxd -i + */ +static const uint8_t INT_NEG_2147483648_EXPECTED[] = { 0xd2, 0x80, 0x00, 0x00, + 0x00 }; + +/* + * echo '-2147483649' | json2msgpack | xxd -i + */ +static const uint8_t INT_NEG_2147483649_EXPECTED[] = { 0xd3, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0xff, 0xff, 0xff }; +/* + * echo '0.0' | json2msgpack | xxd -i + */ +static const uint8_t DOUBLE_ZERO_EXPECTED[] = { 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 }; + +/* + * echo '3.14159265' | json2msgpack | xxd -i + */ +static const uint8_t DOUBLE_PI_EXPECTED[] = { 0xcb, 0x40, 0x09, 0x21, 0xfb, 0x53, + 0xc8, 0xd4, 0xf1 }; + +/* + * echo '3.14159265' | json2msgpack | xxd -i + */ +static const uint8_t DOUBLE_NEG_PI_EXPECTED[] = { 0xcb, 0xc0, 0x09, 0x21, 0xfb, + 0x53, 0xc8, 0xd4, 0xf1 }; + +/* + * echo [1.1, 2.3, -12345.2] | json2msgpack | xxd -i + */ +static const uint8_t ARRAY_DOUBLE_EXPECTED[] = { 0x93, 0xcb, 0x3f, 0xf1, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x9a, 0xcb, 0x40, 0x02, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0xcb, 0xc0, 0xc8, 0x1c, 0x99, 0x99, + 0x99, 0x99, 0x9a }; + +/* + * echo '{"type":"enum","value":117}' | json2msgpack | xxd -i + */ +static const uint8_t MAP_EXPECTED[] = { + 0x82, 0xa4, 0x74, 0x79, 0x70, 0x65, 0xa4, 0x65, 0x6e, 0x75, 0x6d, 0xa5, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x75 }; + +/* + * echo '["meow mix", 18, null, 14.197, [1980, 1995]]' | json2msgpack | xxd -i + */ +static const uint8_t COMPLETE_CAPTURE_EXPECTED[] = { 0x95, 0xa8, 0x6d, 0x65, + 0x6f, 0x77, 0x20, 0x6d, 0x69, 0x78, 0x12, 0xc0, 0xcb, 0x40, + 0x2c, 0x64, 0xdd, 0x2f, 0x1a, 0x9f, 0xbe, 0x92, 0xcd, 0x07, + 0xbc, 0xcd, 0x07, 0xcb }; + +static void string_test(uint8_t *buf, const char *value) +{ + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + lttng_msgpack_write_str(&writer, value); + lttng_msgpack_writer_fini(&writer); +} + +static void int_test(uint8_t *buf, int64_t value) +{ + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + lttng_msgpack_write_signed_integer(&writer, value); + + lttng_msgpack_writer_fini(&writer); +} + +static void uint_test(uint8_t *buf, uint64_t value) +{ + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + lttng_msgpack_write_unsigned_integer(&writer, value); + lttng_msgpack_writer_fini(&writer); +} + +static void double_test(uint8_t *buf, double value) +{ + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + lttng_msgpack_write_double(&writer, value); + lttng_msgpack_writer_fini(&writer); +} + +static void array_double_test(uint8_t *buf, double *values, size_t nb_values) +{ + int i = 0; + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + lttng_msgpack_begin_array(&writer, nb_values); + + for (i = 0; i < nb_values; i++) { + lttng_msgpack_write_double(&writer, values[i]); + } + + lttng_msgpack_end_array(&writer); + lttng_msgpack_writer_fini(&writer); +} + +static void map_test(uint8_t *buf) +{ + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + + lttng_msgpack_begin_map(&writer, 2); + + lttng_msgpack_write_str(&writer, "type"); + lttng_msgpack_write_str(&writer, "enum"); + + lttng_msgpack_write_str(&writer, "value"); + lttng_msgpack_write_unsigned_integer(&writer, 117); + + lttng_msgpack_end_map(&writer); + lttng_msgpack_writer_fini(&writer); +} + +static void complete_capture_test(uint8_t *buf) +{ + /* + * This testcase tests the following json representation: + * "meow mix",18, null, 14.197,[1980, 1995]] + */ + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + + lttng_msgpack_begin_array(&writer, 5); + + lttng_msgpack_write_str(&writer, "meow mix"); + lttng_msgpack_write_signed_integer(&writer, 18); + lttng_msgpack_write_nil(&writer); + lttng_msgpack_write_double(&writer, 14.197); + + lttng_msgpack_begin_array(&writer, 2); + + lttng_msgpack_write_unsigned_integer(&writer, 1980); + lttng_msgpack_write_unsigned_integer(&writer, 1995); + + lttng_msgpack_end_array(&writer); + + lttng_msgpack_end_array(&writer); + + lttng_msgpack_writer_fini(&writer); +} + +static void nil_test(uint8_t *buf) +{ + struct lttng_msgpack_writer writer; + + lttng_msgpack_writer_init(&writer, buf, BUFFER_SIZE); + lttng_msgpack_write_nil(&writer); + lttng_msgpack_writer_fini(&writer); +} + +int main(int argc, char *argv[]) +{ + uint8_t buf[BUFFER_SIZE] = {0}; + double arr_double[] = {1.1, 2.3, -12345.2}; + + plan_tests(NUM_TESTS); + + diag("Testing msgpack implementation"); + + /* + * Expected outputs were produced using the `json2msgpack` tool. + * https://github.com/ludocode/msgpack-tools + * For example, here is the command to produce the null test expected + * output: + * echo 'null' | json2msgpack | hexdump -v -e '"\\\x" 1/1 "%02x"' + * + * The only exception is that we always produce 64bits integer to + * represent integers even if they would fit into smaller objects so + * they need to be manually crafted in 64bits two's complement (if + * signed) big endian. + */ + nil_test(buf); + ok(memcmp(buf, NIL_EXPECTED, sizeof(NIL_EXPECTED)) == 0, + "NIL object"); + + string_test(buf, "bye"); + ok(memcmp(buf, STRING_BYE_EXPECTED, sizeof(STRING_BYE_EXPECTED)) == 0, + "String \"bye\" object"); + + uint_test(buf, 1337); + ok(memcmp(buf, UINT_1337_EXPECTED, sizeof(UINT_1337_EXPECTED)) == 0, + "Unsigned integer \"1337\" object"); + + uint_test(buf, 127); + ok(memcmp(buf, UINT_127_EXPECTED, sizeof(UINT_127_EXPECTED)) == 0, + "Unsigned integer \"127\" object"); + + uint_test(buf, 128); + ok(memcmp(buf, UINT_128_EXPECTED, sizeof(UINT_128_EXPECTED)) == 0, + "Unsigned integer \"128\" object"); + + uint_test(buf, 256); + ok(memcmp(buf, UINT_256_EXPECTED, sizeof(UINT_256_EXPECTED)) == 0, + "Unsigned integer \"256\" object"); + + uint_test(buf, 65536); + ok(memcmp(buf, UINT_65536_EXPECTED, sizeof(UINT_65536_EXPECTED)) == 0, + "Unsigned integer \"65536\" object"); + + uint_test(buf, 65535); + ok(memcmp(buf, UINT_65535_EXPECTED, sizeof(UINT_65535_EXPECTED)) == 0, + "Unsigned integer \"65535\" object"); + + uint_test(buf, 4294967295); + ok(memcmp(buf, UINT_4294967295_EXPECTED, sizeof(UINT_4294967295_EXPECTED)) == 0, + "Unsigned integer \"4294967295\" object"); + + uint_test(buf, 4294967296); + ok(memcmp(buf, UINT_4294967296_EXPECTED, sizeof(UINT_4294967296_EXPECTED)) == 0, + "Unsigned integer \"4294967296\" object"); + + int_test(buf, -32); + ok(memcmp(buf, INT_NEG_32_EXPECTED, sizeof(INT_NEG_32_EXPECTED)) == 0, + "Signed integer \"-32\" object"); + + int_test(buf, -33); + ok(memcmp(buf, INT_NEG_33_EXPECTED, sizeof(INT_NEG_33_EXPECTED)) == 0, + "Signed integer \"-33\" object"); + + int_test(buf, -129); + ok(memcmp(buf, INT_NEG_129_EXPECTED, sizeof(INT_NEG_129_EXPECTED)) == 0, + "Signed integer \"-129\" object"); + + int_test(buf, -32768); + ok(memcmp(buf, INT_NEG_32768_EXPECTED, sizeof(INT_NEG_32768_EXPECTED)) == 0, + "Signed integer \"-32768\" object"); + + int_test(buf, -32769); + ok(memcmp(buf, INT_NEG_32769_EXPECTED, sizeof(INT_NEG_32769_EXPECTED)) == 0, + "Signed integer \"-32769\" object"); + + int_test(buf, -2147483648); + ok(memcmp(buf, INT_NEG_2147483648_EXPECTED, sizeof(INT_NEG_2147483648_EXPECTED)) == 0, + "Signed integer \"-2147483648\" object"); + + int_test(buf, -2147483649); + ok(memcmp(buf, INT_NEG_2147483649_EXPECTED, sizeof(INT_NEG_2147483649_EXPECTED)) == 0, + "Signed integer \"-2147483649\" object"); + + double_test(buf, 0.0); + ok(memcmp(buf, DOUBLE_ZERO_EXPECTED, sizeof(DOUBLE_ZERO_EXPECTED)) == 0, + "double \"0.0\" object"); + + double_test(buf, 3.14159265); + ok(memcmp(buf, DOUBLE_PI_EXPECTED, sizeof(DOUBLE_PI_EXPECTED)) == 0, + "double \"PI\" object"); + + double_test(buf, -3.14159265); + ok(memcmp(buf, DOUBLE_NEG_PI_EXPECTED, sizeof(DOUBLE_NEG_PI_EXPECTED)) == 0, + "double \"-PI\" object"); + + array_double_test(buf, arr_double, 3); + ok(memcmp(buf, ARRAY_DOUBLE_EXPECTED, sizeof(ARRAY_DOUBLE_EXPECTED)) == 0, + "Array of double object"); + + map_test(buf); + ok(memcmp(buf, MAP_EXPECTED, sizeof(MAP_EXPECTED)) == 0, + "Map object"); + + complete_capture_test(buf); + ok(memcmp(buf, COMPLETE_CAPTURE_EXPECTED, sizeof(COMPLETE_CAPTURE_EXPECTED)) == 0, + "Complete capture object"); + + return EXIT_SUCCESS; +} -- 2.34.1