1 /*
2 * SysDB - src/utils/proto.c
3 * Copyright (C) 2013 Sebastian 'tokkee' Harl <sh@tokkee.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #if HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include "core/data.h"
33 #include "core/store.h"
34 #include "core/time.h"
35 #include "utils/error.h"
36 #include "utils/proto.h"
38 #include <assert.h>
39 #include <errno.h>
41 #include <arpa/inet.h>
42 #include <limits.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <unistd.h>
48 #include <sys/select.h>
50 /*
51 * private helper functions
52 */
54 /* swap endianess of the specified 64-bit value */
55 static uint64_t
56 endian_swap64(uint64_t v)
57 {
58 return
59 (((v & 0xff00000000000000LL) >> 56) & 0x00000000000000ffLL)
60 | (((v & 0x00ff000000000000LL) >> 40) & 0x000000000000ff00LL)
61 | (((v & 0x0000ff0000000000LL) >> 24) & 0x0000000000ff0000LL)
62 | (((v & 0x000000ff00000000LL) >> 8) & 0x00000000ff000000LL)
63 | (((v & 0x00000000ff000000LL) << 8) & 0x000000ff00000000LL)
64 | (((v & 0x0000000000ff0000LL) << 24) & 0x0000ff0000000000LL)
65 | (((v & 0x000000000000ff00LL) << 40) & 0x00ff000000000000LL)
66 | (((v & 0x00000000000000ffLL) << 56) & 0xff00000000000000LL);
67 } /* endian_swap64 */
69 static unsigned char *
70 memdup(const unsigned char *d, size_t length)
71 {
72 unsigned char *v = malloc(length);
73 if (! v)
74 return NULL;
75 memcpy(v, d, length);
76 return v;
77 } /* memdup */
79 /* In case there's not enough buffer space, the marshal functions have to
80 * return the number of bytes that would have been written if enough space had
81 * been available. */
83 static ssize_t
84 marshal_int64(char *buf, size_t buf_len, int64_t v)
85 {
86 if (buf_len >= sizeof(v)) {
87 #if __BYTE_ORDER != __BIG_ENDIAN
88 v = endian_swap64(v);
89 #endif
90 memcpy(buf, &v, sizeof(v));
91 }
92 return sizeof(v);
93 } /* marshal_int64 */
95 static ssize_t
96 unmarshal_int64(const char *buf, size_t len, int64_t *v)
97 {
98 if (len < sizeof(*v))
99 return -1;
100 if (v) {
101 memcpy(v, buf, sizeof(*v));
102 #if __BYTE_ORDER != __BIG_ENDIAN
103 *v = endian_swap64(*v);
104 #endif
105 }
106 return sizeof(*v);
107 } /* unmarshal_int64 */
109 static ssize_t
110 marshal_double(char *buf, size_t buf_len, double v)
111 {
112 uint64_t t = 0;
113 assert(sizeof(v) == sizeof(t));
114 if (buf_len >= sizeof(t)) {
115 memcpy(&t, &v, sizeof(v));
116 #if IEEE754_DOUBLE_BYTE_ORDER != IEEE754_DOUBLE_BIG_ENDIAN
117 t = endian_swap64(t);
118 #endif
119 memcpy(buf, &t, sizeof(t));
120 }
121 return sizeof(t);
122 } /* marshal_double */
124 static ssize_t
125 unmarshal_double(const char *buf, size_t len, double *v)
126 {
127 uint64_t t;
128 assert(sizeof(*v) == sizeof(t));
129 if (len < sizeof(*v))
130 return -1;
131 if (v) {
132 memcpy(&t, buf, sizeof(t));
133 #if IEEE754_DOUBLE_BYTE_ORDER != IEEE754_DOUBLE_BIG_ENDIAN
134 t = endian_swap64(t);
135 #endif
136 memcpy(v, &t, sizeof(t));
137 }
138 return sizeof(*v);
139 } /* unmarshal_double */
141 static ssize_t
142 marshal_datetime(char *buf, size_t buf_len, sdb_time_t v)
143 {
144 return marshal_int64(buf, buf_len, (int64_t)v);
145 } /* marshal_datetime */
147 static ssize_t
148 unmarshal_datetime(const char *buf, size_t len, sdb_time_t *v)
149 {
150 return unmarshal_int64(buf, len, (int64_t *)v);
151 } /* unmarshal_datetime */
153 static ssize_t
154 marshal_binary(char *buf, size_t buf_len, size_t len, const unsigned char *v)
155 {
156 uint32_t tmp;
157 if (buf_len >= sizeof(tmp) + len) {
158 tmp = htonl((uint32_t)len);
159 memcpy(buf, &tmp, sizeof(tmp));
160 memcpy(buf + sizeof(tmp), v, len);
161 }
162 return sizeof(tmp) + len;
163 } /* marshal_binary */
165 static ssize_t
166 unmarshal_binary(const char *buf, size_t len,
167 size_t *v_len, const unsigned char **v)
168 {
169 uint32_t l;
170 ssize_t n;
172 if ((n = sdb_proto_unmarshal_int32(buf, len, &l)) < 0)
173 return -1;
174 buf += n; len -= n;
175 if (len < (size_t)l)
176 return -1;
178 if (v_len)
179 *v_len = (size_t)l;
180 if (v && (l > 0))
181 *v = (const unsigned char *)buf;
182 else if (v)
183 *v = NULL;
184 return sizeof(l) + (ssize_t)l;
185 } /* unmarshal_binary */
187 static ssize_t
188 marshal_string(char *buf, size_t buf_len, const char *v)
189 {
190 /* The actual string including the terminating null byte. */
191 size_t len = strlen(v) + 1;
192 if (buf_len >= len)
193 memcpy(buf, v, len);
194 return len;
195 } /* marshal_string */
197 static ssize_t
198 unmarshal_string(const char *buf, size_t len, const char **v)
199 {
200 size_t l = 0;
202 for (l = 0; l < len; ++l)
203 if (buf[l] == '\0')
204 break;
205 if (l == len)
206 return -1;
207 if (v)
208 *v = buf;
209 return l + 1;
210 } /* unmarshal_string */
212 #define OBJ_HEADER_LEN (sizeof(uint32_t) + sizeof(sdb_time_t))
213 static ssize_t
214 marshal_obj_header(char *buf, size_t buf_len,
215 int type, sdb_time_t last_update)
216 {
217 ssize_t n;
219 if (buf_len < OBJ_HEADER_LEN)
220 return OBJ_HEADER_LEN;
222 n = sdb_proto_marshal_int32(buf, buf_len, (uint32_t)type);
223 buf += n; buf_len -= n;
224 marshal_datetime(buf, buf_len, last_update);
225 return OBJ_HEADER_LEN;
226 } /* marshal_obj_header */
228 static ssize_t
229 unmarshal_obj_header(const char *buf, size_t len,
230 int *type, sdb_time_t *last_update)
231 {
232 ssize_t n;
234 if (len < OBJ_HEADER_LEN)
235 return -1;
237 n = sdb_proto_unmarshal_int32(buf, len, (uint32_t *)type);
238 buf += n; len -= n;
239 if (unmarshal_datetime(buf, len, last_update) < 0)
240 return -1;
241 return OBJ_HEADER_LEN;
242 } /* unmarshal_obj_header */
244 /*
245 * public API
246 */
248 ssize_t
249 sdb_proto_marshal(char *buf, size_t buf_len, uint32_t code,
250 uint32_t msg_len, const char *msg)
251 {
252 size_t len = 2 * sizeof(uint32_t) + msg_len;
253 uint32_t tmp;
255 if (buf_len < 2 * sizeof(uint32_t))
256 return -1;
257 if (buf_len < len) /* crop message */
258 msg_len -= (uint32_t)(len - buf_len);
260 tmp = htonl(code);
261 memcpy(buf, &tmp, sizeof(tmp));
262 tmp = htonl(msg_len);
263 memcpy(buf + sizeof(tmp), &tmp, sizeof(tmp));
265 if (msg_len)
266 memcpy(buf + 2 * sizeof(tmp), msg, msg_len);
267 return len;
268 } /* sdb_proto_marshal */
270 ssize_t
271 sdb_proto_marshal_int32(char *buf, size_t buf_len, uint32_t v)
272 {
273 if (buf_len >= sizeof(v)) {
274 v = htonl(v);
275 memcpy(buf, &v, sizeof(v));
276 }
277 return sizeof(v);
278 } /* sdb_proto_marshal_int32 */
280 ssize_t
281 sdb_proto_marshal_data(char *buf, size_t buf_len, const sdb_data_t *datum)
282 {
283 ssize_t len = 0, n = 0;
284 uint32_t tmp;
285 size_t i;
286 int type;
288 if (buf_len >= sizeof(tmp)) {
289 tmp = htonl((uint32_t)datum->type);
290 memcpy(buf, &tmp, sizeof(tmp));
291 buf += sizeof(tmp);
292 buf_len -= sizeof(tmp);
293 }
294 else
295 buf_len = 0;
296 len += sizeof(tmp);
298 if (datum->type == SDB_TYPE_NULL)
299 return len;
301 if (datum->type == SDB_TYPE_INTEGER)
302 n = marshal_int64(buf, buf_len, datum->data.integer);
303 else if (datum->type == SDB_TYPE_DECIMAL)
304 n = marshal_double(buf, buf_len, datum->data.decimal);
305 else if (datum->type == SDB_TYPE_STRING)
306 n = marshal_string(buf, buf_len, datum->data.string);
307 else if (datum->type == SDB_TYPE_DATETIME)
308 n = marshal_datetime(buf, buf_len, datum->data.datetime);
309 else if (datum->type == SDB_TYPE_BINARY)
310 n = marshal_binary(buf, buf_len,
311 datum->data.binary.length, datum->data.binary.datum);
312 else if (datum->type == SDB_TYPE_REGEX)
313 n = marshal_string(buf, buf_len, datum->data.re.raw);
315 if (n < 0)
316 return n;
317 else if (n > 0)
318 return len + n;
320 if (! (datum->type & SDB_TYPE_ARRAY)) {
321 errno = EINVAL;
322 return -1;
323 }
325 /* arrays */
326 if (buf_len >= sizeof(tmp)) {
327 tmp = htonl((uint32_t)datum->data.array.length);
328 memcpy(buf, &tmp, sizeof(tmp));
329 buf += sizeof(tmp);
330 buf_len -= sizeof(tmp);
331 }
332 else
333 buf_len = 0;
334 len += sizeof(tmp);
336 type = datum->type & 0xff;
337 for (i = 0; i < datum->data.array.length; ++i) {
338 if (type == SDB_TYPE_INTEGER) {
339 int64_t *v = datum->data.array.values;
340 n = marshal_int64(buf, buf_len, v[i]);
341 }
342 else if (type == SDB_TYPE_DECIMAL) {
343 double *v = datum->data.array.values;
344 n = marshal_double(buf, buf_len, v[i]);
345 }
346 else if (type == SDB_TYPE_STRING) {
347 char **v = datum->data.array.values;
348 n = marshal_string(buf, buf_len, v[i]);
349 }
350 else if (type == SDB_TYPE_DATETIME) {
351 sdb_time_t *v = datum->data.array.values;
352 n = marshal_datetime(buf, buf_len, v[i]);
353 }
354 else if (type == SDB_TYPE_BINARY) {
355 struct {
356 size_t length;
357 unsigned char *datum;
358 } *v = datum->data.array.values;
359 n = marshal_binary(buf, buf_len, v[i].length, v[i].datum);
360 }
361 else if (type == SDB_TYPE_REGEX) {
362 struct {
363 char *raw;
364 regex_t regex;
365 } *v = datum->data.array.values;
366 n = marshal_string(buf, buf_len, v[i].raw);
367 }
368 else {
369 errno = EINVAL;
370 return -1;
371 }
373 if (n < 0)
374 return -1;
375 if (buf_len >= (size_t)n) {
376 buf += n;
377 buf_len -= n;
378 }
379 else
380 buf_len = 0;
381 len += n;
382 }
383 return len;
384 } /* sdb_proto_marshal_data */
386 ssize_t
387 sdb_proto_marshal_host(char *buf, size_t buf_len,
388 const sdb_proto_host_t *host)
389 {
390 size_t len;
391 ssize_t n;
393 if ((! host) || (! host->name))
394 return -1;
396 len = OBJ_HEADER_LEN + strlen(host->name) + 1;
397 if (buf_len < len)
398 return len;
400 n = marshal_obj_header(buf, buf_len, SDB_HOST, host->last_update);
401 buf += n; buf_len -= n;
402 marshal_string(buf, buf_len, host->name);
403 return len;
404 } /* sdb_proto_marshal_host */
406 ssize_t
407 sdb_proto_marshal_service(char *buf, size_t buf_len,
408 const sdb_proto_service_t *svc)
409 {
410 size_t len;
411 ssize_t n;
413 if ((! svc) || (! svc->hostname) || (! svc->name))
414 return -1;
416 len = OBJ_HEADER_LEN + strlen(svc->hostname) + strlen(svc->name) + 2;
417 if (buf_len < len)
418 return len;
420 n = marshal_obj_header(buf, buf_len, SDB_SERVICE, svc->last_update);
421 buf += n; buf_len -= n;
422 n = marshal_string(buf, buf_len, svc->hostname);
423 buf += n; buf_len -= n;
424 marshal_string(buf, buf_len, svc->name);
425 return len;
426 } /* sdb_proto_marshal_service */
428 ssize_t
429 sdb_proto_marshal_metric(char *buf, size_t buf_len,
430 const sdb_proto_metric_t *metric)
431 {
432 size_t len;
433 ssize_t n;
435 if ((! metric) || (! metric->hostname) || (! metric->name))
436 return -1;
438 len = OBJ_HEADER_LEN + strlen(metric->hostname) + strlen(metric->name) + 2;
439 if (metric->store_type && metric->store_id)
440 len += strlen(metric->store_type) + strlen(metric->store_id) + 2;
441 if (buf_len < len)
442 return len;
444 n = marshal_obj_header(buf, buf_len, SDB_METRIC, metric->last_update);
445 buf += n; buf_len -= n;
446 n = marshal_string(buf, buf_len, metric->hostname);
447 buf += n; buf_len -= n;
448 n = marshal_string(buf, buf_len, metric->name);
449 buf += n; buf_len -= n;
450 if (metric->store_type && metric->store_id) {
451 n = marshal_string(buf, buf_len, metric->store_type);
452 buf += n; buf_len -= n;
453 marshal_string(buf, buf_len, metric->store_id);
454 }
455 return len;
456 } /* sdb_proto_marshal_metric */
458 ssize_t
459 sdb_proto_marshal_attribute(char *buf, size_t buf_len,
460 const sdb_proto_attribute_t *attr)
461 {
462 size_t len;
463 ssize_t n;
465 if ((! attr) || (! attr->parent) || (! attr->key)
466 || ((attr->parent_type != SDB_HOST) && (! attr->hostname))
467 || ((attr->parent_type != SDB_HOST)
468 && (attr->parent_type != SDB_SERVICE)
469 && (attr->parent_type != SDB_METRIC)))
470 return -1;
472 n = sdb_proto_marshal_data(NULL, 0, &attr->value);
473 if (n < 0)
474 return -1;
476 len = OBJ_HEADER_LEN
477 + strlen(attr->parent) + strlen(attr->key) + 2 + (size_t)n;
478 if (attr->parent_type != SDB_HOST)
479 len += strlen(attr->hostname) + 1;
480 if (buf_len < len)
481 return len;
483 n = marshal_obj_header(buf, buf_len,
484 attr->parent_type | SDB_ATTRIBUTE, attr->last_update);
485 buf += n; buf_len -= n;
486 if (attr->parent_type != SDB_HOST) {
487 n = marshal_string(buf, buf_len, attr->hostname);
488 buf += n; buf_len -= n;
489 }
490 n = marshal_string(buf, buf_len, attr->parent);
491 buf += n; buf_len -= n;
492 n = marshal_string(buf, buf_len, attr->key);
493 buf += n; buf_len -= n;
494 sdb_proto_marshal_data(buf, buf_len, &attr->value);
495 return len;
496 } /* sdb_proto_marshal_attribute */
498 ssize_t
499 sdb_proto_unmarshal_header(const char *buf, size_t buf_len,
500 uint32_t *code, uint32_t *msg_len)
501 {
502 uint32_t tmp;
503 ssize_t n;
505 if (buf_len < 2 * sizeof(uint32_t))
506 return -1;
508 n = sdb_proto_unmarshal_int32(buf, buf_len, &tmp);
509 if (code)
510 *code = tmp;
511 buf += n; buf_len -= n;
512 sdb_proto_unmarshal_int32(buf, buf_len, &tmp);
513 if (msg_len)
514 *msg_len = tmp;
515 return 2 * sizeof(uint32_t);
516 } /* sdb_proto_unmarshal_header */
518 ssize_t
519 sdb_proto_unmarshal_int32(const char *buf, size_t buf_len, uint32_t *v)
520 {
521 uint32_t n;
523 /* not enough data to read */
524 if (buf_len < sizeof(n))
525 return -1;
527 memcpy(&n, buf, sizeof(n));
528 if (v)
529 *v = ntohl(n);
530 return sizeof(n);
531 } /* sdb_proto_unmarshal_int32 */
533 ssize_t
534 sdb_proto_unmarshal_data(const char *buf, size_t len, sdb_data_t *datum)
535 {
536 sdb_data_t d = SDB_DATA_INIT;
537 ssize_t l = 0, n;
538 uint32_t tmp;
539 size_t i;
541 if ((n = sdb_proto_unmarshal_int32(buf, len, &tmp)) < 0)
542 return -1;
543 d.type = (int)tmp;
544 if (d.type == SDB_TYPE_NULL)
545 return sizeof(tmp);
546 buf += n; len -= n; l += n;
548 /* Don't populate 'd' if 'datum' is NULL. */
549 #define D(field) (datum ? &d.data.field : NULL)
550 if (d.type == SDB_TYPE_INTEGER)
551 n = unmarshal_int64(buf, len, D(integer));
552 else if (d.type == SDB_TYPE_DECIMAL)
553 n = unmarshal_double(buf, len, D(decimal));
554 else if (d.type == SDB_TYPE_STRING) {
555 const char *str = NULL;
556 n = unmarshal_string(buf, len, &str);
557 if ((n > 0) && datum)
558 if (! (d.data.string = strdup(str)))
559 n = -1;
560 }
561 else if (d.type == SDB_TYPE_DATETIME)
562 n = unmarshal_datetime(buf, len, D(datetime));
563 else if (d.type == SDB_TYPE_BINARY) {
564 const unsigned char *data = NULL;
565 n = unmarshal_binary(buf, len, D(binary.length), &data);
566 if ((n > 0) && datum)
567 if (! (d.data.binary.datum = memdup(data, d.data.binary.length)))
568 n = -1;
569 }
570 else if (d.type == SDB_TYPE_REGEX) {
571 if (datum) {
572 const char *str = NULL;
573 n = unmarshal_string(buf, len, &str);
574 if (sdb_data_parse(str, SDB_TYPE_REGEX, &d))
575 n = -1;
576 }
577 else
578 n = unmarshal_string(buf, len, NULL);
579 }
580 else
581 n = 0;
582 #undef D
584 if (n < 0)
585 return n;
586 else if (n > 0) {
587 if (datum)
588 *datum = d;
589 return l + n;
590 }
592 if (! (d.type & SDB_TYPE_ARRAY)) {
593 errno = EINVAL;
594 return -1;
595 }
597 /* arrays */
598 if ((n = sdb_proto_unmarshal_int32(buf, len, &tmp)) < 0)
599 return -1;
600 buf += n; len -= n; l += n;
601 d.data.array.length = (size_t)tmp;
603 #define V(field) (datum ? &v[i]field : NULL)
604 if (datum)
605 d.data.array.values = calloc(d.data.array.length,
606 sdb_data_sizeof(d.type & 0xff));
607 for (i = 0; i < d.data.array.length; ++i) {
608 if ((d.type & 0xff) == SDB_TYPE_INTEGER) {
609 int64_t *v = d.data.array.values;
610 n = unmarshal_int64(buf, len, V());
611 }
612 else if ((d.type & 0xff) == SDB_TYPE_DECIMAL) {
613 double *v = d.data.array.values;
614 n = unmarshal_double(buf, len, V());
615 }
616 else if ((d.type & 0xff) == SDB_TYPE_STRING) {
617 char **v = d.data.array.values;
618 const char *str = NULL;
619 n = unmarshal_string(buf, len, &str);
620 if ((n > 0) && datum)
621 if (! (v[i] = strdup(str)))
622 n = -1;
623 }
624 else if ((d.type & 0xff) == SDB_TYPE_DATETIME) {
625 sdb_time_t *v = d.data.array.values;
626 n = unmarshal_datetime(buf, len, V());
627 }
628 else if ((d.type & 0xff) == SDB_TYPE_BINARY) {
629 struct {
630 size_t length;
631 unsigned char *datum;
632 } *v = d.data.array.values;
633 const unsigned char *data = NULL;
635 n = unmarshal_binary(buf, len, V(.length), &data);
636 if ((n > 0) && datum)
637 if (! (v[i].datum = memdup(data, v[i].length)))
638 n = -1;
639 }
640 else if ((d.type & 0xff) == SDB_TYPE_REGEX) {
641 struct {
642 char *raw;
643 regex_t regex;
644 } *v = d.data.array.values;
645 if (datum) {
646 sdb_data_t t = SDB_DATA_INIT;
647 const char *str = NULL;
648 n = unmarshal_string(buf, len, &str);
649 if (! sdb_data_parse(str, SDB_TYPE_REGEX, &t)) {
650 v[i].raw = t.data.re.raw;
651 v[i].regex = t.data.re.regex;
652 }
653 else
654 n = -1;
655 }
656 else
657 n = unmarshal_string(buf, len, NULL);
658 }
659 else {
660 if (datum)
661 sdb_data_free_datum(&d);
662 errno = EINVAL;
663 return -1;
664 }
666 if (n < 0) {
667 if (datum)
668 sdb_data_free_datum(&d);
669 return -1;
670 }
671 buf += n; len -= n; l += n;
672 }
673 #undef V
675 if (datum)
676 *datum = d;
677 return l;
678 } /* sdb_proto_unmarshal_data */
680 ssize_t
681 sdb_proto_unmarshal_host(const char *buf, size_t len,
682 sdb_proto_host_t *host)
683 {
684 int type = 0;
685 ssize_t l = 0, n;
687 if ((n = unmarshal_obj_header(buf, len,
688 &type, host ? &host->last_update : NULL)) < 0)
689 return n;
690 if (type != SDB_HOST)
691 return -1;
692 buf += n; len -= n; l += n;
693 if ((n = unmarshal_string(buf, len, host ? &host->name : NULL)) < 0)
694 return n;
695 return l + n;
696 } /* sdb_proto_unmarshal_host */
698 ssize_t
699 sdb_proto_unmarshal_service(const char *buf, size_t len,
700 sdb_proto_service_t *svc)
701 {
702 int type = 0;
703 ssize_t l = 0, n;
705 if ((n = unmarshal_obj_header(buf, len,
706 &type, svc ? &svc->last_update : NULL)) < 0)
707 return n;
708 if (type != SDB_SERVICE)
709 return -1;
710 buf += n; len -= n; l += n;
711 if ((n = unmarshal_string(buf, len, svc ? &svc->hostname : NULL)) < 0)
712 return n;
713 buf += n; len -= n; l += n;
714 if ((n = unmarshal_string(buf, len, svc ? &svc->name : NULL)) < 0)
715 return n;
716 return l + n;
717 } /* sdb_proto_unmarshal_service */
719 ssize_t
720 sdb_proto_unmarshal_metric(const char *buf, size_t len,
721 sdb_proto_metric_t *metric)
722 {
723 int type = 0;
724 ssize_t l = 0, n;
726 if ((n = unmarshal_obj_header(buf, len,
727 &type, metric ? &metric->last_update : NULL)) < 0)
728 return n;
729 if (type != SDB_METRIC)
730 return -1;
731 buf += n; len -= n; l += n;
732 if ((n = unmarshal_string(buf, len,
733 metric ? &metric->hostname : NULL)) < 0)
734 return n;
735 buf += n; len -= n; l += n;
736 if ((n = unmarshal_string(buf, len, metric ? &metric->name : NULL)) < 0)
737 return n;
738 if (len > (size_t)n) {
739 buf += n; len -= n; l += n;
740 if ((n = unmarshal_string(buf, len,
741 metric ? &metric->store_type : NULL)) < 0)
742 return n;
743 buf += n; len -= n; l += n;
744 if ((n = unmarshal_string(buf, len,
745 metric ? &metric->store_id : NULL)) < 0)
746 return n;
747 }
748 else if (metric) {
749 metric->store_type = NULL;
750 metric->store_id = NULL;
751 }
752 return l + n;
753 } /* sdb_proto_unmarshal_metric */
755 ssize_t
756 sdb_proto_unmarshal_attribute(const char *buf, size_t len,
757 sdb_proto_attribute_t *attr)
758 {
759 int parent_type, type = 0;
760 ssize_t l = 0, n;
762 if ((n = unmarshal_obj_header(buf, len,
763 &type, attr ? &attr->last_update : NULL)) < 0)
764 return n;
765 buf += n; len -= n; l += n;
766 parent_type = type & 0xf;
767 if (type != (parent_type | SDB_ATTRIBUTE))
768 return -1;
769 if ((parent_type != SDB_HOST) && (parent_type != SDB_SERVICE)
770 && (parent_type != SDB_METRIC))
771 return -1;
772 if (attr)
773 attr->parent_type = parent_type;
775 if (parent_type != SDB_HOST) {
776 if ((n = unmarshal_string(buf, len,
777 attr ? &attr->hostname : NULL)) < 0)
778 return n;
779 buf += n; len -= n; l += n;
780 }
781 else if (attr)
782 attr->hostname = NULL;
783 if ((n = unmarshal_string(buf, len, attr ? &attr->parent : NULL)) < 0)
784 return n;
785 buf += n; len -= n; l += n;
786 if ((n = unmarshal_string(buf, len, attr ? &attr->key : NULL)) < 0)
787 return n;
788 buf += n; len -= n; l += n;
789 if ((n = sdb_proto_unmarshal_data(buf, len,
790 attr ? &attr->value : NULL)) < 0)
791 return n;
792 return l + n;
793 } /* sdb_proto_unmarshal_attribute */
795 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */