Code

proto: Make sdb_proto_marshal_int32 a public function.
[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_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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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 : */