From 549e6d0d2f5774fcec7c12843fc733cbd1d9c960 Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Sun, 19 Jul 2015 14:31:51 +0200 Subject: [PATCH 1/2] Ability to craft new CBOR easily [https://github.com/iptube/SPUDlib/issues/6] Added explicit spud_map_t object and interfaces to manipulate it. --- include/map.h | 90 +++++++++ src/CMakeLists.txt | 1 + src/map.c | 456 ++++++++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/map_test.c | 130 +++++++++++++ 5 files changed, 678 insertions(+) create mode 100644 include/map.h create mode 100644 src/map.c create mode 100644 test/map_test.c diff --git a/include/map.h b/include/map.h new file mode 100644 index 0000000..2b7059b --- /dev/null +++ b/include/map.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2015 SPUDlib authors. See LICENSE file. + */ + +#ifndef _SPUD_MAP_H +#define _SPUD_MAP_H + +#include "spud.h" + +typedef struct spud_map_s { + cn_cbor_context ctx; + cn_cbor *cbor; +} spud_map_t; + +#define SPUD_MAP_MAX_SERIALIZED_SZ 1500 + +// +// SPUD CBOR map life time +// +LS_API void spud_map_reset(spud_map_t *map); +LS_API bool spud_map_create(spud_map_t **pmap, ls_err *err); +LS_API bool spud_map_create_ctx(spud_map_t *map, ls_err *err); + +LS_API void spud_map_free(spud_map_t *map); +LS_API void spud_map_free_ctx(spud_map_t *map); + +// +// Setters for various path declarations +// (Section 8 of draft-hildebrand-spud-prototype-03) +// +LS_API bool spud_map_add_ip_address(spud_map_t *map, const uint8_t *ip_addr, + size_t ip_addr_sz, ls_err *err); +LS_API bool spud_map_add_token(spud_map_t *map, const uint8_t *token, + size_t token_sz, ls_err *err); +LS_API bool spud_map_add_url(spud_map_t *map, const char *url, ls_err *err); +LS_API bool spud_map_add_warning(spud_map_t *map, const char *msg_tag, + const char *msg, ls_err *err); +LS_API bool spud_map_add_icmp(spud_map_t *map, const uint8_t *icmp_pkt, + size_t icmp_pkt_sz, ls_err *err); +LS_API bool spud_map_add_icmp_type(spud_map_t *map, int64_t icmp_type, + ls_err *err); +LS_API bool spud_map_add_icmp_code(spud_map_t *map, int64_t icmp_code, + ls_err *err); +LS_API bool spud_map_add_translated_external_address(spud_map_t *map, + const uint8_t *ip_addr, + size_t ip_addr_sz, + ls_err *err); +LS_API bool spud_map_add_internal_address(spud_map_t *map, + const uint8_t *ip_addr, + size_t ip_addr_sz, ls_err *err); +LS_API bool spud_map_add_translated_external_port(spud_map_t *map, + uint16_t port, ls_err *err); +LS_API bool spud_map_add_internal_port(spud_map_t *map, uint16_t port, + ls_err *err); +LS_API bool spud_map_add_inactivity_timer(spud_map_t *map, int64_t msec, + ls_err *err); +LS_API bool spud_map_add_path_element_description(spud_map_t *map, + const char *description, + ls_err *err); +LS_API bool spud_map_add_path_element_version(spud_map_t *map, + const char *version, ls_err *err); +LS_API bool spud_map_add_path_element_caps(spud_map_t *map, const uint8_t *caps, + size_t caps_sz, ls_err *err); +LS_API bool spud_map_add_path_element_ttl(spud_map_t *map, int64_t ttl, + ls_err *err); +LS_API bool spud_map_add_mtu(spud_map_t *map, int64_t mtu, ls_err *err); +LS_API bool spud_map_add_max_byte_rate(spud_map_t *map, int64_t mbr, + ls_err *err); +LS_API bool spud_map_add_max_packet_rate(spud_map_t *map, int64_t mpr, + ls_err *err); +LS_API bool spud_map_add_latency(spud_map_t *map, int64_t msec, ls_err *err); + +// +// Getters (a very limited subset of what can be set) +// +LS_API const char *spud_map_get_url(spud_map_t *map); +LS_API const uint8_t *spud_map_get_ip_address(spud_map_t *map, + size_t *pip_addr_sz); +LS_API const uint8_t *spud_map_get_token(spud_map_t *map, size_t *ptoken_sz); +LS_API const char *spud_map_get_warning(spud_map_t *map, const char *lang_tag); + +// +// Encode/decode +// +LS_API bool spud_map_encode(const spud_map_t *map, uint8_t *out, size_t *out_sz, + ls_err *err); +LS_API bool spud_map_decode(const uint8_t *buf, size_t buf_sz, spud_map_t *map, + ls_err *err); + +#endif // !_SPUD_MAP_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c259785..4c14ebe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,7 @@ set ( spud_srcs tube.c tube_manager.c tube_stream.c + map.c ) add_definitions(-DUSE_CBOR_CONTEXT) diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..b42e73d --- /dev/null +++ b/src/map.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2015 SPUDlib authors. See LICENSE file. + */ + +#include "map.h" + +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "ls_log.h" +#include "ls_sockaddr.h" +#include "cn-cbor/cn-cbor.h" + +static spud_map_t *spud_map_alloc(void); +static bool cbor_map_add_string(cn_cbor *map, cn_cbor_context *ctx, + const char *key, const char *str, ls_err *err); +static const char *cbor_map_get_string(cn_cbor *map, const char *key); +static bool spud_map_add_data(spud_map_t *map, const char *key, + const uint8_t *data, size_t data_sz, ls_err *err); +static bool spud_map_add_string(spud_map_t *map, const char *key, + const char *str, ls_err *err); +static const uint8_t *spud_map_get_data(spud_map_t *map, const char *key, + size_t *pdata_sz); +static cn_cbor *spud_map_create_warnings(spud_map_t *map); +static bool spud_map_add_int(spud_map_t *map, const char *key, int64_t val, + ls_err *err); + +// +// spud_map_t life cycle +// + +LS_API void spud_map_reset(spud_map_t *map) +{ + assert(map); + + map->ctx.calloc_func = NULL; + map->ctx.free_func = NULL; + map->ctx.context = NULL; + + map->cbor = NULL; +} + +LS_API bool spud_map_create_ctx(spud_map_t *map, ls_err *err) +{ + assert(map != NULL); + + if (!ls_pool_create(128, (ls_pool **)&map->ctx.context, err)) { + LS_ERROR(err, LS_ERR_NO_MEMORY); + return false; + } + + if ((map->cbor = cn_cbor_map_create(&map->ctx, NULL)) == NULL) { + ls_pool_destroy(map->ctx.context); + LS_ERROR(err, LS_ERR_NO_MEMORY); + return false; + } + + return true; +} + +LS_API bool spud_map_create(spud_map_t **pmap, ls_err *err) +{ + assert(pmap != NULL); + + spud_map_t *map = spud_map_alloc(); + + if (map == NULL) { + LS_ERROR(err, LS_ERR_NO_MEMORY); + return false; + } + + if (!spud_map_create_ctx(map, err)) { + spud_map_free(map); + return false; + } + + // Copy out the handler + *pmap = map; + + return true; +} + +LS_API void spud_map_free_ctx(spud_map_t *map) +{ + assert(map != NULL); + + // We don't need to explicitly free the .cbor member since it'll be + // deallocated along with the pool. + if (map->ctx.context) { + ls_pool_destroy(map->ctx.context); + map->ctx.context = NULL; + } +} + +LS_API void spud_map_free(spud_map_t *map) +{ + if (map) { + spud_map_free_ctx(map); + ls_data_free(map); + } +} + +// +// spud_map_t setters +// +LS_API bool spud_map_add_inactivity_timer(spud_map_t *map, int64_t msec, + ls_err *err) +{ + return spud_map_add_int(map, "inactivity-timer", msec, err); +} + +LS_API bool spud_map_add_icmp_type(spud_map_t *map, int64_t icmp_type, + ls_err *err) +{ + return spud_map_add_int(map, "icmp-type", icmp_type, err); +} + +LS_API bool spud_map_add_icmp_code(spud_map_t *map, int64_t icmp_code, + ls_err *err) +{ + return spud_map_add_int(map, "icmp-code", icmp_code, err); +} + +LS_API bool spud_map_add_translated_external_address(spud_map_t *map, + const uint8_t *ip_addr, + size_t ip_addr_sz, + ls_err *err) +{ + return spud_map_add_data(map, "translated-external-address", ip_addr, + ip_addr_sz, err); +} + +LS_API bool spud_map_add_internal_address(spud_map_t *map, + const uint8_t *ip_addr, + size_t ip_addr_sz, ls_err *err) +{ + return spud_map_add_data(map, "internal-address", ip_addr, ip_addr_sz, err); +} + +LS_API bool spud_map_add_translated_external_port(spud_map_t *map, + uint16_t port, ls_err *err) +{ + return spud_map_add_int(map, "translated-external-port", port, err); +} + +LS_API bool spud_map_add_internal_port(spud_map_t *map, uint16_t port, + ls_err *err) +{ + return spud_map_add_int(map, "internal-port", port, err); +} + +LS_API bool spud_map_add_path_element_description(spud_map_t *map, + const char *description, + ls_err *err) +{ + return spud_map_add_string(map, "description", description, err); +} + +LS_API bool spud_map_add_path_element_version(spud_map_t *map, + const char *version, ls_err *err) +{ + return spud_map_add_string(map, "version", version, err); +} + +LS_API bool spud_map_add_path_element_caps(spud_map_t *map, const uint8_t *caps, + size_t caps_sz, ls_err *err) +{ + return spud_map_add_data(map, "caps", caps, caps_sz, err); +} + +LS_API bool spud_map_add_path_element_ttl(spud_map_t *map, int64_t ttl, + ls_err *err) +{ + return spud_map_add_int(map, "ttl", ttl, err); +} + +LS_API bool spud_map_add_mtu(spud_map_t *map, int64_t mtu, ls_err *err) +{ + return spud_map_add_int(map, "mtu", mtu, err); +} + +LS_API bool spud_map_add_max_byte_rate(spud_map_t *map, int64_t mbr, + ls_err *err) +{ + return spud_map_add_int(map, "max-byte-rate", mbr, err); +} + +LS_API bool spud_map_add_max_packet_rate(spud_map_t *map, int64_t mpr, + ls_err *err) +{ + return spud_map_add_int(map, "max-packet-rate", mpr, err); +} + +LS_API bool spud_map_add_latency(spud_map_t *map, int64_t msec, ls_err *err) +{ + return spud_map_add_int(map, "latency", msec, err); +} + +LS_API bool spud_map_add_icmp(spud_map_t *map, const uint8_t *icmp_pkt, + size_t icmp_pkt_sz, ls_err *err) +{ + return spud_map_add_data(map, "icmp", icmp_pkt, icmp_pkt_sz, err); +} + +LS_API bool spud_map_add_ip_address(spud_map_t *map, const uint8_t *ip_addr, + size_t ip_addr_sz, ls_err *err) +{ + return spud_map_add_data(map, "ipaddr", ip_addr, ip_addr_sz, err); +} + +LS_API bool spud_map_add_token(spud_map_t *map, const uint8_t *token, + size_t token_sz, ls_err *err) +{ + return spud_map_add_data(map, "token", token, token_sz, err); +} + +LS_API bool spud_map_add_url(spud_map_t *map, const char *url, ls_err *err) +{ + return spud_map_add_string(map, "url", url, err); +} + +LS_API bool spud_map_add_warning(spud_map_t *map, const char *lang_tag, + const char *msg, ls_err *err) +{ + cn_cbor *warning_map = + (cn_cbor *)cn_cbor_mapget_string(map->cbor, "warning"); + + if (warning_map == NULL) { + // Create a new warning map and stick it into the cbor map + if ((warning_map = spud_map_create_warnings(map)) == NULL) { + LS_ERROR(err, LS_ERR_NO_MEMORY); + return false; + } + } + + return cbor_map_add_string(warning_map, &map->ctx, lang_tag, msg, err); +} + +// +// spud_map_t getters +// + +LS_API const char *spud_map_get_url(spud_map_t *map) +{ + assert(map != NULL); + assert(map->cbor != NULL); + + return cbor_map_get_string(map->cbor, "url"); +} + +LS_API const uint8_t *spud_map_get_ip_address(spud_map_t *map, + size_t *pip_addr_sz) +{ + assert(map != NULL); + assert(map->cbor != NULL); + assert(pip_addr_sz != NULL); + + return spud_map_get_data(map, "ipaddr", pip_addr_sz); +} + +LS_API const uint8_t *spud_map_get_token(spud_map_t *map, size_t *ptoken_sz) +{ + assert(map != NULL); + assert(map->cbor != NULL); + assert(ptoken_sz != NULL); + + return spud_map_get_data(map, "token", ptoken_sz); +} + +LS_API const char *spud_map_get_warning(spud_map_t *map, const char *lang_tag) +{ + assert(map != NULL); + assert(map->cbor != NULL); + + cn_cbor *warning_map = + (cn_cbor *)cn_cbor_mapget_string(map->cbor, "warning"); + + if (warning_map == NULL) { + return NULL; + } + + return cbor_map_get_string(warning_map, lang_tag); +} + +// +// spud_map_t encode/decode +// + +LS_API bool spud_map_encode(const spud_map_t *map, uint8_t *out, size_t *out_sz, + ls_err *err) +{ + assert(map != NULL); + assert(out != NULL); + assert(out_sz != NULL); + + ssize_t rc = cbor_encoder_write(out, 0, *out_sz, map->cbor); + + if (rc < 0) { + LS_ERROR(err, LS_ERR_OVERFLOW); + return false; + } + + *out_sz = (size_t)rc; + + return true; +} + +// - wants a pre-allocated spud map +// - caller is responsible to check the semantic consistency of the map +LS_API bool spud_map_decode(const uint8_t *buf, size_t buf_sz, spud_map_t *map, + ls_err *err) +{ + assert(map != NULL); + + cn_cbor_errback cbor_err; + cn_cbor *cbor = + (cn_cbor *)cn_cbor_decode(buf, buf_sz, &map->ctx, &cbor_err); + + if (cbor == NULL) { + if (err) { + err->code = LS_ERR_USER + cbor_err.err; + err->message = cn_cbor_error_str[cbor_err.err]; + err->function = __func__; + err->file = __FILE__; + err->line = __LINE__; + } + return false; + } + + map->cbor = cbor, cbor = NULL; + + return true; +} + +// +// private stuff +// + +static spud_map_t *spud_map_alloc(void) +{ + spud_map_t *map = ls_data_malloc(sizeof(spud_map_t)); + + if (map) { + spud_map_reset(map); + } + + return map; +} + +static bool spud_map_add_int(spud_map_t *map, const char *key, int64_t i, + ls_err *err) +{ + assert(map != NULL); + + if (key) { + cn_cbor *val = cn_cbor_int_create(i, &map->ctx, NULL); + if (!val || + !cn_cbor_mapput_string(map->cbor, key, val, &map->ctx, NULL)) { + LS_ERROR(err, LS_ERR_NO_MEMORY); + return false; + } + } + + return true; +} + +static bool cbor_map_add_string(cn_cbor *map, cn_cbor_context *ctx, + const char *key, const char *str, ls_err *err) +{ + assert(map != NULL); + assert(ctx != NULL); + + if (key && str) { + cn_cbor *val = cn_cbor_string_create(str, ctx, NULL); + if (!val || !cn_cbor_mapput_string(map, key, val, ctx, NULL)) { + LS_ERROR(err, LS_ERR_NO_MEMORY); + return false; + } + } + + return true; +} + +// naming is not perfect (string refers to the value; the type of the key is +// implicit...) +static bool spud_map_add_string(spud_map_t *map, const char *key, + const char *str, ls_err *err) +{ + assert(map != NULL); + + return cbor_map_add_string(map->cbor, &map->ctx, key, str, err); +} + +static bool spud_map_add_data(spud_map_t *map, const char *key, + const uint8_t *data, size_t data_sz, ls_err *err) +{ + assert(map != NULL); + + if (key && data) { + cn_cbor *val = cn_cbor_data_create(data, data_sz, &map->ctx, NULL); + if (!val || + !cn_cbor_mapput_string(map->cbor, key, val, &map->ctx, NULL)) { + LS_ERROR(err, LS_ERR_NO_MEMORY); + return false; + } + } + + return true; +} + +static const uint8_t *spud_map_get_data(spud_map_t *map, const char *key, + size_t *pdata_sz) +{ + const cn_cbor *val = cn_cbor_mapget_string(map->cbor, key); + + if (val->type != CN_CBOR_BYTES) { + return NULL; + } + + *pdata_sz = val->length; + + return (const uint8_t *)val->v.str; +} + +// assumes the callers has made sure that there's no warnings' map +static cn_cbor *spud_map_create_warnings(spud_map_t *map) +{ + assert(map != NULL); + assert(map->cbor != NULL); + + cn_cbor *warning_map = cn_cbor_map_create(&map->ctx, NULL); + + if (warning_map == NULL || + !cn_cbor_mapput_string(map->cbor, "warning", warning_map, &map->ctx, + NULL)) { + return NULL; + } + + return warning_map; +} + +static const char *cbor_map_get_string(cn_cbor *map, const char *key) +{ + const cn_cbor *val = cn_cbor_mapget_string(map, key); + + if (val->type != CN_CBOR_TEXT) { + return NULL; + } + + return val->v.str; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b18c57a..1858eeb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -26,6 +26,7 @@ ls_test ( ls_timer ) ls_test ( spud ) ls_test ( tube ) ls_test ( tube_stream ) +ls_test ( map ) target_link_libraries ( tube_test PRIVATE pthread ) include ( CTest ) diff --git a/test/map_test.c b/test/map_test.c new file mode 100644 index 0000000..6507721 --- /dev/null +++ b/test/map_test.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2015 SPUDlib authors. See LICENSE file. + */ + +#include +#include "test_utils.h" +#include "map.h" + +CTEST(map, basic_create_and_free) +{ + spud_map_t *map; + + ASSERT_TRUE(spud_map_create(&map, NULL)); + + spud_map_free(map); +} + +CTEST(map, add_ip_address) +{ + spud_map_t map; + const uint8_t ip[] = {192, 168, 0, 0}; + + spud_map_reset(&map); + + ASSERT_TRUE(spud_map_create_ctx(&map, NULL)); + ASSERT_TRUE(spud_map_add_ip_address(&map, ip, sizeof ip, NULL)); + + spud_map_free_ctx(&map); +} + +CTEST(map, add_token) +{ + spud_map_t map; + const uint8_t token[] = {0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf}; + + spud_map_reset(&map); + + ASSERT_TRUE(spud_map_create_ctx(&map, NULL)); + ASSERT_TRUE(spud_map_add_token(&map, token, sizeof token, NULL)); + + spud_map_free_ctx(&map); +} + +CTEST(map, add_url) +{ + spud_map_t map; + const char *url = "http://www.example.org/spud"; + + spud_map_reset(&map); + + ASSERT_TRUE(spud_map_create_ctx(&map, NULL)); + ASSERT_TRUE(spud_map_add_url(&map, url, NULL)); + + spud_map_free_ctx(&map); +} + +CTEST(map, add_warnings) +{ + spud_map_t map; + + struct warning_s { + const char *tag; + const char *msg; + }; + + struct warning_s warnings[] = {{"it", "avvertimento"}, + {"es", "advertencia"}, + {"de", "warnung"}, + {"fr", "avertissement"}}; + + spud_map_reset(&map); + ASSERT_TRUE(spud_map_create_ctx(&map, NULL)); + + size_t i; + for (i = 0; i < sizeof warnings / sizeof(struct warning_s); ++i) { + ASSERT_TRUE( + spud_map_add_warning(&map, warnings[i].tag, warnings[i].msg, NULL)); + } + + for (i = 0; i < sizeof warnings / sizeof(struct warning_s); ++i) { + const char *msg = spud_map_get_warning(&map, warnings[i].tag); + ASSERT_NOT_NULL(msg); + ASSERT_STR(warnings[i].msg, msg); + } + + spud_map_free_ctx(&map); +} + +CTEST(map, encode_decode_check) +{ + spud_map_t map_out; + spud_map_reset(&map_out); + + const uint8_t ip0[] = {192, 168, 0, 0}; + const uint8_t token0[] = {0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf}; + const char *url = "http://www.example.org/spud"; + + ASSERT_TRUE(spud_map_create_ctx(&map_out, NULL)); + ASSERT_TRUE(spud_map_add_ip_address(&map_out, ip0, sizeof ip0, NULL)); + ASSERT_TRUE(spud_map_add_token(&map_out, token0, sizeof token0, NULL)); + ASSERT_TRUE(spud_map_add_url(&map_out, url, NULL)); + + spud_map_free_ctx(&map_out); + + uint8_t out[SPUD_MAP_MAX_SERIALIZED_SZ]; + size_t out_sz = sizeof out; + + spud_map_t map_in; + spud_map_reset(&map_in); + + ASSERT_TRUE(spud_map_encode(&map_out, out, &out_sz, NULL)); + ASSERT_TRUE(spud_map_decode(out, out_sz, &map_in, NULL)); + + // Check decoded is as expected + ASSERT_STR(url, spud_map_get_url(&map_in)); + + size_t ip1_sz; + const uint8_t *ip1 = spud_map_get_ip_address(&map_in, &ip1_sz); + ASSERT_NOT_NULL(ip1); // got something + ASSERT_EQUAL(sizeof ip0, ip1_sz); // same length as the original + ASSERT_DATA(ip0, sizeof ip0, ip1, ip1_sz); // and same contents + + size_t token1_sz; + const uint8_t *token1 = spud_map_get_token(&map_in, &token1_sz); + ASSERT_NOT_NULL(token1); // ditto + ASSERT_EQUAL(sizeof token0, token1_sz); + ASSERT_DATA(token0, sizeof token0, token1, token1_sz); + + spud_map_free_ctx(&map_in); +} From ec829be9ccca171d646d82d0eec4c913c3ddee8c Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Sun, 19 Jul 2015 16:54:08 +0200 Subject: [PATCH 2/2] fix two problems with https://github.com/iptube/SPUDlib/issues/6 - mem leak in spud_map_t free - get_string interface change (explicitly return string length) --- include/map.h | 5 +++-- src/map.c | 24 ++++++++++++++++-------- test/map_test.c | 18 +++++++++++------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/include/map.h b/include/map.h index 2b7059b..cfb68ce 100644 --- a/include/map.h +++ b/include/map.h @@ -73,11 +73,12 @@ LS_API bool spud_map_add_latency(spud_map_t *map, int64_t msec, ls_err *err); // // Getters (a very limited subset of what can be set) // -LS_API const char *spud_map_get_url(spud_map_t *map); +LS_API const char *spud_map_get_url(spud_map_t *map, size_t *purl_len); LS_API const uint8_t *spud_map_get_ip_address(spud_map_t *map, size_t *pip_addr_sz); LS_API const uint8_t *spud_map_get_token(spud_map_t *map, size_t *ptoken_sz); -LS_API const char *spud_map_get_warning(spud_map_t *map, const char *lang_tag); +LS_API const char *spud_map_get_warning(spud_map_t *map, const char *lang_tag, + size_t *pmsg_len); // // Encode/decode diff --git a/src/map.c b/src/map.c index b42e73d..51db12f 100644 --- a/src/map.c +++ b/src/map.c @@ -19,7 +19,8 @@ static spud_map_t *spud_map_alloc(void); static bool cbor_map_add_string(cn_cbor *map, cn_cbor_context *ctx, const char *key, const char *str, ls_err *err); -static const char *cbor_map_get_string(cn_cbor *map, const char *key); +static const char *cbor_map_get_string(cn_cbor *map, const char *key, + size_t *pstr_len); static bool spud_map_add_data(spud_map_t *map, const char *key, const uint8_t *data, size_t data_sz, ls_err *err); static bool spud_map_add_string(spud_map_t *map, const char *key, @@ -89,8 +90,11 @@ LS_API void spud_map_free_ctx(spud_map_t *map) { assert(map != NULL); - // We don't need to explicitly free the .cbor member since it'll be - // deallocated along with the pool. + if (map->cbor) { + cn_cbor_free(map->cbor, &map->ctx); + map->cbor = NULL; + } + if (map->ctx.context) { ls_pool_destroy(map->ctx.context); map->ctx.context = NULL; @@ -245,12 +249,12 @@ LS_API bool spud_map_add_warning(spud_map_t *map, const char *lang_tag, // spud_map_t getters // -LS_API const char *spud_map_get_url(spud_map_t *map) +LS_API const char *spud_map_get_url(spud_map_t *map, size_t *purl_len) { assert(map != NULL); assert(map->cbor != NULL); - return cbor_map_get_string(map->cbor, "url"); + return cbor_map_get_string(map->cbor, "url", purl_len); } LS_API const uint8_t *spud_map_get_ip_address(spud_map_t *map, @@ -272,7 +276,8 @@ LS_API const uint8_t *spud_map_get_token(spud_map_t *map, size_t *ptoken_sz) return spud_map_get_data(map, "token", ptoken_sz); } -LS_API const char *spud_map_get_warning(spud_map_t *map, const char *lang_tag) +LS_API const char *spud_map_get_warning(spud_map_t *map, const char *lang_tag, + size_t *pmsg_len) { assert(map != NULL); assert(map->cbor != NULL); @@ -284,7 +289,7 @@ LS_API const char *spud_map_get_warning(spud_map_t *map, const char *lang_tag) return NULL; } - return cbor_map_get_string(warning_map, lang_tag); + return cbor_map_get_string(warning_map, lang_tag, pmsg_len); } // @@ -444,7 +449,8 @@ static cn_cbor *spud_map_create_warnings(spud_map_t *map) return warning_map; } -static const char *cbor_map_get_string(cn_cbor *map, const char *key) +static const char *cbor_map_get_string(cn_cbor *map, const char *key, + size_t *pstr_len) { const cn_cbor *val = cn_cbor_mapget_string(map, key); @@ -452,5 +458,7 @@ static const char *cbor_map_get_string(cn_cbor *map, const char *key) return NULL; } + *pstr_len = val->length; + return val->v.str; } diff --git a/test/map_test.c b/test/map_test.c index 6507721..519de86 100644 --- a/test/map_test.c +++ b/test/map_test.c @@ -78,9 +78,11 @@ CTEST(map, add_warnings) } for (i = 0; i < sizeof warnings / sizeof(struct warning_s); ++i) { - const char *msg = spud_map_get_warning(&map, warnings[i].tag); + size_t msg_len; + const char *msg = spud_map_get_warning(&map, warnings[i].tag, &msg_len); ASSERT_NOT_NULL(msg); - ASSERT_STR(warnings[i].msg, msg); + ASSERT_DATA((const uint8_t *)warnings[i].msg, strlen(warnings[i].msg), + (const uint8_t *)msg, msg_len); } spud_map_free_ctx(&map); @@ -93,14 +95,12 @@ CTEST(map, encode_decode_check) const uint8_t ip0[] = {192, 168, 0, 0}; const uint8_t token0[] = {0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf}; - const char *url = "http://www.example.org/spud"; + const char *url0 = "http://www.example.org/spud"; ASSERT_TRUE(spud_map_create_ctx(&map_out, NULL)); ASSERT_TRUE(spud_map_add_ip_address(&map_out, ip0, sizeof ip0, NULL)); ASSERT_TRUE(spud_map_add_token(&map_out, token0, sizeof token0, NULL)); - ASSERT_TRUE(spud_map_add_url(&map_out, url, NULL)); - - spud_map_free_ctx(&map_out); + ASSERT_TRUE(spud_map_add_url(&map_out, url0, NULL)); uint8_t out[SPUD_MAP_MAX_SERIALIZED_SZ]; size_t out_sz = sizeof out; @@ -112,7 +112,10 @@ CTEST(map, encode_decode_check) ASSERT_TRUE(spud_map_decode(out, out_sz, &map_in, NULL)); // Check decoded is as expected - ASSERT_STR(url, spud_map_get_url(&map_in)); + size_t url1_len; + const char *url1 = spud_map_get_url(&map_in, &url1_len); + ASSERT_DATA((const uint8_t *)url0, strlen(url0), (const uint8_t *)url1, + url1_len); size_t ip1_sz; const uint8_t *ip1 = spud_map_get_ip_address(&map_in, &ip1_sz); @@ -127,4 +130,5 @@ CTEST(map, encode_decode_check) ASSERT_DATA(token0, sizeof token0, token1, token1_sz); spud_map_free_ctx(&map_in); + spud_map_free_ctx(&map_out); }