Code

Let the network protocol and SysQL support last_update for metric stores.
[sysdb.git] / src / utils / proto.c
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 : */