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_bool(char *buf, size_t buf_len, bool v)
85 {
86 uint8_t t;
87 if (buf_len >= sizeof(t)) {
88 t = v ? 1 : 0;
89 memcpy(buf, &t, sizeof(t));
90 }
91 return sizeof(t);
92 } /* marshal_bool */
94 static ssize_t
95 unmarshal_bool(const char *buf, size_t len, bool *v)
96 {
97 uint8_t t;
98 if (len < sizeof(t))
99 return -1;
100 if (v) {
101 memcpy(&t, buf, sizeof(t));
102 *v = t != 0;
103 }
104 return sizeof(t);
105 } /* unmarshal_bool */
107 static ssize_t
108 marshal_int64(char *buf, size_t buf_len, int64_t v)
109 {
110 if (buf_len >= sizeof(v)) {
111 #if __BYTE_ORDER != __BIG_ENDIAN
112 v = endian_swap64(v);
113 #endif
114 memcpy(buf, &v, sizeof(v));
115 }
116 return sizeof(v);
117 } /* marshal_int64 */
119 static ssize_t
120 unmarshal_int64(const char *buf, size_t len, int64_t *v)
121 {
122 if (len < sizeof(*v))
123 return -1;
124 if (v) {
125 memcpy(v, buf, sizeof(*v));
126 #if __BYTE_ORDER != __BIG_ENDIAN
127 *v = endian_swap64(*v);
128 #endif
129 }
130 return sizeof(*v);
131 } /* unmarshal_int64 */
133 static ssize_t
134 marshal_double(char *buf, size_t buf_len, double v)
135 {
136 uint64_t t = 0;
137 assert(sizeof(v) == sizeof(t));
138 if (buf_len >= sizeof(t)) {
139 memcpy(&t, &v, sizeof(v));
140 #if IEEE754_DOUBLE_BYTE_ORDER != IEEE754_DOUBLE_BIG_ENDIAN
141 t = endian_swap64(t);
142 #endif
143 memcpy(buf, &t, sizeof(t));
144 }
145 return sizeof(t);
146 } /* marshal_double */
148 static ssize_t
149 unmarshal_double(const char *buf, size_t len, double *v)
150 {
151 uint64_t t;
152 assert(sizeof(*v) == sizeof(t));
153 if (len < sizeof(*v))
154 return -1;
155 if (v) {
156 memcpy(&t, buf, sizeof(t));
157 #if IEEE754_DOUBLE_BYTE_ORDER != IEEE754_DOUBLE_BIG_ENDIAN
158 t = endian_swap64(t);
159 #endif
160 memcpy(v, &t, sizeof(t));
161 }
162 return sizeof(*v);
163 } /* unmarshal_double */
165 static ssize_t
166 marshal_datetime(char *buf, size_t buf_len, sdb_time_t v)
167 {
168 return marshal_int64(buf, buf_len, (int64_t)v);
169 } /* marshal_datetime */
171 static ssize_t
172 unmarshal_datetime(const char *buf, size_t len, sdb_time_t *v)
173 {
174 return unmarshal_int64(buf, len, (int64_t *)v);
175 } /* unmarshal_datetime */
177 static ssize_t
178 marshal_binary(char *buf, size_t buf_len, size_t len, const unsigned char *v)
179 {
180 uint32_t tmp;
181 if (buf_len >= sizeof(tmp) + len) {
182 tmp = htonl((uint32_t)len);
183 memcpy(buf, &tmp, sizeof(tmp));
184 memcpy(buf + sizeof(tmp), v, len);
185 }
186 return sizeof(tmp) + len;
187 } /* marshal_binary */
189 static ssize_t
190 unmarshal_binary(const char *buf, size_t len,
191 size_t *v_len, const unsigned char **v)
192 {
193 uint32_t l;
194 ssize_t n;
196 if ((n = sdb_proto_unmarshal_int32(buf, len, &l)) < 0)
197 return -1;
198 buf += n; len -= n;
199 if (len < (size_t)l)
200 return -1;
202 if (v_len)
203 *v_len = (size_t)l;
204 if (v && (l > 0))
205 *v = (const unsigned char *)buf;
206 else if (v)
207 *v = NULL;
208 return sizeof(l) + (ssize_t)l;
209 } /* unmarshal_binary */
211 static ssize_t
212 marshal_string(char *buf, size_t buf_len, const char *v)
213 {
214 /* The actual string including the terminating null byte. */
215 size_t len = strlen(v) + 1;
216 if (buf_len >= len)
217 memcpy(buf, v, len);
218 return len;
219 } /* marshal_string */
221 static ssize_t
222 unmarshal_string(const char *buf, size_t len, const char **v)
223 {
224 size_t l = 0;
226 for (l = 0; l < len; ++l)
227 if (buf[l] == '\0')
228 break;
229 if (l == len)
230 return -1;
231 if (v)
232 *v = buf;
233 return l + 1;
234 } /* unmarshal_string */
236 #define OBJ_HEADER_LEN (sizeof(uint32_t) + sizeof(sdb_time_t))
237 static ssize_t
238 marshal_obj_header(char *buf, size_t buf_len,
239 int type, sdb_time_t last_update)
240 {
241 ssize_t n;
243 if (buf_len < OBJ_HEADER_LEN)
244 return OBJ_HEADER_LEN;
246 n = sdb_proto_marshal_int32(buf, buf_len, (uint32_t)type);
247 buf += n; buf_len -= n;
248 marshal_datetime(buf, buf_len, last_update);
249 return OBJ_HEADER_LEN;
250 } /* marshal_obj_header */
252 static ssize_t
253 unmarshal_obj_header(const char *buf, size_t len,
254 int *type, sdb_time_t *last_update)
255 {
256 ssize_t n;
258 if (len < OBJ_HEADER_LEN)
259 return -1;
261 n = sdb_proto_unmarshal_int32(buf, len, (uint32_t *)type);
262 buf += n; len -= n;
263 if (unmarshal_datetime(buf, len, last_update) < 0)
264 return -1;
265 return OBJ_HEADER_LEN;
266 } /* unmarshal_obj_header */
268 /*
269 * public API
270 */
272 ssize_t
273 sdb_proto_marshal(char *buf, size_t buf_len, uint32_t code,
274 uint32_t msg_len, const char *msg)
275 {
276 size_t len = 2 * sizeof(uint32_t) + msg_len;
277 uint32_t tmp;
279 if (buf_len < 2 * sizeof(uint32_t))
280 return -1;
281 if (buf_len < len) /* crop message */
282 msg_len -= (uint32_t)(len - buf_len);
284 tmp = htonl(code);
285 memcpy(buf, &tmp, sizeof(tmp));
286 tmp = htonl(msg_len);
287 memcpy(buf + sizeof(tmp), &tmp, sizeof(tmp));
289 if (msg_len)
290 memcpy(buf + 2 * sizeof(tmp), msg, msg_len);
291 return len;
292 } /* sdb_proto_marshal */
294 ssize_t
295 sdb_proto_marshal_int32(char *buf, size_t buf_len, uint32_t v)
296 {
297 if (buf_len >= sizeof(v)) {
298 v = htonl(v);
299 memcpy(buf, &v, sizeof(v));
300 }
301 return sizeof(v);
302 } /* sdb_proto_marshal_int32 */
304 ssize_t
305 sdb_proto_marshal_data(char *buf, size_t buf_len, const sdb_data_t *datum)
306 {
307 ssize_t len = 0, n = 0;
308 uint32_t tmp;
309 size_t i;
310 int type;
312 if (buf_len >= sizeof(tmp)) {
313 tmp = htonl((uint32_t)datum->type);
314 memcpy(buf, &tmp, sizeof(tmp));
315 buf += sizeof(tmp);
316 buf_len -= sizeof(tmp);
317 }
318 else
319 buf_len = 0;
320 len += sizeof(tmp);
322 if (datum->type == SDB_TYPE_NULL)
323 return len;
325 if (datum->type == SDB_TYPE_BOOLEAN)
326 n = marshal_bool(buf, buf_len, datum->data.boolean);
327 else if (datum->type == SDB_TYPE_INTEGER)
328 n = marshal_int64(buf, buf_len, datum->data.integer);
329 else if (datum->type == SDB_TYPE_DECIMAL)
330 n = marshal_double(buf, buf_len, datum->data.decimal);
331 else if (datum->type == SDB_TYPE_STRING)
332 n = marshal_string(buf, buf_len, datum->data.string);
333 else if (datum->type == SDB_TYPE_DATETIME)
334 n = marshal_datetime(buf, buf_len, datum->data.datetime);
335 else if (datum->type == SDB_TYPE_BINARY)
336 n = marshal_binary(buf, buf_len,
337 datum->data.binary.length, datum->data.binary.datum);
338 else if (datum->type == SDB_TYPE_REGEX)
339 n = marshal_string(buf, buf_len, datum->data.re.raw);
341 if (n < 0)
342 return n;
343 else if (n > 0)
344 return len + n;
346 if (! (datum->type & SDB_TYPE_ARRAY)) {
347 errno = EINVAL;
348 return -1;
349 }
351 /* arrays */
352 if (buf_len >= sizeof(tmp)) {
353 tmp = htonl((uint32_t)datum->data.array.length);
354 memcpy(buf, &tmp, sizeof(tmp));
355 buf += sizeof(tmp);
356 buf_len -= sizeof(tmp);
357 }
358 else
359 buf_len = 0;
360 len += sizeof(tmp);
362 type = datum->type & 0xff;
363 for (i = 0; i < datum->data.array.length; ++i) {
364 if (type == SDB_TYPE_BOOLEAN) {
365 bool *v = datum->data.array.values;
366 n = marshal_bool(buf, buf_len, v[i]);
367 }
368 else if (type == SDB_TYPE_INTEGER) {
369 int64_t *v = datum->data.array.values;
370 n = marshal_int64(buf, buf_len, v[i]);
371 }
372 else if (type == SDB_TYPE_DECIMAL) {
373 double *v = datum->data.array.values;
374 n = marshal_double(buf, buf_len, v[i]);
375 }
376 else if (type == SDB_TYPE_STRING) {
377 char **v = datum->data.array.values;
378 n = marshal_string(buf, buf_len, v[i]);
379 }
380 else if (type == SDB_TYPE_DATETIME) {
381 sdb_time_t *v = datum->data.array.values;
382 n = marshal_datetime(buf, buf_len, v[i]);
383 }
384 else if (type == SDB_TYPE_BINARY) {
385 struct {
386 size_t length;
387 unsigned char *datum;
388 } *v = datum->data.array.values;
389 n = marshal_binary(buf, buf_len, v[i].length, v[i].datum);
390 }
391 else if (type == SDB_TYPE_REGEX) {
392 struct {
393 char *raw;
394 regex_t regex;
395 } *v = datum->data.array.values;
396 n = marshal_string(buf, buf_len, v[i].raw);
397 }
398 else {
399 errno = EINVAL;
400 return -1;
401 }
403 if (n < 0)
404 return -1;
405 if (buf_len >= (size_t)n) {
406 buf += n;
407 buf_len -= n;
408 }
409 else
410 buf_len = 0;
411 len += n;
412 }
413 return len;
414 } /* sdb_proto_marshal_data */
416 ssize_t
417 sdb_proto_marshal_host(char *buf, size_t buf_len,
418 const sdb_proto_host_t *host)
419 {
420 size_t len;
421 ssize_t n;
423 if ((! host) || (! host->name))
424 return -1;
426 len = OBJ_HEADER_LEN + strlen(host->name) + 1;
427 if (buf_len < len)
428 return len;
430 n = marshal_obj_header(buf, buf_len, SDB_HOST, host->last_update);
431 buf += n; buf_len -= n;
432 marshal_string(buf, buf_len, host->name);
433 return len;
434 } /* sdb_proto_marshal_host */
436 ssize_t
437 sdb_proto_marshal_service(char *buf, size_t buf_len,
438 const sdb_proto_service_t *svc)
439 {
440 size_t len;
441 ssize_t n;
443 if ((! svc) || (! svc->hostname) || (! svc->name))
444 return -1;
446 len = OBJ_HEADER_LEN + strlen(svc->hostname) + strlen(svc->name) + 2;
447 if (buf_len < len)
448 return len;
450 n = marshal_obj_header(buf, buf_len, SDB_SERVICE, svc->last_update);
451 buf += n; buf_len -= n;
452 n = marshal_string(buf, buf_len, svc->hostname);
453 buf += n; buf_len -= n;
454 marshal_string(buf, buf_len, svc->name);
455 return len;
456 } /* sdb_proto_marshal_service */
458 ssize_t
459 sdb_proto_marshal_metric(char *buf, size_t buf_len,
460 const sdb_proto_metric_t *metric)
461 {
462 size_t len;
463 ssize_t n;
465 if ((! metric) || (! metric->hostname) || (! metric->name))
466 return -1;
468 len = OBJ_HEADER_LEN + strlen(metric->hostname) + strlen(metric->name) + 2;
469 if (metric->store_type && metric->store_id) {
470 len += strlen(metric->store_type) + strlen(metric->store_id) + 2;
471 if (metric->store_last_update > 0)
472 len += sizeof(sdb_time_t);
473 }
474 if (buf_len < len)
475 return len;
477 n = marshal_obj_header(buf, buf_len, SDB_METRIC, metric->last_update);
478 buf += n; buf_len -= n;
479 n = marshal_string(buf, buf_len, metric->hostname);
480 buf += n; buf_len -= n;
481 n = marshal_string(buf, buf_len, metric->name);
482 buf += n; buf_len -= n;
483 if (metric->store_type && metric->store_id) {
484 n = marshal_string(buf, buf_len, metric->store_type);
485 buf += n; buf_len -= n;
486 n = marshal_string(buf, buf_len, metric->store_id);
487 buf += n; buf_len -= n;
488 if (metric->store_last_update > 0) {
489 n = marshal_datetime(buf, buf_len, metric->store_last_update);
490 buf += n; buf_len -= n;
491 }
492 }
493 return len;
494 } /* sdb_proto_marshal_metric */
496 ssize_t
497 sdb_proto_marshal_attribute(char *buf, size_t buf_len,
498 const sdb_proto_attribute_t *attr)
499 {
500 size_t len;
501 ssize_t n;
503 if ((! attr) || (! attr->parent) || (! attr->key)
504 || ((attr->parent_type != SDB_HOST) && (! attr->hostname))
505 || ((attr->parent_type != SDB_HOST)
506 && (attr->parent_type != SDB_SERVICE)
507 && (attr->parent_type != SDB_METRIC)))
508 return -1;
510 n = sdb_proto_marshal_data(NULL, 0, &attr->value);
511 if (n < 0)
512 return -1;
514 len = OBJ_HEADER_LEN
515 + strlen(attr->parent) + strlen(attr->key) + 2 + (size_t)n;
516 if (attr->parent_type != SDB_HOST)
517 len += strlen(attr->hostname) + 1;
518 if (buf_len < len)
519 return len;
521 n = marshal_obj_header(buf, buf_len,
522 attr->parent_type | SDB_ATTRIBUTE, attr->last_update);
523 buf += n; buf_len -= n;
524 if (attr->parent_type != SDB_HOST) {
525 n = marshal_string(buf, buf_len, attr->hostname);
526 buf += n; buf_len -= n;
527 }
528 n = marshal_string(buf, buf_len, attr->parent);
529 buf += n; buf_len -= n;
530 n = marshal_string(buf, buf_len, attr->key);
531 buf += n; buf_len -= n;
532 sdb_proto_marshal_data(buf, buf_len, &attr->value);
533 return len;
534 } /* sdb_proto_marshal_attribute */
536 ssize_t
537 sdb_proto_unmarshal_header(const char *buf, size_t buf_len,
538 uint32_t *code, uint32_t *msg_len)
539 {
540 uint32_t tmp;
541 ssize_t n;
543 if (buf_len < 2 * sizeof(uint32_t))
544 return -1;
546 n = sdb_proto_unmarshal_int32(buf, buf_len, &tmp);
547 if (code)
548 *code = tmp;
549 buf += n; buf_len -= n;
550 sdb_proto_unmarshal_int32(buf, buf_len, &tmp);
551 if (msg_len)
552 *msg_len = tmp;
553 return 2 * sizeof(uint32_t);
554 } /* sdb_proto_unmarshal_header */
556 ssize_t
557 sdb_proto_unmarshal_int32(const char *buf, size_t buf_len, uint32_t *v)
558 {
559 uint32_t n;
561 /* not enough data to read */
562 if (buf_len < sizeof(n))
563 return -1;
565 memcpy(&n, buf, sizeof(n));
566 if (v)
567 *v = ntohl(n);
568 return sizeof(n);
569 } /* sdb_proto_unmarshal_int32 */
571 ssize_t
572 sdb_proto_unmarshal_data(const char *buf, size_t len, sdb_data_t *datum)
573 {
574 sdb_data_t d = SDB_DATA_INIT;
575 ssize_t l = 0, n;
576 uint32_t tmp;
577 size_t i;
579 if ((n = sdb_proto_unmarshal_int32(buf, len, &tmp)) < 0)
580 return -1;
581 d.type = (int)tmp;
582 if (d.type == SDB_TYPE_NULL)
583 return sizeof(tmp);
584 buf += n; len -= n; l += n;
586 /* Don't populate 'd' if 'datum' is NULL. */
587 #define D(field) (datum ? &d.data.field : NULL)
588 if (d.type == SDB_TYPE_BOOLEAN)
589 n = unmarshal_bool(buf, len, D(boolean));
590 else if (d.type == SDB_TYPE_INTEGER)
591 n = unmarshal_int64(buf, len, D(integer));
592 else if (d.type == SDB_TYPE_DECIMAL)
593 n = unmarshal_double(buf, len, D(decimal));
594 else if (d.type == SDB_TYPE_STRING) {
595 const char *str = NULL;
596 n = unmarshal_string(buf, len, &str);
597 if ((n > 0) && datum)
598 if (! (d.data.string = strdup(str)))
599 n = -1;
600 }
601 else if (d.type == SDB_TYPE_DATETIME)
602 n = unmarshal_datetime(buf, len, D(datetime));
603 else if (d.type == SDB_TYPE_BINARY) {
604 const unsigned char *data = NULL;
605 n = unmarshal_binary(buf, len, D(binary.length), &data);
606 if ((n > 0) && datum)
607 if (! (d.data.binary.datum = memdup(data, d.data.binary.length)))
608 n = -1;
609 }
610 else if (d.type == SDB_TYPE_REGEX) {
611 if (datum) {
612 const char *str = NULL;
613 n = unmarshal_string(buf, len, &str);
614 if (sdb_data_parse(str, SDB_TYPE_REGEX, &d))
615 n = -1;
616 }
617 else
618 n = unmarshal_string(buf, len, NULL);
619 }
620 else
621 n = 0;
622 #undef D
624 if (n < 0)
625 return n;
626 else if (n > 0) {
627 if (datum)
628 *datum = d;
629 return l + n;
630 }
632 if (! (d.type & SDB_TYPE_ARRAY)) {
633 errno = EINVAL;
634 return -1;
635 }
637 /* arrays */
638 if ((n = sdb_proto_unmarshal_int32(buf, len, &tmp)) < 0)
639 return -1;
640 buf += n; len -= n; l += n;
641 d.data.array.length = (size_t)tmp;
643 #define V(field) (datum ? &v[i]field : NULL)
644 if (datum)
645 d.data.array.values = calloc(d.data.array.length,
646 sdb_data_sizeof(d.type & 0xff));
647 for (i = 0; i < d.data.array.length; ++i) {
648 if ((d.type & 0xff) == SDB_TYPE_BOOLEAN) {
649 bool *v = d.data.array.values;
650 n = unmarshal_bool(buf, len, V());
651 }
652 else if ((d.type & 0xff) == SDB_TYPE_INTEGER) {
653 int64_t *v = d.data.array.values;
654 n = unmarshal_int64(buf, len, V());
655 }
656 else if ((d.type & 0xff) == SDB_TYPE_DECIMAL) {
657 double *v = d.data.array.values;
658 n = unmarshal_double(buf, len, V());
659 }
660 else if ((d.type & 0xff) == SDB_TYPE_STRING) {
661 char **v = d.data.array.values;
662 const char *str = NULL;
663 n = unmarshal_string(buf, len, &str);
664 if ((n > 0) && datum)
665 if (! (v[i] = strdup(str)))
666 n = -1;
667 }
668 else if ((d.type & 0xff) == SDB_TYPE_DATETIME) {
669 sdb_time_t *v = d.data.array.values;
670 n = unmarshal_datetime(buf, len, V());
671 }
672 else if ((d.type & 0xff) == SDB_TYPE_BINARY) {
673 struct {
674 size_t length;
675 unsigned char *datum;
676 } *v = d.data.array.values;
677 const unsigned char *data = NULL;
679 n = unmarshal_binary(buf, len, V(.length), &data);
680 if ((n > 0) && datum)
681 if (! (v[i].datum = memdup(data, v[i].length)))
682 n = -1;
683 }
684 else if ((d.type & 0xff) == SDB_TYPE_REGEX) {
685 struct {
686 char *raw;
687 regex_t regex;
688 } *v = d.data.array.values;
689 if (datum) {
690 sdb_data_t t = SDB_DATA_INIT;
691 const char *str = NULL;
692 n = unmarshal_string(buf, len, &str);
693 if (! sdb_data_parse(str, SDB_TYPE_REGEX, &t)) {
694 v[i].raw = t.data.re.raw;
695 v[i].regex = t.data.re.regex;
696 }
697 else
698 n = -1;
699 }
700 else
701 n = unmarshal_string(buf, len, NULL);
702 }
703 else {
704 if (datum)
705 sdb_data_free_datum(&d);
706 errno = EINVAL;
707 return -1;
708 }
710 if (n < 0) {
711 if (datum)
712 sdb_data_free_datum(&d);
713 return -1;
714 }
715 buf += n; len -= n; l += n;
716 }
717 #undef V
719 if (datum)
720 *datum = d;
721 return l;
722 } /* sdb_proto_unmarshal_data */
724 ssize_t
725 sdb_proto_unmarshal_host(const char *buf, size_t len,
726 sdb_proto_host_t *host)
727 {
728 int type = 0;
729 ssize_t l = 0, n;
731 if ((n = unmarshal_obj_header(buf, len,
732 &type, host ? &host->last_update : NULL)) < 0)
733 return n;
734 if (type != SDB_HOST)
735 return -1;
736 buf += n; len -= n; l += n;
737 if ((n = unmarshal_string(buf, len, host ? &host->name : NULL)) < 0)
738 return n;
739 return l + n;
740 } /* sdb_proto_unmarshal_host */
742 ssize_t
743 sdb_proto_unmarshal_service(const char *buf, size_t len,
744 sdb_proto_service_t *svc)
745 {
746 int type = 0;
747 ssize_t l = 0, n;
749 if ((n = unmarshal_obj_header(buf, len,
750 &type, svc ? &svc->last_update : NULL)) < 0)
751 return n;
752 if (type != SDB_SERVICE)
753 return -1;
754 buf += n; len -= n; l += n;
755 if ((n = unmarshal_string(buf, len, svc ? &svc->hostname : NULL)) < 0)
756 return n;
757 buf += n; len -= n; l += n;
758 if ((n = unmarshal_string(buf, len, svc ? &svc->name : NULL)) < 0)
759 return n;
760 return l + n;
761 } /* sdb_proto_unmarshal_service */
763 ssize_t
764 sdb_proto_unmarshal_metric(const char *buf, size_t len,
765 sdb_proto_metric_t *metric)
766 {
767 int type = 0;
768 ssize_t l = 0, n;
770 if ((n = unmarshal_obj_header(buf, len,
771 &type, metric ? &metric->last_update : NULL)) < 0)
772 return n;
773 if (type != SDB_METRIC)
774 return -1;
775 buf += n; len -= n; l += n;
776 if ((n = unmarshal_string(buf, len,
777 metric ? &metric->hostname : NULL)) < 0)
778 return n;
779 buf += n; len -= n; l += n;
780 if ((n = unmarshal_string(buf, len, metric ? &metric->name : NULL)) < 0)
781 return n;
783 metric->store_last_update = 0;
784 if (len > (size_t)n) {
785 buf += n; len -= n; l += n;
786 if ((n = unmarshal_string(buf, len,
787 metric ? &metric->store_type : NULL)) < 0)
788 return n;
789 buf += n; len -= n; l += n;
790 if ((n = unmarshal_string(buf, len,
791 metric ? &metric->store_id : NULL)) < 0)
792 return n;
793 if (len >= sizeof(sdb_time_t)) {
794 buf += n; len -= n; l += n;
795 if ((n = unmarshal_datetime(buf, len,
796 metric ? &metric->store_last_update : NULL)) < 0)
797 return n;
798 }
799 }
800 else if (metric) {
801 metric->store_type = NULL;
802 metric->store_id = NULL;
803 }
804 return l + n;
805 } /* sdb_proto_unmarshal_metric */
807 ssize_t
808 sdb_proto_unmarshal_attribute(const char *buf, size_t len,
809 sdb_proto_attribute_t *attr)
810 {
811 int parent_type, type = 0;
812 ssize_t l = 0, n;
814 if ((n = unmarshal_obj_header(buf, len,
815 &type, attr ? &attr->last_update : NULL)) < 0)
816 return n;
817 buf += n; len -= n; l += n;
818 parent_type = type & 0xf;
819 if (type != (parent_type | SDB_ATTRIBUTE))
820 return -1;
821 if ((parent_type != SDB_HOST) && (parent_type != SDB_SERVICE)
822 && (parent_type != SDB_METRIC))
823 return -1;
824 if (attr)
825 attr->parent_type = parent_type;
827 if (parent_type != SDB_HOST) {
828 if ((n = unmarshal_string(buf, len,
829 attr ? &attr->hostname : NULL)) < 0)
830 return n;
831 buf += n; len -= n; l += n;
832 }
833 else if (attr)
834 attr->hostname = NULL;
835 if ((n = unmarshal_string(buf, len, attr ? &attr->parent : NULL)) < 0)
836 return n;
837 buf += n; len -= n; l += n;
838 if ((n = unmarshal_string(buf, len, attr ? &attr->key : NULL)) < 0)
839 return n;
840 buf += n; len -= n; l += n;
841 if ((n = sdb_proto_unmarshal_data(buf, len,
842 attr ? &attr->value : NULL)) < 0)
843 return n;
844 return l + n;
845 } /* sdb_proto_unmarshal_attribute */
847 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */