From c9a8aeb13d617c36e5ef71d6abf8223ac91fcdb1 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Fri, 2 Jan 2015 17:52:52 +0100 Subject: [PATCH] proto: Added support for unmarshaling hosts/services/metrics/attributes. --- src/include/utils/proto.h | 25 ++++++- src/utils/proto.c | 145 +++++++++++++++++++++++++++++++++++--- t/unit/utils/proto_test.c | 124 ++++++++++++++++++++++++++++---- 3 files changed, 269 insertions(+), 25 deletions(-) diff --git a/src/include/utils/proto.h b/src/include/utils/proto.h index 0b3374f..df24278 100644 --- a/src/include/utils/proto.h +++ b/src/include/utils/proto.h @@ -67,7 +67,7 @@ typedef struct { const char *hostname; /* optional */ const char *parent; const char *key; - const sdb_data_t *value; + sdb_data_t value; } sdb_proto_attribute_t; /* @@ -164,6 +164,29 @@ sdb_proto_unmarshal_int32(const char *buf, size_t buf_len, uint32_t *v); ssize_t sdb_proto_unmarshal_data(const char *buf, size_t len, sdb_data_t *datum); +/* + * sdb_proto_unmarshal_host, sdb_proto_unmarshal_service, + * sdb_proto_unmarshal_metric, sdb_proto_unmarshal_attribute: + * Read and decode a host, service, metric, or attribute object from the + * specified string. + * + * Returns: + * - the number of bytes read on success + * - a negative value else + */ +ssize_t +sdb_proto_unmarshal_host(const char *buf, size_t len, + sdb_proto_host_t *host); +ssize_t +sdb_proto_unmarshal_service(const char *buf, size_t len, + sdb_proto_service_t *svc); +ssize_t +sdb_proto_unmarshal_metric(const char *buf, size_t len, + sdb_proto_metric_t *metric); +ssize_t +sdb_proto_unmarshal_attribute(const char *buf, size_t len, + sdb_proto_attribute_t *attr); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/utils/proto.c b/src/utils/proto.c index 07511ce..13d9129 100644 --- a/src/utils/proto.c +++ b/src/utils/proto.c @@ -235,6 +235,22 @@ marshal_obj_header(char *buf, size_t buf_len, return OBJ_HEADER_LEN; } /* marshal_obj_header */ +static ssize_t +unmarshal_obj_header(const char *buf, size_t len, + int *type, sdb_time_t *last_update) +{ + ssize_t n; + + if (len < OBJ_HEADER_LEN) + return -1; + + n = sdb_proto_unmarshal_int32(buf, len, (uint32_t *)type); + buf += n; len -= n; + if (unmarshal_datetime(buf, len, last_update) < 0) + return -1; + return OBJ_HEADER_LEN; +} /* unmarshal_obj_header */ + /* * public API */ @@ -446,14 +462,14 @@ sdb_proto_marshal_attribute(char *buf, size_t buf_len, size_t len; ssize_t n; - if ((! attr) || (! attr->parent) || (! attr->key) || (! attr->value) + if ((! attr) || (! attr->parent) || (! attr->key) || ((attr->parent_type != SDB_HOST) && (! attr->hostname)) || ((attr->parent_type != SDB_HOST) && (attr->parent_type != SDB_SERVICE) && (attr->parent_type != SDB_METRIC))) return -1; - n = sdb_proto_marshal_data(NULL, 0, attr->value); + n = sdb_proto_marshal_data(NULL, 0, &attr->value); if (n < 0) return -1; @@ -475,7 +491,7 @@ sdb_proto_marshal_attribute(char *buf, size_t buf_len, buf += n; buf_len -= n; n = marshal_string(buf, buf_len, attr->key); buf += n; buf_len -= n; - sdb_proto_marshal_data(buf, buf_len, attr->value); + sdb_proto_marshal_data(buf, buf_len, &attr->value); return len; } /* sdb_proto_marshal_attribute */ @@ -652,13 +668,7 @@ sdb_proto_unmarshal_data(const char *buf, size_t len, sdb_data_t *datum) sdb_data_free_datum(&d); return -1; } - if (len >= (size_t)n) { - buf += n; - len -= n; - l += n; - } - else - return -1; + buf += n; len -= n; l += n; } #undef V @@ -667,5 +677,120 @@ sdb_proto_unmarshal_data(const char *buf, size_t len, sdb_data_t *datum) return l; } /* sdb_proto_unmarshal_data */ +ssize_t +sdb_proto_unmarshal_host(const char *buf, size_t len, + sdb_proto_host_t *host) +{ + int type = 0; + ssize_t l = 0, n; + + if ((n = unmarshal_obj_header(buf, len, + &type, host ? &host->last_update : NULL)) < 0) + return n; + if (type != SDB_HOST) + return -1; + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, host ? &host->name : NULL)) < 0) + return n; + return l + n; +} /* sdb_proto_unmarshal_host */ + +ssize_t +sdb_proto_unmarshal_service(const char *buf, size_t len, + sdb_proto_service_t *svc) +{ + int type = 0; + ssize_t l = 0, n; + + if ((n = unmarshal_obj_header(buf, len, + &type, svc ? &svc->last_update : NULL)) < 0) + return n; + if (type != SDB_SERVICE) + return -1; + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, svc ? &svc->hostname : NULL)) < 0) + return n; + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, svc ? &svc->name : NULL)) < 0) + return n; + return l + n; +} /* sdb_proto_unmarshal_service */ + +ssize_t +sdb_proto_unmarshal_metric(const char *buf, size_t len, + sdb_proto_metric_t *metric) +{ + int type = 0; + ssize_t l = 0, n; + + if ((n = unmarshal_obj_header(buf, len, + &type, metric ? &metric->last_update : NULL)) < 0) + return n; + if (type != SDB_METRIC) + return -1; + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, + metric ? &metric->hostname : NULL)) < 0) + return n; + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, metric ? &metric->name : NULL)) < 0) + return n; + if (len > (size_t)n) { + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, + metric ? &metric->store_type : NULL)) < 0) + return n; + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, + metric ? &metric->store_id : NULL)) < 0) + return n; + } + else if (metric) { + metric->store_type = NULL; + metric->store_id = NULL; + } + return l + n; +} /* sdb_proto_unmarshal_metric */ + +ssize_t +sdb_proto_unmarshal_attribute(const char *buf, size_t len, + sdb_proto_attribute_t *attr) +{ + int parent_type, type = 0; + ssize_t l = 0, n; + + if ((n = unmarshal_obj_header(buf, len, + &type, attr ? &attr->last_update : NULL)) < 0) + return n; + buf += n; len -= n; l += n; + parent_type = type & 0xf; + if (type != (parent_type | SDB_ATTRIBUTE)) + return -1; + if ((parent_type != SDB_HOST) && (parent_type != SDB_SERVICE) + && (parent_type != SDB_METRIC)) + return -1; + if (attr) + attr->parent_type = parent_type; + + if (parent_type != SDB_HOST) { + if ((n = unmarshal_string(buf, len, + attr ? &attr->hostname : NULL)) < 0) + return n; + buf += n; len -= n; l += n; + } + else if (attr) + attr->hostname = NULL; + if ((n = unmarshal_string(buf, len, attr ? &attr->parent : NULL)) < 0) + return n; + buf += n; len -= n; l += n; + if ((n = unmarshal_string(buf, len, attr ? &attr->key : NULL)) < 0) + return n; + buf += n; len -= n; l += n; + if ((n = sdb_proto_unmarshal_data(buf, len, + attr ? &attr->value : NULL)) < 0) + return n; + return l + n; +} /* sdb_proto_unmarshal_attribute */ + /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/t/unit/utils/proto_test.c b/t/unit/utils/proto_test.c index 2412034..d82a40b 100644 --- a/t/unit/utils/proto_test.c +++ b/t/unit/utils/proto_test.c @@ -30,9 +30,18 @@ #include "libsysdb_test.h" #include +#include #include #include +static bool +streq(const char *s1, const char *s2) +{ + if ((! s1) || (! s2)) + return (s1 == NULL) == (s2 == NULL); + return strcmp(s1, s2) == 0; +} /* streq */ + START_TEST(test_marshal_data) { #define INT_TYPE "\0\0\0\1" @@ -225,6 +234,9 @@ START_TEST(test_marshal_host) ssize_t len = sdb_proto_marshal_host(NULL, 0, &golden_data[i].host); char buf[len > 0 ? len : 1]; + sdb_proto_host_t host; + ssize_t check; + fail_unless(len == golden_data[i].expected_len, "<%zu> sdb_proto_marshal_host(NULL, 0, %s) = %zi; expected: %zi", i, golden_data[i].host.name, len, golden_data[i].expected_len); @@ -247,6 +259,17 @@ START_TEST(test_marshal_host) i, golden_data[i].host.name, buf, golden_data[i].expected, pos, (int)buf[pos], (int)golden_data[i].expected[pos]); } + + check = sdb_proto_unmarshal_host(buf, len, &host); + fail_unless(check == len, + "<%zu> sdb_proto_unmarshal_host(buf<%s>) = %zi; expected: %zi", + i, golden_data[i].host.name, check, len); + fail_unless((host.last_update == golden_data[i].host.last_update) + && streq(host.name, golden_data[i].host.name), + "<%zu> sdb_proto_unmarshal_host(buf<%s>) = { %"PRIsdbTIME", %s }; " + "expected: { %"PRIsdbTIME", %s }", i, golden_data[i].host.name, + host.last_update, host.name, golden_data[i].host.last_update, + golden_data[i].host.name); } } END_TEST @@ -277,6 +300,9 @@ START_TEST(test_marshal_service) ssize_t len = sdb_proto_marshal_service(NULL, 0, &golden_data[i].svc); char buf[len > 0 ? len : 1]; + sdb_proto_service_t svc; + ssize_t check; + fail_unless(len == golden_data[i].expected_len, "<%zu> sdb_proto_marshal_service(NULL, 0, %s) = %zi; expected: %zi", i, golden_data[i].svc.name, len, golden_data[i].expected_len); @@ -299,6 +325,18 @@ START_TEST(test_marshal_service) i, golden_data[i].svc.name, buf, golden_data[i].expected, pos, (int)buf[pos], (int)golden_data[i].expected[pos]); } + + check = sdb_proto_unmarshal_service(buf, len, &svc); + fail_unless(check == len, + "<%zu> sdb_proto_unmarshal_service(buf<%s>) = %zi; expected: %zi", + i, golden_data[i].svc.name, check, len); + fail_unless((svc.last_update == golden_data[i].svc.last_update) + && streq(svc.hostname, golden_data[i].svc.hostname) + && streq(svc.name, golden_data[i].svc.name), + "<%zu> sdb_proto_unmarshal_service(buf<%s>) = { %"PRIsdbTIME", %s, %s }; " + "expected: { %"PRIsdbTIME", %s, %s }", i, golden_data[i].svc.name, + svc.last_update, svc.hostname, svc.name, golden_data[i].svc.last_update, + golden_data[i].svc.hostname, golden_data[i].svc.name); } } END_TEST @@ -341,6 +379,9 @@ START_TEST(test_marshal_metric) ssize_t len = sdb_proto_marshal_metric(NULL, 0, &golden_data[i].metric); char buf[len > 0 ? len : 1]; + sdb_proto_metric_t metric; + ssize_t check; + fail_unless(len == golden_data[i].expected_len, "<%zu> sdb_proto_marshal_metric(NULL, 0, %s) = %zi; expected: %zi", i, golden_data[i].metric.name, len, golden_data[i].expected_len); @@ -363,37 +404,61 @@ START_TEST(test_marshal_metric) i, golden_data[i].metric.name, buf, golden_data[i].expected, pos, (int)buf[pos], (int)golden_data[i].expected[pos]); } + + if ((! golden_data[i].metric.store_type) + || (! golden_data[i].metric.store_id)) { + /* if any of these is NULL, we expect both to be NULL */ + golden_data[i].metric.store_type = NULL; + golden_data[i].metric.store_id = NULL; + } + + check = sdb_proto_unmarshal_metric(buf, len, &metric); + fail_unless(check == len, + "<%zu> sdb_proto_unmarshal_metric(buf<%s>) = %zi; expected: %zi", + i, golden_data[i].metric.name, check, len); + fail_unless((metric.last_update == golden_data[i].metric.last_update) + && streq(metric.hostname, golden_data[i].metric.hostname) + && streq(metric.name, golden_data[i].metric.name) + && streq(metric.store_type, golden_data[i].metric.store_type) + && streq(metric.store_id, golden_data[i].metric.store_id), + "<%zu> sdb_proto_unmarshal_metric(buf<%s>) = " + "{ %"PRIsdbTIME", %s, %s, %s, %s }; expected: " + "{ %"PRIsdbTIME", %s, %s, %s, %s }", i, golden_data[i].metric.name, + metric.last_update, metric.hostname, metric.name, + metric.store_type, metric.store_id, + golden_data[i].metric.last_update, + golden_data[i].metric.hostname, golden_data[i].metric.name, + golden_data[i].metric.store_type, golden_data[i].metric.store_id); } } END_TEST START_TEST(test_marshal_attribute) { - sdb_data_t v = { SDB_TYPE_NULL, { .integer = 0 } }; -#define VAL "\0\0\0\0" + sdb_data_t v = { SDB_TYPE_INTEGER, { .integer = 4711 } }; +#define VAL "\0\0\0\1" "\0\0\0\0\0\0\x12\x67" struct { sdb_proto_attribute_t attr; ssize_t expected_len; char *expected; } golden_data[] = { { - { 4711, SDB_HOST, NULL, "hostA", "k1", &v }, - 25, HOST_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "k1\0" VAL + { 4711, SDB_HOST, NULL, "hostA", "k1", v }, + 33, HOST_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "k1\0" VAL }, { - { 4711, SDB_SERVICE, "hostA", "svc1", "k1", &v }, - 30, SVC_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "svc1\0" "k1\0" VAL + { 4711, SDB_SERVICE, "hostA", "svc1", "k1", v }, + 38, SVC_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "svc1\0" "k1\0" VAL }, { - { 4711, SDB_METRIC, "hostA", "m1", "k1", &v }, - 28, METRIC_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "m1\0" "k1\0" VAL + { 4711, SDB_METRIC, "hostA", "m1", "k1", v }, + 36, METRIC_ATTR_TYPE "\0\0\0\0\0\0\x12\x67" "hostA\0" "m1\0" "k1\0" VAL }, - { { 4711, SDB_HOST, NULL, NULL, "k1", &v }, -1, NULL }, - { { 4711, SDB_HOST, NULL, "hostA", NULL, &v }, -1, NULL }, - { { 4711, SDB_HOST, NULL, "hostA", "k1", NULL }, -1, NULL }, - { { 4711, SDB_SERVICE, NULL, "svc1", "k1", &v }, -1, NULL }, - { { 4711, SDB_METRIC, NULL, "m1", "k1", &v }, -1, NULL }, - { { 4711, 0, "hostA", "svc1", "k1", &v }, -1, NULL }, + { { 4711, SDB_HOST, NULL, NULL, "k1", v }, -1, NULL }, + { { 4711, SDB_HOST, NULL, "hostA", NULL, v }, -1, NULL }, + { { 4711, SDB_SERVICE, NULL, "svc1", "k1", v }, -1, NULL }, + { { 4711, SDB_METRIC, NULL, "m1", "k1", v }, -1, NULL }, + { { 4711, 0, "hostA", "svc1", "k1", v }, -1, NULL }, }; size_t i; @@ -402,6 +467,11 @@ START_TEST(test_marshal_attribute) ssize_t len = sdb_proto_marshal_attribute(NULL, 0, &golden_data[i].attr); char buf[len > 0 ? len : 1]; + sdb_proto_attribute_t attr; + ssize_t check; + char v1[sdb_data_strlen(&golden_data[i].attr.value) + 1]; + char v2[sdb_data_strlen(&golden_data[i].attr.value) + 1]; + fail_unless(len == golden_data[i].expected_len, "<%zu> sdb_proto_marshal_attribute(NULL, 0, %s) = %zi; expected: %zi", i, golden_data[i].attr.key, len, golden_data[i].expected_len); @@ -424,6 +494,32 @@ START_TEST(test_marshal_attribute) i, golden_data[i].attr.key, buf, golden_data[i].expected, pos, (int)buf[pos], (int)golden_data[i].expected[pos]); } + + if (sdb_data_format(&golden_data[i].attr.value, v1, sizeof(v1), 0) < 0) + snprintf(v1, sizeof(v1), ""); + + check = sdb_proto_unmarshal_attribute(buf, len, &attr); + fail_unless(check == len, + "<%zu> sdb_proto_unmarshal_attribute(buf<%s>) = %zi; expected: %zi", + i, golden_data[i].attr.key, check, len); + + if (sdb_data_format(&attr.value, v2, sizeof(v2), 0) < 0) + snprintf(v2, sizeof(v2), ""); + fail_unless((attr.last_update == golden_data[i].attr.last_update) + && (attr.parent_type == golden_data[i].attr.parent_type) + && streq(attr.hostname, golden_data[i].attr.hostname) + && streq(attr.parent, golden_data[i].attr.parent) + && streq(attr.key, golden_data[i].attr.key) + && (sdb_data_cmp(&attr.value, &golden_data[i].attr.value) == 0), + "<%zu> sdb_proto_unmarshal_attribute(buf<%s>) = " + "{ %"PRIsdbTIME", %s, %s, %s, %s, %s }; expected: " + "{ %"PRIsdbTIME", %s, %s, %s, %s, %s }", i, golden_data[i].attr.key, + attr.last_update, SDB_STORE_TYPE_TO_NAME(attr.parent_type), + attr.hostname, attr.parent, attr.key, v1, + golden_data[i].attr.last_update, + SDB_STORE_TYPE_TO_NAME(golden_data[i].attr.parent_type), + golden_data[i].attr.hostname, golden_data[i].attr.parent, + golden_data[i].attr.key, v2); } } END_TEST -- 2.30.2