ctdb-protocol: Fix marshalling for tdb_data
[kai/samba-autobuild/.git] / ctdb / protocol / protocol_types.c
1 /*
2    CTDB protocol marshalling
3
4    Copyright (C) Amitay Isaacs  2015-2017
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21 #include "system/network.h"
22
23 #include <talloc.h>
24 #include <tdb.h>
25
26 #include "protocol.h"
27 #include "protocol_private.h"
28 #include "protocol_api.h"
29
30 size_t ctdb_tdb_data_len(TDB_DATA *in)
31 {
32         return in->dsize > UINT32_MAX ? UINT32_MAX : in->dsize;
33 }
34
35 void ctdb_tdb_data_push(TDB_DATA *in, uint8_t *buf, size_t *npush)
36 {
37         size_t len = ctdb_tdb_data_len(in);
38
39         if (len > 0) {
40                 memcpy(buf, in->dptr, len);
41         }
42
43         *npush = len;
44 }
45
46 int ctdb_tdb_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
47                        TDB_DATA *out, size_t *npull)
48 {
49         TDB_DATA val;
50
51         if (buflen > UINT32_MAX) {
52                 return EMSGSIZE;
53         }
54
55         val.dsize = buflen;
56         if (val.dsize > 0) {
57                 val.dptr = talloc_memdup(mem_ctx, buf, buflen);
58                 if (val.dptr == NULL) {
59                         return ENOMEM;
60                 }
61         } else {
62                 val.dptr = NULL;
63         }
64
65         *out = val;
66         *npull = buflen;
67         return 0;
68 }
69
70 size_t ctdb_statistics_len(struct ctdb_statistics *stats)
71 {
72         return sizeof(struct ctdb_statistics);
73 }
74
75 void ctdb_statistics_push(struct ctdb_statistics *stats, uint8_t *buf)
76 {
77         memcpy(buf, stats, sizeof(struct ctdb_statistics));
78 }
79
80 int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
81                          struct ctdb_statistics **out)
82 {
83         struct ctdb_statistics *stats;
84         struct ctdb_statistics *wire = (struct ctdb_statistics *)buf;
85
86         if (buflen < sizeof(struct ctdb_statistics)) {
87                 return EMSGSIZE;
88         }
89
90         stats = talloc(mem_ctx, struct ctdb_statistics);
91         if (stats == NULL) {
92                 return ENOMEM;
93         }
94         memcpy(stats, wire, sizeof(struct ctdb_statistics));
95
96         *out = stats;
97         return 0;
98 }
99
100 struct ctdb_statistics_list_wire {
101         uint32_t num;
102         struct ctdb_statistics stats[1];
103 };
104
105 size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list)
106 {
107         return offsetof(struct ctdb_statistics_list_wire, stats) +
108                stats_list->num * sizeof(struct ctdb_statistics);
109 }
110
111 void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list,
112                                uint8_t *buf)
113 {
114         struct ctdb_statistics_list_wire *wire =
115                 (struct ctdb_statistics_list_wire *)buf;
116
117         wire->num = stats_list->num;
118         memcpy(wire->stats, stats_list->stats,
119                stats_list->num * sizeof(struct ctdb_statistics));
120 }
121
122 int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
123                               struct ctdb_statistics_list **out)
124 {
125         struct ctdb_statistics_list *stats_list;
126         struct ctdb_statistics_list_wire *wire =
127                 (struct ctdb_statistics_list_wire *)buf;
128
129         if (buflen < offsetof(struct ctdb_statistics_list_wire, stats)) {
130                 return EMSGSIZE;
131         }
132         if (wire->num > buflen / sizeof(struct ctdb_statistics)) {
133                 return EMSGSIZE;
134         }
135         if (offsetof(struct ctdb_statistics_list_wire, stats) +
136             wire->num * sizeof(struct ctdb_statistics) <
137             offsetof(struct ctdb_statistics_list_wire, stats)) {
138                 return EMSGSIZE;
139         }
140         if (buflen < offsetof(struct ctdb_statistics_list_wire, stats) +
141                      wire->num * sizeof(struct ctdb_statistics)) {
142                 return EMSGSIZE;
143         }
144
145         stats_list = talloc(mem_ctx, struct ctdb_statistics_list);
146         if (stats_list == NULL) {
147                 return ENOMEM;
148         }
149
150         stats_list->num = wire->num;
151
152         stats_list->stats = talloc_array(stats_list, struct ctdb_statistics,
153                                          wire->num);
154         if (stats_list->stats == NULL) {
155                 talloc_free(stats_list);
156                 return ENOMEM;
157         }
158
159         memcpy(stats_list->stats, wire->stats,
160                wire->num * sizeof(struct ctdb_statistics));
161
162         *out = stats_list;
163         return 0;
164 }
165
166 struct ctdb_vnn_map_wire {
167         uint32_t generation;
168         uint32_t size;
169         uint32_t map[1];
170 };
171
172 size_t ctdb_vnn_map_len(struct ctdb_vnn_map *vnnmap)
173 {
174         return offsetof(struct ctdb_vnn_map, map) +
175                vnnmap->size * sizeof(uint32_t);
176 }
177
178 void ctdb_vnn_map_push(struct ctdb_vnn_map *vnnmap, uint8_t *buf)
179 {
180         struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
181
182         memcpy(wire, vnnmap, offsetof(struct ctdb_vnn_map, map));
183         memcpy(wire->map, vnnmap->map, vnnmap->size * sizeof(uint32_t));
184 }
185
186 int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
187                       struct ctdb_vnn_map **out)
188 {
189         struct ctdb_vnn_map *vnnmap;
190         struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
191
192         if (buflen < offsetof(struct ctdb_vnn_map_wire, map)) {
193                 return EMSGSIZE;
194         }
195         if (wire->size > buflen / sizeof(uint32_t)) {
196                 return EMSGSIZE;
197         }
198         if (offsetof(struct ctdb_vnn_map_wire, map) +
199             wire->size * sizeof(uint32_t) <
200             offsetof(struct ctdb_vnn_map_wire, map)) {
201                     return EMSGSIZE;
202         }
203         if (buflen < offsetof(struct ctdb_vnn_map_wire, map) +
204                      wire->size * sizeof(uint32_t)) {
205                 return EMSGSIZE;
206         }
207
208         vnnmap = talloc(mem_ctx, struct ctdb_vnn_map);
209         if (vnnmap == NULL) {
210                 return ENOMEM;
211         }
212
213         memcpy(vnnmap, wire, offsetof(struct ctdb_vnn_map, map));
214
215         vnnmap->map = talloc_memdup(vnnmap, wire->map,
216                                     wire->size * sizeof(uint32_t));
217         if (vnnmap->map == NULL) {
218                 talloc_free(vnnmap);
219                 return ENOMEM;
220         }
221
222         *out = vnnmap;
223         return 0;
224 }
225
226 struct ctdb_dbid_map_wire {
227         uint32_t num;
228         struct ctdb_dbid dbs[1];
229 };
230
231 size_t ctdb_dbid_map_len(struct ctdb_dbid_map *dbmap)
232 {
233         return sizeof(uint32_t) + dbmap->num * sizeof(struct ctdb_dbid);
234 }
235
236 void ctdb_dbid_map_push(struct ctdb_dbid_map *dbmap, uint8_t *buf)
237 {
238         struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
239
240         wire->num = dbmap->num;
241         memcpy(wire->dbs, dbmap->dbs, dbmap->num * sizeof(struct ctdb_dbid));
242 }
243
244 int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
245                        struct ctdb_dbid_map **out)
246 {
247         struct ctdb_dbid_map *dbmap;
248         struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
249
250         if (buflen < sizeof(uint32_t)) {
251                 return EMSGSIZE;
252         }
253         if (wire->num > buflen / sizeof(struct ctdb_dbid)) {
254                 return EMSGSIZE;
255         }
256         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_dbid) <
257             sizeof(uint32_t)) {
258                 return EMSGSIZE;
259         }
260         if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_dbid)) {
261                 return EMSGSIZE;
262         }
263
264         dbmap = talloc(mem_ctx, struct ctdb_dbid_map);
265         if (dbmap == NULL) {
266                 return ENOMEM;
267         }
268
269         dbmap->num = wire->num;
270
271         dbmap->dbs = talloc_memdup(dbmap, wire->dbs,
272                                    wire->num * sizeof(struct ctdb_dbid));
273         if (dbmap->dbs == NULL) {
274                 talloc_free(dbmap);
275                 return ENOMEM;
276         }
277
278         *out = dbmap;
279         return 0;
280 }
281
282 size_t ctdb_pulldb_len(struct ctdb_pulldb *pulldb)
283 {
284         return sizeof(struct ctdb_pulldb);
285 }
286
287 void ctdb_pulldb_push(struct ctdb_pulldb *pulldb, uint8_t *buf)
288 {
289         memcpy(buf, pulldb, sizeof(struct ctdb_pulldb));
290 }
291
292 int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
293                      struct ctdb_pulldb **out)
294 {
295         struct ctdb_pulldb *pulldb;
296
297         if (buflen < sizeof(struct ctdb_pulldb)) {
298                 return EMSGSIZE;
299         }
300
301         pulldb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_pulldb));
302         if (pulldb == NULL) {
303                 return ENOMEM;
304         }
305
306         *out = pulldb;
307         return 0;
308 }
309
310 size_t ctdb_pulldb_ext_len(struct ctdb_pulldb_ext *pulldb)
311 {
312         return sizeof(struct ctdb_pulldb_ext);
313 }
314
315 void ctdb_pulldb_ext_push(struct ctdb_pulldb_ext *pulldb, uint8_t *buf)
316 {
317         memcpy(buf, pulldb, sizeof(struct ctdb_pulldb_ext));
318 }
319
320 int ctdb_pulldb_ext_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
321                          struct ctdb_pulldb_ext **out)
322 {
323         struct ctdb_pulldb_ext *pulldb;
324
325         if (buflen < sizeof(struct ctdb_pulldb_ext)) {
326                 return EMSGSIZE;
327         }
328
329         pulldb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_pulldb_ext));
330         if (pulldb == NULL) {
331                 return ENOMEM;
332         }
333
334         *out = pulldb;
335         return 0;
336 }
337
338 size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *header)
339 {
340         return sizeof(struct ctdb_ltdb_header);
341 }
342
343 void ctdb_ltdb_header_push(struct ctdb_ltdb_header *header, uint8_t *buf)
344 {
345         memcpy(buf, header, sizeof(struct ctdb_ltdb_header));
346 }
347
348 int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen,
349                           struct ctdb_ltdb_header *header)
350 {
351         if (buflen < sizeof(struct ctdb_ltdb_header)) {
352                 return EMSGSIZE;
353         }
354
355         memcpy(header, buf, sizeof(struct ctdb_ltdb_header));
356         return 0;
357 }
358
359 int ctdb_ltdb_header_extract(TDB_DATA *data, struct ctdb_ltdb_header *header)
360 {
361         int ret;
362
363         ret = ctdb_ltdb_header_pull(data->dptr, data->dsize, header);
364         if (ret != 0) {
365                 return ret;
366         }
367
368         data->dptr += sizeof(struct ctdb_ltdb_header);
369         data->dsize -= sizeof(struct ctdb_ltdb_header);
370
371         return 0;
372 }
373
374 struct ctdb_rec_data_wire {
375         uint32_t length;
376         uint32_t reqid;
377         uint32_t keylen;
378         uint32_t datalen;
379         uint8_t data[1];
380 };
381
382 size_t ctdb_rec_data_len(struct ctdb_rec_data *rec)
383 {
384         return offsetof(struct ctdb_rec_data_wire, data) +
385                rec->key.dsize + rec->data.dsize +
386                (rec->header == NULL ? 0 : sizeof(struct ctdb_ltdb_header));
387 }
388
389 void ctdb_rec_data_push(struct ctdb_rec_data *rec, uint8_t *buf)
390 {
391         struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
392         size_t offset;
393
394         wire->length = ctdb_rec_data_len(rec);
395         wire->reqid = rec->reqid;
396         wire->keylen = rec->key.dsize;
397         wire->datalen = rec->data.dsize;
398         if (rec->header != NULL) {
399                 wire->datalen += sizeof(struct ctdb_ltdb_header);
400         }
401
402         memcpy(wire->data, rec->key.dptr, rec->key.dsize);
403         offset = rec->key.dsize;
404         if (rec->header != NULL) {
405                 memcpy(&wire->data[offset], rec->header,
406                        sizeof(struct ctdb_ltdb_header));
407                 offset += sizeof(struct ctdb_ltdb_header);
408         }
409         if (rec->data.dsize > 0) {
410                 memcpy(&wire->data[offset], rec->data.dptr, rec->data.dsize);
411         }
412 }
413
414 static int ctdb_rec_data_pull_data(uint8_t *buf, size_t buflen,
415                                    uint32_t *reqid,
416                                    struct ctdb_ltdb_header **header,
417                                    TDB_DATA *key, TDB_DATA *data,
418                                    size_t *reclen)
419 {
420         struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
421         size_t offset;
422
423         if (buflen < offsetof(struct ctdb_rec_data_wire, data)) {
424                 return EMSGSIZE;
425         }
426         if (wire->keylen > buflen || wire->datalen > buflen) {
427                 return EMSGSIZE;
428         }
429         if (offsetof(struct ctdb_rec_data_wire, data) + wire->keylen <
430             offsetof(struct ctdb_rec_data_wire, data)) {
431                 return EMSGSIZE;
432         }
433         if (offsetof(struct ctdb_rec_data_wire, data) +
434                 wire->keylen + wire->datalen <
435             offsetof(struct ctdb_rec_data_wire, data)) {
436                 return EMSGSIZE;
437         }
438         if (buflen < offsetof(struct ctdb_rec_data_wire, data) +
439                         wire->keylen + wire->datalen) {
440                 return EMSGSIZE;
441         }
442
443         *reqid = wire->reqid;
444
445         key->dsize = wire->keylen;
446         key->dptr = wire->data;
447         offset = wire->keylen;
448
449         /* Always set header to NULL.  If it is required, exact it using
450          * ctdb_rec_data_extract_header()
451          */
452         *header = NULL;
453
454         data->dsize = wire->datalen;
455         data->dptr = &wire->data[offset];
456
457         *reclen = offsetof(struct ctdb_rec_data_wire, data) +
458                         wire->keylen + wire->datalen;
459
460         return 0;
461 }
462
463 static int ctdb_rec_data_pull_elems(uint8_t *buf, size_t buflen,
464                                     TALLOC_CTX *mem_ctx,
465                                     struct ctdb_rec_data *out)
466 {
467         uint32_t reqid;
468         struct ctdb_ltdb_header *header;
469         TDB_DATA key, data;
470         size_t reclen;
471         int ret;
472
473         ret = ctdb_rec_data_pull_data(buf, buflen, &reqid, &header,
474                                       &key, &data, &reclen);
475         if (ret != 0) {
476                 return ret;
477         }
478
479         out->reqid = reqid;
480         out->header = NULL;
481
482         out->key.dsize = key.dsize;
483         if (key.dsize > 0) {
484                 out->key.dptr = talloc_memdup(mem_ctx, key.dptr, key.dsize);
485                 if (out->key.dptr == NULL) {
486                         return ENOMEM;
487                 }
488         }
489
490         out->data.dsize = data.dsize;
491         if (data.dsize > 0) {
492                 out->data.dptr = talloc_memdup(mem_ctx, data.dptr, data.dsize);
493                 if (out->data.dptr == NULL) {
494                         return ENOMEM;
495                 }
496         }
497
498         return 0;
499 }
500
501 int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
502                        struct ctdb_rec_data **out)
503 {
504         struct ctdb_rec_data *rec;
505         int ret;
506
507         rec = talloc(mem_ctx, struct ctdb_rec_data);
508         if (rec == NULL) {
509                 return ENOMEM;
510         }
511
512         ret = ctdb_rec_data_pull_elems(buf, buflen, rec, rec);
513         if (ret != 0) {
514                 TALLOC_FREE(rec);
515         }
516
517         *out = rec;
518         return ret;
519 }
520
521 struct ctdb_rec_buffer_wire {
522         uint32_t db_id;
523         uint32_t count;
524         uint8_t data[1];
525 };
526
527 size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *recbuf)
528 {
529         return offsetof(struct ctdb_rec_buffer_wire, data) + recbuf->buflen;
530 }
531
532 void ctdb_rec_buffer_push(struct ctdb_rec_buffer *recbuf, uint8_t *buf)
533 {
534         struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
535
536         wire->db_id = recbuf->db_id;
537         wire->count = recbuf->count;
538         if (recbuf->buflen > 0) {
539                 memcpy(wire->data, recbuf->buf, recbuf->buflen);
540         }
541 }
542
543 int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
544                          struct ctdb_rec_buffer **out)
545 {
546         struct ctdb_rec_buffer *recbuf;
547         struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
548         size_t offset;
549
550         if (buflen < offsetof(struct ctdb_rec_buffer_wire, data)) {
551                 return EMSGSIZE;
552         }
553
554         recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
555         if (recbuf == NULL) {
556                 return ENOMEM;
557         }
558
559         recbuf->db_id = wire->db_id;
560         recbuf->count = wire->count;
561
562         offset = offsetof(struct ctdb_rec_buffer_wire, data);
563         recbuf->buflen = buflen - offset;
564         recbuf->buf = talloc_memdup(recbuf, wire->data, recbuf->buflen);
565         if (recbuf->buf == NULL) {
566                 talloc_free(recbuf);
567                 return ENOMEM;
568         }
569
570         *out = recbuf;
571         return 0;
572 }
573
574 struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx,
575                                              uint32_t db_id)
576 {
577         struct ctdb_rec_buffer *recbuf;
578
579         recbuf = talloc_zero(mem_ctx, struct ctdb_rec_buffer);
580         if (recbuf == NULL) {
581                 return recbuf;
582         }
583
584         recbuf->db_id = db_id;
585
586         return recbuf;
587 }
588
589 int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf,
590                         uint32_t reqid, struct ctdb_ltdb_header *header,
591                         TDB_DATA key, TDB_DATA data)
592 {
593         struct ctdb_rec_data recdata;
594         size_t len;
595         uint8_t *ptr;
596
597         recdata.reqid = reqid;
598         recdata.header = header;
599         recdata.key = key;
600         recdata.data = data;
601
602         len = ctdb_rec_data_len(&recdata);
603
604         ptr = talloc_realloc(mem_ctx, recbuf->buf, uint8_t,
605                              recbuf->buflen + len);
606         if (ptr == NULL) {
607                 return ENOMEM;
608         }
609
610         ctdb_rec_data_push(&recdata, &ptr[recbuf->buflen]);
611
612         recbuf->count++;
613         recbuf->buf = ptr;
614         recbuf->buflen += len;
615         return 0;
616 }
617
618 int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf,
619                              ctdb_rec_parser_func_t func,
620                              void *private_data)
621 {
622         struct ctdb_ltdb_header *header;
623         TDB_DATA key, data;
624         uint32_t reqid;
625         size_t offset, reclen;
626         int ret = 0, i;
627
628         offset = 0;
629         for (i=0; i<recbuf->count; i++) {
630                 ret = ctdb_rec_data_pull_data(&recbuf->buf[offset],
631                                               recbuf->buflen - offset,
632                                               &reqid, &header,
633                                               &key, &data, &reclen);
634                 if (ret != 0) {
635                         return ret;
636                 }
637
638                 ret = func(reqid, header, key, data, private_data);
639                 if (ret != 0) {
640                         break;
641                 }
642
643                 offset += reclen;
644         }
645
646         return ret;
647 }
648
649 int ctdb_rec_buffer_write(struct ctdb_rec_buffer *recbuf, int fd)
650 {
651         ssize_t n;
652
653         n = write(fd, &recbuf->db_id, sizeof(uint32_t));
654         if (n == -1 || n != sizeof(uint32_t)) {
655                 return (errno != 0 ? errno : EIO);
656         }
657         n = write(fd, &recbuf->count, sizeof(uint32_t));
658         if (n == -1 || n != sizeof(uint32_t)) {
659                 return (errno != 0 ? errno : EIO);
660         }
661         n = write(fd, &recbuf->buflen, sizeof(size_t));
662         if (n == -1 || n != sizeof(size_t)) {
663                 return (errno != 0 ? errno : EIO);
664         }
665         n = write(fd, recbuf->buf, recbuf->buflen);
666         if (n == -1 || n != recbuf->buflen) {
667                 return (errno != 0 ? errno : EIO);
668         }
669
670         return 0;
671 }
672
673 int ctdb_rec_buffer_read(int fd, TALLOC_CTX *mem_ctx,
674                          struct ctdb_rec_buffer **out)
675 {
676         struct ctdb_rec_buffer *recbuf;
677         ssize_t n;
678
679         recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
680         if (recbuf == NULL) {
681                 return ENOMEM;
682         }
683
684         n = read(fd, &recbuf->db_id, sizeof(uint32_t));
685         if (n == -1 || n != sizeof(uint32_t)) {
686                 return (errno != 0 ? errno : EIO);
687         }
688         n = read(fd, &recbuf->count, sizeof(uint32_t));
689         if (n == -1 || n != sizeof(uint32_t)) {
690                 return (errno != 0 ? errno : EIO);
691         }
692         n = read(fd, &recbuf->buflen, sizeof(size_t));
693         if (n == -1 || n != sizeof(size_t)) {
694                 return (errno != 0 ? errno : EIO);
695         }
696
697         recbuf->buf = talloc_size(recbuf, recbuf->buflen);
698         if (recbuf->buf == NULL) {
699                 return ENOMEM;
700         }
701
702         n = read(fd, recbuf->buf, recbuf->buflen);
703         if (n == -1 || n != recbuf->buflen) {
704                 return (errno != 0 ? errno : EIO);
705         }
706
707         *out = recbuf;
708         return 0;
709 }
710
711 size_t ctdb_traverse_start_len(struct ctdb_traverse_start *traverse)
712 {
713         return sizeof(struct ctdb_traverse_start);
714 }
715
716 void ctdb_traverse_start_push(struct ctdb_traverse_start *traverse,
717                               uint8_t *buf)
718 {
719         memcpy(buf, traverse, sizeof(struct ctdb_traverse_start));
720 }
721
722 int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
723                              struct ctdb_traverse_start **out)
724 {
725         struct ctdb_traverse_start *traverse;
726
727         if (buflen < sizeof(struct ctdb_traverse_start)) {
728                 return EMSGSIZE;
729         }
730
731         traverse = talloc_memdup(mem_ctx, buf,
732                                  sizeof(struct ctdb_traverse_start));
733         if (traverse == NULL) {
734                 return ENOMEM;
735         }
736
737         *out = traverse;
738         return 0;
739 }
740
741 size_t ctdb_traverse_all_len(struct ctdb_traverse_all *traverse)
742 {
743         return sizeof(struct ctdb_traverse_all);
744 }
745
746 void ctdb_traverse_all_push(struct ctdb_traverse_all *traverse, uint8_t *buf)
747 {
748         memcpy(buf, traverse, sizeof(struct ctdb_traverse_all));
749 }
750
751 int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
752                            struct ctdb_traverse_all **out)
753 {
754         struct ctdb_traverse_all *traverse;
755
756         if (buflen < sizeof(struct ctdb_traverse_all)) {
757                 return EMSGSIZE;
758         }
759
760         traverse = talloc_memdup(mem_ctx, buf,
761                                  sizeof(struct ctdb_traverse_all));
762         if (traverse == NULL) {
763                 return ENOMEM;
764         }
765
766         *out = traverse;
767         return 0;
768 }
769
770 size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *traverse)
771 {
772         return sizeof(struct ctdb_traverse_start_ext);
773 }
774
775 void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *traverse,
776                                   uint8_t *buf)
777 {
778         memcpy(buf, traverse, sizeof(struct ctdb_traverse_start_ext));
779 }
780
781 int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen,
782                                  TALLOC_CTX *mem_ctx,
783                                  struct ctdb_traverse_start_ext **out)
784 {
785         struct ctdb_traverse_start_ext *traverse;
786
787         if (buflen < sizeof(struct ctdb_traverse_start_ext)) {
788                 return EMSGSIZE;
789         }
790
791         traverse = talloc_memdup(mem_ctx, buf,
792                                  sizeof(struct ctdb_traverse_start_ext));
793         if (traverse == NULL) {
794                 return ENOMEM;
795         }
796
797         *out = traverse;
798         return 0;
799 }
800
801 size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *traverse)
802 {
803         return sizeof(struct ctdb_traverse_all_ext);
804 }
805
806 void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *traverse,
807                                 uint8_t *buf)
808 {
809         memcpy(buf, traverse, sizeof(struct ctdb_traverse_all_ext));
810 }
811
812 int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen,
813                                TALLOC_CTX *mem_ctx,
814                                struct ctdb_traverse_all_ext **out)
815 {
816         struct ctdb_traverse_all_ext *traverse;
817
818         if (buflen < sizeof(struct ctdb_traverse_all_ext)) {
819                 return EMSGSIZE;
820         }
821
822         traverse = talloc_memdup(mem_ctx, buf,
823                                  sizeof(struct ctdb_traverse_all_ext));
824         if (traverse == NULL) {
825                 return ENOMEM;
826         }
827
828         *out = traverse;
829         return 0;
830 }
831
832 size_t ctdb_sock_addr_len(ctdb_sock_addr *addr)
833 {
834         return sizeof(ctdb_sock_addr);
835 }
836
837 void ctdb_sock_addr_push(ctdb_sock_addr *addr, uint8_t *buf)
838 {
839         memcpy(buf, addr, sizeof(ctdb_sock_addr));
840 }
841
842 static int ctdb_sock_addr_pull_elems(uint8_t *buf, size_t buflen,
843                                      TALLOC_CTX *mem_ctx, ctdb_sock_addr *out)
844 {
845         if (buflen < sizeof(ctdb_sock_addr)) {
846                 return EMSGSIZE;
847         }
848
849         memcpy(out, buf, sizeof(ctdb_sock_addr));
850
851         return 0;
852 }
853
854 int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
855                         ctdb_sock_addr **out)
856 {
857         ctdb_sock_addr *addr;
858         int ret;
859
860         addr = talloc(mem_ctx, ctdb_sock_addr);
861         if (addr == NULL) {
862                 return false;
863         }
864
865         ret = ctdb_sock_addr_pull_elems(buf, buflen, addr, addr);
866         if (ret != 0) {
867                 TALLOC_FREE(addr);
868         }
869
870         *out = addr;
871         return ret;
872 }
873
874 size_t ctdb_connection_len(struct ctdb_connection *conn)
875 {
876         return sizeof(struct ctdb_connection);
877 }
878
879 void ctdb_connection_push(struct ctdb_connection *conn, uint8_t *buf)
880 {
881         memcpy(buf, conn, sizeof(struct ctdb_connection));
882 }
883
884 static int ctdb_connection_pull_elems(uint8_t *buf, size_t buflen,
885                                       TALLOC_CTX *mem_ctx,
886                                       struct ctdb_connection *out)
887 {
888         if (buflen < sizeof(struct ctdb_connection)) {
889                 return EMSGSIZE;
890         }
891
892         memcpy(out, buf, sizeof(struct ctdb_connection));
893
894         return 0;
895 }
896
897 int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
898                          struct ctdb_connection **out)
899 {
900         struct ctdb_connection *conn;
901         int ret;
902
903         conn = talloc(mem_ctx, struct ctdb_connection);
904         if (conn == NULL) {
905                 return ENOMEM;
906         }
907
908         ret = ctdb_connection_pull_elems(buf, buflen, conn, conn);
909         if (ret != 0) {
910                 TALLOC_FREE(conn);
911         }
912
913         *out = conn;
914         return ret;
915 }
916
917 struct ctdb_tunable_wire {
918         uint32_t value;
919         uint32_t length;
920         uint8_t name[1];
921 };
922
923 size_t ctdb_tunable_len(struct ctdb_tunable *tunable)
924 {
925         return offsetof(struct ctdb_tunable_wire, name) +
926                strlen(tunable->name) + 1;
927 }
928
929 void ctdb_tunable_push(struct ctdb_tunable *tunable, uint8_t *buf)
930 {
931         struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
932
933         wire->value = tunable->value;
934         wire->length = strlen(tunable->name) + 1;
935         memcpy(wire->name, tunable->name, wire->length);
936 }
937
938 int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
939                       struct ctdb_tunable **out)
940 {
941         struct ctdb_tunable *tunable;
942         struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
943
944         if (buflen < offsetof(struct ctdb_tunable_wire, name)) {
945                 return EMSGSIZE;
946         }
947         if (wire->length > buflen) {
948                 return EMSGSIZE;
949         }
950         if (offsetof(struct ctdb_tunable_wire, name) + wire->length <
951             offsetof(struct ctdb_tunable_wire, name)) {
952                 return EMSGSIZE;
953         }
954         if (buflen < offsetof(struct ctdb_tunable_wire, name) + wire->length) {
955                 return EMSGSIZE;
956         }
957
958         tunable = talloc(mem_ctx, struct ctdb_tunable);
959         if (tunable == NULL) {
960                 return ENOMEM;
961         }
962
963         tunable->value = wire->value;
964         tunable->name = talloc_memdup(tunable, wire->name, wire->length);
965         if (tunable->name == NULL) {
966                 talloc_free(tunable);
967                 return ENOMEM;
968         }
969
970         *out = tunable;
971         return 0;
972 }
973
974 size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *flag_change)
975 {
976         return sizeof(struct ctdb_node_flag_change);
977 }
978
979 void ctdb_node_flag_change_push(struct ctdb_node_flag_change *flag_change,
980                                 uint8_t *buf)
981 {
982         memcpy(buf, flag_change, sizeof(struct ctdb_node_flag_change));
983 }
984
985 int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
986                                struct ctdb_node_flag_change **out)
987 {
988         struct ctdb_node_flag_change *flag_change;
989
990         if (buflen < sizeof(struct ctdb_node_flag_change)) {
991                 return EMSGSIZE;
992         }
993
994         flag_change = talloc_memdup(mem_ctx, buf,
995                                     sizeof(struct ctdb_node_flag_change));
996         if (flag_change == NULL) {
997                 return ENOMEM;
998         }
999
1000         *out = flag_change;
1001         return 0;
1002 }
1003
1004 struct ctdb_var_list_wire {
1005         uint32_t length;
1006         char list_str[1];
1007 };
1008
1009 size_t ctdb_var_list_len(struct ctdb_var_list *var_list)
1010 {
1011         int i;
1012         size_t len = sizeof(uint32_t);
1013
1014         for (i=0; i<var_list->count; i++) {
1015                 len += strlen(var_list->var[i]) + 1;
1016         }
1017         return len;
1018 }
1019
1020 void ctdb_var_list_push(struct ctdb_var_list *var_list, uint8_t *buf)
1021 {
1022         struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
1023         int i, n;
1024         size_t offset = 0;
1025
1026         if (var_list->count > 0) {
1027                 n = sprintf(wire->list_str, "%s", var_list->var[0]);
1028                 offset += n;
1029         }
1030         for (i=1; i<var_list->count; i++) {
1031                 n = sprintf(&wire->list_str[offset], ":%s", var_list->var[i]);
1032                 offset += n;
1033         }
1034         wire->length = offset + 1;
1035 }
1036
1037 int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1038                        struct ctdb_var_list **out)
1039 {
1040         struct ctdb_var_list *var_list = NULL;
1041         struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
1042         char *str, *s, *tok, *ptr;
1043         const char **list;
1044
1045         if (buflen < sizeof(uint32_t)) {
1046                 return EMSGSIZE;
1047         }
1048         if (wire->length > buflen) {
1049                 return EMSGSIZE;
1050         }
1051         if (sizeof(uint32_t) + wire->length < sizeof(uint32_t)) {
1052                 return EMSGSIZE;
1053         }
1054         if (buflen < sizeof(uint32_t) + wire->length) {
1055                 return EMSGSIZE;
1056         }
1057
1058         str = talloc_strndup(mem_ctx, (char *)wire->list_str, wire->length);
1059         if (str == NULL) {
1060                 return ENOMEM;
1061         }
1062
1063         var_list = talloc_zero(mem_ctx, struct ctdb_var_list);
1064         if (var_list == NULL) {
1065                 goto fail;
1066         }
1067
1068         s = str;
1069         while ((tok = strtok_r(s, ":", &ptr)) != NULL) {
1070                 s = NULL;
1071                 list = talloc_realloc(var_list, var_list->var, const char *,
1072                                       var_list->count+1);
1073                 if (list == NULL) {
1074                         goto fail;
1075                 }
1076
1077                 var_list->var = list;
1078                 var_list->var[var_list->count] = talloc_strdup(var_list, tok);
1079                 if (var_list->var[var_list->count] == NULL) {
1080                         goto fail;
1081                 }
1082                 var_list->count++;
1083         }
1084
1085         talloc_free(str);
1086         *out = var_list;
1087         return 0;
1088
1089 fail:
1090         talloc_free(str);
1091         talloc_free(var_list);
1092         return ENOMEM;
1093 }
1094
1095 size_t ctdb_tunable_list_len(struct ctdb_tunable_list *tun_list)
1096 {
1097         return sizeof(struct ctdb_tunable_list);
1098 }
1099
1100 void ctdb_tunable_list_push(struct ctdb_tunable_list *tun_list, uint8_t *buf)
1101 {
1102         memcpy(buf, tun_list, sizeof(struct ctdb_tunable_list));
1103 }
1104
1105 int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1106                            struct ctdb_tunable_list **out)
1107 {
1108         struct ctdb_tunable_list *tun_list;
1109
1110         if (buflen < sizeof(struct ctdb_tunable_list)) {
1111                 return EMSGSIZE;
1112         }
1113
1114         tun_list = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_tunable_list));
1115         if (tun_list == NULL) {
1116                 return ENOMEM;
1117         }
1118
1119         *out = tun_list;
1120         return 0;
1121 }
1122
1123 struct ctdb_tickle_list_wire {
1124         ctdb_sock_addr addr;
1125         uint32_t num;
1126         struct ctdb_connection conn[1];
1127 };
1128
1129 size_t ctdb_tickle_list_len(struct ctdb_tickle_list *tickles)
1130 {
1131         return offsetof(struct ctdb_tickle_list, conn) +
1132                tickles->num * sizeof(struct ctdb_connection);
1133 }
1134
1135 void ctdb_tickle_list_push(struct ctdb_tickle_list *tickles, uint8_t *buf)
1136 {
1137         struct ctdb_tickle_list_wire *wire =
1138                 (struct ctdb_tickle_list_wire *)buf;
1139         size_t offset;
1140         int i;
1141
1142         memcpy(&wire->addr, &tickles->addr, sizeof(ctdb_sock_addr));
1143         wire->num = tickles->num;
1144
1145         offset = offsetof(struct ctdb_tickle_list_wire, conn);
1146         for (i=0; i<tickles->num; i++) {
1147                 ctdb_connection_push(&tickles->conn[i], &buf[offset]);
1148                 offset += ctdb_connection_len(&tickles->conn[i]);
1149         }
1150 }
1151
1152 int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1153                            struct ctdb_tickle_list **out)
1154 {
1155         struct ctdb_tickle_list *tickles;
1156         struct ctdb_tickle_list_wire *wire =
1157                 (struct ctdb_tickle_list_wire *)buf;
1158         size_t offset;
1159         int i, ret;
1160
1161         if (buflen < offsetof(struct ctdb_tickle_list_wire, conn)) {
1162                 return EMSGSIZE;
1163         }
1164         if (wire->num > buflen / sizeof(struct ctdb_connection)) {
1165                 return EMSGSIZE;
1166         }
1167         if (offsetof(struct ctdb_tickle_list_wire, conn) +
1168             wire->num * sizeof(struct ctdb_connection) <
1169             offsetof(struct ctdb_tickle_list_wire, conn)) {
1170                 return EMSGSIZE;
1171         }
1172         if (buflen < offsetof(struct ctdb_tickle_list_wire, conn) +
1173                      wire->num * sizeof(struct ctdb_connection)) {
1174                 return EMSGSIZE;
1175         }
1176
1177         tickles = talloc(mem_ctx, struct ctdb_tickle_list);
1178         if (tickles == NULL) {
1179                 return ENOMEM;
1180         }
1181
1182         offset = offsetof(struct ctdb_tickle_list, conn);
1183         memcpy(tickles, wire, offset);
1184
1185         tickles->conn = talloc_array(tickles, struct ctdb_connection,
1186                                      wire->num);
1187         if (tickles->conn == NULL) {
1188                 talloc_free(tickles);
1189                 return ENOMEM;
1190         }
1191
1192         for (i=0; i<wire->num; i++) {
1193                 ret = ctdb_connection_pull_elems(&buf[offset], buflen-offset,
1194                                                  tickles->conn,
1195                                                  &tickles->conn[i]);
1196                 if (ret != 0) {
1197                         talloc_free(tickles);
1198                         return ret;
1199                 }
1200                 offset += ctdb_connection_len(&tickles->conn[i]);
1201         }
1202
1203         *out = tickles;
1204         return 0;
1205 }
1206
1207 struct ctdb_addr_info_wire {
1208         ctdb_sock_addr addr;
1209         uint32_t mask;
1210         uint32_t len;
1211         char iface[1];
1212 };
1213
1214 size_t ctdb_addr_info_len(struct ctdb_addr_info *arp)
1215 {
1216         uint32_t len;
1217
1218         len = offsetof(struct ctdb_addr_info_wire, iface);
1219         if (arp->iface != NULL) {
1220                len += strlen(arp->iface)+1;
1221         }
1222
1223         return len;
1224 }
1225
1226 void ctdb_addr_info_push(struct ctdb_addr_info *addr_info, uint8_t *buf)
1227 {
1228         struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
1229
1230         wire->addr = addr_info->addr;
1231         wire->mask = addr_info->mask;
1232         if (addr_info->iface == NULL) {
1233                 wire->len = 0;
1234         } else {
1235                 wire->len = strlen(addr_info->iface)+1;
1236                 memcpy(wire->iface, addr_info->iface, wire->len);
1237         }
1238 }
1239
1240 int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1241                         struct ctdb_addr_info **out)
1242 {
1243         struct ctdb_addr_info *addr_info;
1244         struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
1245
1246         if (buflen < offsetof(struct ctdb_addr_info_wire, iface)) {
1247                 return EMSGSIZE;
1248         }
1249         if (wire->len > buflen) {
1250                 return EMSGSIZE;
1251         }
1252         if (offsetof(struct ctdb_addr_info_wire, iface) + wire->len <
1253             offsetof(struct ctdb_addr_info_wire, iface)) {
1254                 return EMSGSIZE;
1255         }
1256         if (buflen < offsetof(struct ctdb_addr_info_wire, iface) + wire->len) {
1257                 return EMSGSIZE;
1258         }
1259
1260         addr_info = talloc(mem_ctx, struct ctdb_addr_info);
1261         if (addr_info == NULL) {
1262                 return ENOMEM;
1263         }
1264
1265         addr_info->addr = wire->addr;
1266         addr_info->mask = wire->mask;
1267
1268         if (wire->len == 0) {
1269                 addr_info->iface = NULL;
1270         } else {
1271                 addr_info->iface = talloc_strndup(addr_info, wire->iface,
1272                                                   wire->len);
1273                 if (addr_info->iface == NULL) {
1274                         talloc_free(addr_info);
1275                         return ENOMEM;
1276                 }
1277         }
1278
1279         *out = addr_info;
1280         return 0;
1281 }
1282
1283 size_t ctdb_transdb_len(struct ctdb_transdb *transdb)
1284 {
1285         return sizeof(struct ctdb_transdb);
1286 }
1287
1288 void ctdb_transdb_push(struct ctdb_transdb *transdb, uint8_t *buf)
1289 {
1290         memcpy(buf, transdb, sizeof(struct ctdb_transdb));
1291 }
1292
1293 int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1294                      struct ctdb_transdb **out)
1295 {
1296         struct ctdb_transdb *transdb;
1297
1298         if (buflen < sizeof(struct ctdb_transdb)) {
1299                 return EMSGSIZE;
1300         }
1301
1302         transdb = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_transdb));
1303         if (transdb == NULL) {
1304                 return ENOMEM;
1305         }
1306
1307         *out = transdb;
1308         return 0;
1309 }
1310
1311 size_t ctdb_uptime_len(struct ctdb_uptime *uptime)
1312 {
1313         return sizeof(struct ctdb_uptime);
1314 }
1315
1316 void ctdb_uptime_push(struct ctdb_uptime *uptime, uint8_t *buf)
1317 {
1318         memcpy(buf, uptime, sizeof(struct ctdb_uptime));
1319 }
1320
1321 int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1322                      struct ctdb_uptime **out)
1323 {
1324         struct ctdb_uptime *uptime;
1325
1326         if (buflen < sizeof(struct ctdb_uptime)) {
1327                 return EMSGSIZE;
1328         }
1329
1330         uptime = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_uptime));
1331         if (uptime == NULL) {
1332                 return ENOMEM;
1333         }
1334
1335         *out = uptime;
1336         return 0;
1337 }
1338
1339 size_t ctdb_public_ip_len(struct ctdb_public_ip *pubip)
1340 {
1341         return sizeof(struct ctdb_public_ip);
1342 }
1343
1344 void ctdb_public_ip_push(struct ctdb_public_ip *pubip, uint8_t *buf)
1345 {
1346         memcpy(buf, pubip, sizeof(struct ctdb_public_ip));
1347 }
1348
1349 static int ctdb_public_ip_pull_elems(uint8_t *buf, size_t buflen,
1350                                      TALLOC_CTX *mem_ctx,
1351                                      struct ctdb_public_ip *out)
1352 {
1353         if (buflen < sizeof(struct ctdb_public_ip)) {
1354                 return EMSGSIZE;
1355         }
1356
1357         memcpy(out, buf, sizeof(struct ctdb_public_ip));
1358
1359         return 0;
1360 }
1361
1362 int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1363                         struct ctdb_public_ip **out)
1364 {
1365         struct ctdb_public_ip *pubip;
1366         int ret;
1367
1368         pubip = talloc(mem_ctx, struct ctdb_public_ip);
1369         if (pubip == NULL) {
1370                 return ENOMEM;
1371         }
1372
1373         ret = ctdb_public_ip_pull_elems(buf, buflen, pubip, pubip);
1374         if (ret != 0) {
1375                 TALLOC_FREE(pubip);
1376         }
1377
1378         *out = pubip;
1379         return ret;
1380 }
1381
1382 struct ctdb_public_ip_list_wire {
1383         uint32_t num;
1384         struct ctdb_public_ip ip[1];
1385 };
1386
1387 size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list)
1388 {
1389         int i;
1390         size_t len;
1391
1392         len = sizeof(uint32_t);
1393         for (i=0; i<pubip_list->num; i++) {
1394                 len += ctdb_public_ip_len(&pubip_list->ip[i]);
1395         }
1396         return len;
1397 }
1398
1399 void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list,
1400                               uint8_t *buf)
1401 {
1402         struct ctdb_public_ip_list_wire *wire =
1403                 (struct ctdb_public_ip_list_wire *)buf;
1404         size_t offset;
1405         int i;
1406
1407         wire->num = pubip_list->num;
1408
1409         offset = offsetof(struct ctdb_public_ip_list_wire, ip);
1410         for (i=0; i<pubip_list->num; i++) {
1411                 ctdb_public_ip_push(&pubip_list->ip[i], &buf[offset]);
1412                 offset += ctdb_public_ip_len(&pubip_list->ip[i]);
1413         }
1414 }
1415
1416 int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1417                              struct ctdb_public_ip_list **out)
1418 {
1419         struct ctdb_public_ip_list *pubip_list;
1420         struct ctdb_public_ip_list_wire *wire =
1421                 (struct ctdb_public_ip_list_wire *)buf;
1422         size_t offset;
1423         int i;
1424         bool ret;
1425
1426         if (buflen < sizeof(uint32_t)) {
1427                 return EMSGSIZE;
1428         }
1429         if (wire->num > buflen / sizeof(struct ctdb_public_ip)) {
1430                 return EMSGSIZE;
1431         }
1432         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_public_ip) <
1433             sizeof(uint32_t)) {
1434                 return EMSGSIZE;
1435         }
1436         if (buflen < sizeof(uint32_t) +
1437                      wire->num * sizeof(struct ctdb_public_ip)) {
1438                 return EMSGSIZE;
1439         }
1440
1441         pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list);
1442         if (pubip_list == NULL) {
1443                 return ENOMEM;
1444         }
1445
1446         pubip_list->num = wire->num;
1447         if (wire->num == 0) {
1448                 pubip_list->ip = NULL;
1449                 *out = pubip_list;
1450                 return 0;
1451         }
1452         pubip_list->ip = talloc_array(pubip_list, struct ctdb_public_ip,
1453                                       wire->num);
1454         if (pubip_list->ip == NULL) {
1455                 talloc_free(pubip_list);
1456                 return ENOMEM;
1457         }
1458
1459         offset = offsetof(struct ctdb_public_ip_list_wire, ip);
1460         for (i=0; i<wire->num; i++) {
1461                 ret = ctdb_public_ip_pull_elems(&buf[offset], buflen-offset,
1462                                                 pubip_list->ip,
1463                                                 &pubip_list->ip[i]);
1464                 if (ret != 0) {
1465                         talloc_free(pubip_list);
1466                         return ret;
1467                 }
1468                 offset += ctdb_public_ip_len(&pubip_list->ip[i]);
1469         }
1470
1471         *out = pubip_list;
1472         return 0;
1473 }
1474
1475 size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node)
1476 {
1477         return sizeof(struct ctdb_node_and_flags);
1478 }
1479
1480 void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf)
1481 {
1482         memcpy(buf, node, sizeof(struct ctdb_node_and_flags));
1483 }
1484
1485 static int ctdb_node_and_flags_pull_elems(TALLOC_CTX *mem_ctx,
1486                                           uint8_t *buf, size_t buflen,
1487                                           struct ctdb_node_and_flags *out)
1488 {
1489         if (buflen < sizeof(struct ctdb_node_and_flags)) {
1490                 return EMSGSIZE;
1491         }
1492
1493         memcpy(out, buf, sizeof(struct ctdb_node_and_flags));
1494
1495         return 0;
1496 }
1497
1498 int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1499                               struct ctdb_node_and_flags **out)
1500 {
1501         struct ctdb_node_and_flags *node;
1502         int ret;
1503
1504         node = talloc(mem_ctx, struct ctdb_node_and_flags);
1505         if (node == NULL) {
1506                 return ENOMEM;
1507         }
1508
1509         ret = ctdb_node_and_flags_pull_elems(node, buf, buflen, node);
1510         if (ret != 0) {
1511                 TALLOC_FREE(node);
1512         }
1513
1514         *out = node;
1515         return ret;
1516 }
1517
1518 struct ctdb_node_map_wire {
1519         uint32_t num;
1520         struct ctdb_node_and_flags node[1];
1521 };
1522
1523 size_t ctdb_node_map_len(struct ctdb_node_map *nodemap)
1524 {
1525         return sizeof(uint32_t) +
1526                nodemap->num * sizeof(struct ctdb_node_and_flags);
1527 }
1528
1529 void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf)
1530 {
1531         struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
1532         size_t offset;
1533         int i;
1534
1535         wire->num = nodemap->num;
1536
1537         offset = offsetof(struct ctdb_node_map_wire, node);
1538         for (i=0; i<nodemap->num; i++) {
1539                 ctdb_node_and_flags_push(&nodemap->node[i], &buf[offset]);
1540                 offset += ctdb_node_and_flags_len(&nodemap->node[i]);
1541         }
1542 }
1543
1544 int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1545                        struct ctdb_node_map **out)
1546 {
1547         struct ctdb_node_map *nodemap;
1548         struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
1549         size_t offset;
1550         int i;
1551         bool ret;
1552
1553         if (buflen < sizeof(uint32_t)) {
1554                 return EMSGSIZE;
1555         }
1556         if (wire->num > buflen / sizeof(struct ctdb_node_and_flags)) {
1557                 return EMSGSIZE;
1558         }
1559         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_node_and_flags) <
1560             sizeof(uint32_t)) {
1561                 return EMSGSIZE;
1562         }
1563         if (buflen < sizeof(uint32_t) +
1564                      wire->num * sizeof(struct ctdb_node_and_flags)) {
1565                 return EMSGSIZE;
1566         }
1567
1568         nodemap = talloc(mem_ctx, struct ctdb_node_map);
1569         if (nodemap == NULL) {
1570                 return ENOMEM;
1571         }
1572
1573         nodemap->num = wire->num;
1574         nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags,
1575                                      wire->num);
1576         if (nodemap->node == NULL) {
1577                 talloc_free(nodemap);
1578                 return ENOMEM;
1579         }
1580
1581         offset = offsetof(struct ctdb_node_map_wire, node);
1582         for (i=0; i<wire->num; i++) {
1583                 ret = ctdb_node_and_flags_pull_elems(nodemap->node,
1584                                                      &buf[offset],
1585                                                      buflen-offset,
1586                                                      &nodemap->node[i]);
1587                 if (ret != 0) {
1588                         talloc_free(nodemap);
1589                         return ret;
1590                 }
1591                 offset += ctdb_node_and_flags_len(&nodemap->node[i]);
1592         }
1593
1594         *out = nodemap;
1595         return 0;
1596 }
1597
1598 size_t ctdb_script_len(struct ctdb_script *script)
1599 {
1600         return sizeof(struct ctdb_script);
1601 }
1602
1603 void ctdb_script_push(struct ctdb_script *script, uint8_t *buf)
1604 {
1605         memcpy(buf, script, sizeof(struct ctdb_script));
1606 }
1607
1608 static int ctdb_script_pull_elems(uint8_t *buf, size_t buflen,
1609                                   TALLOC_CTX *mem_ctx,
1610                                   struct ctdb_script *out)
1611 {
1612         if (buflen < sizeof(struct ctdb_script)) {
1613                 return EMSGSIZE;
1614         }
1615
1616         memcpy(out, buf, sizeof(struct ctdb_script));
1617
1618         return 0;
1619 }
1620
1621 int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1622                      struct ctdb_script **out)
1623 {
1624         struct ctdb_script *script;
1625         int ret;
1626
1627         script = talloc(mem_ctx, struct ctdb_script);
1628         if (script == NULL) {
1629                 return ENOMEM;
1630         }
1631
1632         ret = ctdb_script_pull_elems(buf, buflen, script, script);
1633         if (ret != 0) {
1634                 TALLOC_FREE(script);
1635         }
1636
1637         *out = script;
1638         return ret;
1639 }
1640
1641 struct ctdb_script_list_wire {
1642         uint32_t num_scripts;
1643         struct ctdb_script script[1];
1644 };
1645
1646 size_t ctdb_script_list_len(struct ctdb_script_list *script_list)
1647 {
1648         int i;
1649         size_t len;
1650
1651         if (script_list == NULL) {
1652                 return 0;
1653         }
1654
1655         len = offsetof(struct ctdb_script_list_wire, script);
1656         for (i=0; i<script_list->num_scripts; i++) {
1657                 len += ctdb_script_len(&script_list->script[i]);
1658         }
1659         return len;
1660 }
1661
1662 void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf)
1663 {
1664         struct ctdb_script_list_wire *wire =
1665                 (struct ctdb_script_list_wire *)buf;
1666         size_t offset;
1667         int i;
1668
1669         if (script_list == NULL) {
1670                 return;
1671         }
1672
1673         wire->num_scripts = script_list->num_scripts;
1674
1675         offset = offsetof(struct ctdb_script_list_wire, script);
1676         for (i=0; i<script_list->num_scripts; i++) {
1677                 ctdb_script_push(&script_list->script[i], &buf[offset]);
1678                 offset += ctdb_script_len(&script_list->script[i]);
1679         }
1680 }
1681
1682 int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1683                           struct ctdb_script_list **out)
1684 {
1685         struct ctdb_script_list *script_list;
1686         struct ctdb_script_list_wire *wire =
1687                 (struct ctdb_script_list_wire *)buf;
1688         size_t offset;
1689         int i;
1690         bool ret;
1691
1692         /* If event scripts have never been run, the result will be NULL */
1693         if (buflen == 0) {
1694                 *out = NULL;
1695                 return 0;
1696         }
1697
1698         offset = offsetof(struct ctdb_script_list_wire, script);
1699
1700         if (buflen < offset) {
1701                 return EMSGSIZE;
1702         }
1703         if (wire->num_scripts > buflen / sizeof(struct ctdb_script)) {
1704                 return EMSGSIZE;
1705         }
1706         if (offset + wire->num_scripts * sizeof(struct ctdb_script) < offset) {
1707                 return EMSGSIZE;
1708         }
1709         if (buflen < offset + wire->num_scripts * sizeof(struct ctdb_script)) {
1710                 return EMSGSIZE;
1711         }
1712
1713         script_list = talloc(mem_ctx, struct ctdb_script_list);
1714         if (script_list == NULL) {
1715                 return ENOMEM;
1716
1717         }
1718
1719         script_list->num_scripts = wire->num_scripts;
1720         script_list->script = talloc_array(script_list, struct ctdb_script,
1721                                            wire->num_scripts);
1722         if (script_list->script == NULL) {
1723                 talloc_free(script_list);
1724                 return ENOMEM;
1725         }
1726
1727         for (i=0; i<wire->num_scripts; i++) {
1728                 ret = ctdb_script_pull_elems(&buf[offset], buflen-offset,
1729                                              script_list->script,
1730                                              &script_list->script[i]);
1731                 if (ret != 0) {
1732                         talloc_free(script_list);
1733                         return ret;
1734                 }
1735                 offset += ctdb_script_len(&script_list->script[i]);
1736         }
1737
1738         *out = script_list;
1739         return 0;
1740 }
1741
1742 size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state)
1743 {
1744         return sizeof(struct ctdb_ban_state);
1745 }
1746
1747 void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf)
1748 {
1749         memcpy(buf, ban_state, sizeof(struct ctdb_ban_state));
1750 }
1751
1752 int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1753                         struct ctdb_ban_state **out)
1754 {
1755         struct ctdb_ban_state *ban_state;
1756
1757         if (buflen < sizeof(struct ctdb_ban_state)) {
1758                 return EMSGSIZE;
1759         }
1760
1761         ban_state = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_ban_state));
1762         if (ban_state == NULL) {
1763                 return ENOMEM;
1764         }
1765
1766         *out = ban_state;
1767         return 0;
1768 }
1769
1770 struct ctdb_notify_data_wire {
1771         uint64_t srvid;
1772         uint32_t len;
1773         uint8_t data[1];
1774 };
1775
1776 size_t ctdb_notify_data_len(struct ctdb_notify_data *notify)
1777 {
1778         return offsetof(struct ctdb_notify_data_wire, data) +
1779                notify->data.dsize;
1780 }
1781
1782 void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf)
1783 {
1784         struct ctdb_notify_data_wire *wire =
1785                 (struct ctdb_notify_data_wire *)buf;
1786
1787         wire->srvid = notify->srvid;
1788         wire->len = notify->data.dsize;
1789         memcpy(wire->data, notify->data.dptr, notify->data.dsize);
1790 }
1791
1792 int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1793                           struct ctdb_notify_data **out)
1794 {
1795         struct ctdb_notify_data *notify;
1796         struct ctdb_notify_data_wire *wire =
1797                 (struct ctdb_notify_data_wire *)buf;
1798
1799         if (buflen < offsetof(struct ctdb_notify_data_wire, data)) {
1800                 return EMSGSIZE;
1801         }
1802         if (wire->len > buflen) {
1803                 return EMSGSIZE;
1804         }
1805         if (offsetof(struct ctdb_notify_data_wire, data) + wire->len <
1806             offsetof(struct ctdb_notify_data_wire, data)) {
1807                 return EMSGSIZE;
1808         }
1809         if (buflen < offsetof(struct ctdb_notify_data_wire, data) + wire->len) {
1810                 return EMSGSIZE;
1811         }
1812
1813         notify = talloc(mem_ctx, struct ctdb_notify_data);
1814         if (notify == NULL) {
1815                 return ENOMEM;
1816         }
1817
1818         notify->srvid = wire->srvid;
1819         notify->data.dsize = wire->len;
1820         notify->data.dptr = talloc_memdup(notify, wire->data, wire->len);
1821         if (notify->data.dptr == NULL) {
1822                 talloc_free(notify);
1823                 return ENOMEM;
1824         }
1825
1826         *out = notify;
1827         return 0;
1828 }
1829
1830 size_t ctdb_iface_len(struct ctdb_iface *iface)
1831 {
1832         return sizeof(struct ctdb_iface);
1833 }
1834
1835 void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf)
1836 {
1837         memcpy(buf, iface, sizeof(struct ctdb_iface));
1838 }
1839
1840 static int ctdb_iface_pull_elems(uint8_t *buf, size_t buflen,
1841                                  TALLOC_CTX *mem_ctx,
1842                                  struct ctdb_iface *out)
1843 {
1844         if (buflen < sizeof(struct ctdb_iface)) {
1845                 return EMSGSIZE;
1846         }
1847
1848         memcpy(out, buf, sizeof(struct ctdb_iface));
1849
1850         return 0;
1851 }
1852
1853 int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1854                     struct ctdb_iface **out)
1855 {
1856         struct ctdb_iface *iface;
1857         int ret;
1858
1859         iface = talloc(mem_ctx, struct ctdb_iface);
1860         if (iface == NULL) {
1861                 return ENOMEM;
1862         }
1863
1864         ret = ctdb_iface_pull_elems(buf, buflen, iface, iface);
1865         if (ret != 0) {
1866                 TALLOC_FREE(iface);
1867         }
1868
1869         *out = iface;
1870         return ret;
1871 }
1872
1873 struct ctdb_iface_list_wire {
1874         uint32_t num;
1875         struct ctdb_iface iface[1];
1876 };
1877
1878 size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list)
1879 {
1880         return sizeof(uint32_t) +
1881                iface_list->num * sizeof(struct ctdb_iface);
1882 }
1883
1884 void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf)
1885 {
1886         struct ctdb_iface_list_wire *wire =
1887                 (struct ctdb_iface_list_wire *)buf;
1888
1889         wire->num = iface_list->num;
1890         memcpy(wire->iface, iface_list->iface,
1891                iface_list->num * sizeof(struct ctdb_iface));
1892 }
1893
1894 int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1895                          struct ctdb_iface_list **out)
1896 {
1897         struct ctdb_iface_list *iface_list;
1898         struct ctdb_iface_list_wire *wire =
1899                 (struct ctdb_iface_list_wire *)buf;
1900
1901         if (buflen < sizeof(uint32_t)) {
1902                 return EMSGSIZE;
1903         }
1904         if (wire->num > buflen / sizeof(struct ctdb_iface)) {
1905                 return EMSGSIZE;
1906         }
1907         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_iface) <
1908             sizeof(uint32_t)) {
1909                 return EMSGSIZE;
1910         }
1911         if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_iface)) {
1912                 return EMSGSIZE;
1913         }
1914
1915         iface_list = talloc(mem_ctx, struct ctdb_iface_list);
1916         if (iface_list == NULL) {
1917                 return ENOMEM;
1918         }
1919
1920         iface_list->num = wire->num;
1921         iface_list->iface = talloc_array(iface_list, struct ctdb_iface,
1922                                          wire->num);
1923         if (iface_list->iface == NULL) {
1924                 talloc_free(iface_list);
1925                 return ENOMEM;
1926         }
1927
1928         memcpy(iface_list->iface, wire->iface,
1929                wire->num * sizeof(struct ctdb_iface));
1930
1931         *out = iface_list;
1932         return 0;
1933 }
1934
1935 struct ctdb_public_ip_info_wire {
1936         struct ctdb_public_ip ip;
1937         uint32_t active_idx;
1938         uint32_t num;
1939         struct ctdb_iface ifaces[1];
1940 };
1941
1942 size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo)
1943 {
1944         return offsetof(struct ctdb_public_ip_info_wire, num) +
1945                ctdb_iface_list_len(ipinfo->ifaces);
1946 }
1947
1948 void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf)
1949 {
1950         struct ctdb_public_ip_info_wire *wire =
1951                 (struct ctdb_public_ip_info_wire *)buf;
1952         size_t offset;
1953
1954         offset = offsetof(struct ctdb_public_ip_info_wire, num);
1955         memcpy(wire, ipinfo, offset);
1956         wire->num = ipinfo->ifaces->num;
1957         memcpy(wire->ifaces, ipinfo->ifaces->iface,
1958                ipinfo->ifaces->num * sizeof(struct ctdb_iface));
1959 }
1960
1961 int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1962                              struct ctdb_public_ip_info **out)
1963 {
1964         struct ctdb_public_ip_info *ipinfo;
1965         struct ctdb_public_ip_info_wire *wire =
1966                 (struct ctdb_public_ip_info_wire *)buf;
1967
1968         if (buflen < offsetof(struct ctdb_public_ip_info_wire, ifaces)) {
1969                 return EMSGSIZE;
1970         }
1971         if (wire->num > buflen / sizeof(struct ctdb_iface)) {
1972                 return EMSGSIZE;
1973         }
1974         if (offsetof(struct ctdb_public_ip_info_wire, ifaces) +
1975             wire->num * sizeof(struct ctdb_iface) <
1976             offsetof(struct ctdb_public_ip_info_wire, ifaces)) {
1977                 return EMSGSIZE;
1978         }
1979         if (buflen < offsetof(struct ctdb_public_ip_info_wire, ifaces) +
1980                      wire->num * sizeof(struct ctdb_iface)) {
1981                 return EMSGSIZE;
1982         }
1983
1984         ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info);
1985         if (ipinfo == NULL) {
1986                 return ENOMEM;
1987         }
1988
1989         memcpy(ipinfo, wire, offsetof(struct ctdb_public_ip_info_wire, num));
1990
1991         ipinfo->ifaces = talloc(ipinfo, struct ctdb_iface_list);
1992         if (ipinfo->ifaces == NULL) {
1993                 talloc_free(ipinfo);
1994                 return ENOMEM;
1995         }
1996
1997         ipinfo->ifaces->num = wire->num;
1998         ipinfo->ifaces->iface = talloc_array(ipinfo->ifaces, struct ctdb_iface,
1999                                              wire->num);
2000         if (ipinfo->ifaces->iface == NULL) {
2001                 talloc_free(ipinfo);
2002                 return ENOMEM;
2003         }
2004
2005         memcpy(ipinfo->ifaces->iface, wire->ifaces,
2006                wire->num * sizeof(struct ctdb_iface));
2007
2008         *out = ipinfo;
2009         return 0;
2010 }
2011
2012 struct ctdb_key_data_wire {
2013         uint32_t db_id;
2014         struct ctdb_ltdb_header header;
2015         uint32_t keylen;
2016         uint8_t key[1];
2017 };
2018
2019 size_t ctdb_key_data_len(struct ctdb_key_data *key)
2020 {
2021         return offsetof(struct ctdb_key_data_wire, key) + key->key.dsize;
2022 }
2023
2024 void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf)
2025 {
2026         struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
2027
2028         memcpy(wire, key, offsetof(struct ctdb_key_data, key));
2029         wire->keylen = key->key.dsize;
2030         memcpy(wire->key, key->key.dptr, key->key.dsize);
2031 }
2032
2033 int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2034                        struct ctdb_key_data **out)
2035 {
2036         struct ctdb_key_data *key_data;
2037         struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
2038
2039         if (buflen < offsetof(struct ctdb_key_data_wire, key)) {
2040                 return EMSGSIZE;
2041         }
2042         if (wire->keylen > buflen) {
2043                 return EMSGSIZE;
2044         }
2045         if (offsetof(struct ctdb_key_data_wire, key) + wire->keylen <
2046             offsetof(struct ctdb_key_data_wire, key)) {
2047                 return EMSGSIZE;
2048         }
2049         if (buflen < offsetof(struct ctdb_key_data_wire, key) + wire->keylen) {
2050                 return EMSGSIZE;
2051         }
2052
2053         key_data = talloc(mem_ctx, struct ctdb_key_data);
2054         if (key_data == NULL) {
2055                 return ENOMEM;
2056         }
2057
2058         memcpy(key_data, wire, offsetof(struct ctdb_key_data, key));
2059
2060         key_data->key.dsize = wire->keylen;
2061         key_data->key.dptr = talloc_memdup(key_data, wire->key, wire->keylen);
2062         if (key_data->key.dptr == NULL) {
2063                 talloc_free(key_data);
2064                 return ENOMEM;
2065         }
2066
2067         *out = key_data;
2068         return 0;
2069 }
2070
2071 struct ctdb_db_statistics_wire {
2072         struct ctdb_db_statistics dbstats;
2073         char hot_keys_wire[1];
2074 };
2075
2076 size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats)
2077 {
2078         size_t len;
2079         int i;
2080
2081         len = sizeof(struct ctdb_db_statistics);
2082         for (i=0; i<MAX_HOT_KEYS; i++) {
2083                 len += dbstats->hot_keys[i].key.dsize;
2084         }
2085         return len;
2086 }
2087
2088 void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf)
2089 {
2090         struct ctdb_db_statistics_wire *wire =
2091                 (struct ctdb_db_statistics_wire *)buf;
2092         size_t offset;
2093         int i;
2094
2095         dbstats->num_hot_keys = MAX_HOT_KEYS;
2096         memcpy(wire, dbstats, sizeof(struct ctdb_db_statistics));
2097
2098         offset = 0;
2099         for (i=0; i<MAX_HOT_KEYS; i++) {
2100                 memcpy(&wire->hot_keys_wire[offset],
2101                        dbstats->hot_keys[i].key.dptr,
2102                        dbstats->hot_keys[i].key.dsize);
2103                 offset += dbstats->hot_keys[i].key.dsize;
2104         }
2105 }
2106
2107 int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2108                             struct ctdb_db_statistics **out)
2109 {
2110         struct ctdb_db_statistics *dbstats;
2111         struct ctdb_db_statistics_wire *wire =
2112                 (struct ctdb_db_statistics_wire *)buf;
2113         size_t offset;
2114         int i;
2115
2116         if (buflen < sizeof(struct ctdb_db_statistics)) {
2117                 return EMSGSIZE;
2118         }
2119
2120         offset = 0;
2121         for (i=0; i<wire->dbstats.num_hot_keys; i++) {
2122                 if (wire->dbstats.hot_keys[i].key.dsize > buflen) {
2123                         return EMSGSIZE;
2124                 }
2125                 if (offset + wire->dbstats.hot_keys[i].key.dsize < offset) {
2126                         return EMSGSIZE;
2127                 }
2128                 offset += wire->dbstats.hot_keys[i].key.dsize;
2129                 if (offset > buflen) {
2130                         return EMSGSIZE;
2131                 }
2132         }
2133         if (sizeof(struct ctdb_db_statistics) + offset <
2134             sizeof(struct ctdb_db_statistics)) {
2135                 return EMSGSIZE;
2136         }
2137         if (buflen < sizeof(struct ctdb_db_statistics) + offset) {
2138                 return EMSGSIZE;
2139         }
2140
2141         dbstats = talloc(mem_ctx, struct ctdb_db_statistics);
2142         if (dbstats == NULL) {
2143                 return ENOMEM;
2144         }
2145
2146         memcpy(dbstats, wire, sizeof(struct ctdb_db_statistics));
2147
2148         offset = 0;
2149         for (i=0; i<wire->dbstats.num_hot_keys; i++) {
2150                 uint8_t *ptr;
2151                 size_t key_size;
2152
2153                 key_size = dbstats->hot_keys[i].key.dsize;
2154                 ptr = talloc_memdup(mem_ctx, &wire->hot_keys_wire[offset],
2155                                     key_size);
2156                 if (ptr == NULL) {
2157                         talloc_free(dbstats);
2158                         return ENOMEM;
2159                 }
2160                 dbstats->hot_keys[i].key.dptr = ptr;
2161                 offset += key_size;
2162         }
2163
2164         *out = dbstats;
2165         return 0;
2166 }
2167
2168 size_t ctdb_election_message_len(struct ctdb_election_message *election)
2169 {
2170         return sizeof(struct ctdb_election_message);
2171 }
2172
2173 void ctdb_election_message_push(struct ctdb_election_message *election,
2174                                 uint8_t *buf)
2175 {
2176         memcpy(buf, election, sizeof(struct ctdb_election_message));
2177 }
2178
2179 int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2180                                struct ctdb_election_message **out)
2181 {
2182         struct ctdb_election_message *election;
2183
2184         if (buflen < sizeof(struct ctdb_election_message)) {
2185                 return EMSGSIZE;
2186         }
2187
2188         election = talloc_memdup(mem_ctx, buf,
2189                                  sizeof(struct ctdb_election_message));
2190         if (election == NULL) {
2191                 return ENOMEM;
2192         }
2193
2194         *out = election;
2195         return 0;
2196 }
2197
2198 size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg)
2199 {
2200         return sizeof(struct ctdb_srvid_message);
2201 }
2202
2203 void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf)
2204 {
2205         memcpy(buf, msg, sizeof(struct ctdb_srvid_message));
2206 }
2207
2208 int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2209                             struct ctdb_srvid_message **out)
2210 {
2211         struct ctdb_srvid_message *msg;
2212
2213         if (buflen < sizeof(struct ctdb_srvid_message)) {
2214                 return EMSGSIZE;
2215         }
2216
2217         msg = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_srvid_message));
2218         if (msg == NULL) {
2219                 return ENOMEM;
2220         }
2221
2222         *out = msg;
2223         return 0;
2224 }
2225
2226 size_t ctdb_disable_message_len(struct ctdb_disable_message *disable)
2227 {
2228         return sizeof(struct ctdb_disable_message);
2229 }
2230
2231 void ctdb_disable_message_push(struct ctdb_disable_message *disable,
2232                                uint8_t *buf)
2233 {
2234         memcpy(buf, disable, sizeof(struct ctdb_disable_message));
2235 }
2236
2237 int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2238                               struct ctdb_disable_message **out)
2239 {
2240         struct ctdb_disable_message *disable;
2241
2242         if (buflen < sizeof(struct ctdb_disable_message)) {
2243                 return EMSGSIZE;
2244         }
2245
2246         disable = talloc_memdup(mem_ctx, buf,
2247                                 sizeof(struct ctdb_disable_message));
2248         if (disable == NULL) {
2249                 return ENOMEM;
2250         }
2251
2252         *out = disable;
2253         return 0;
2254 }
2255
2256 size_t ctdb_server_id_len(struct ctdb_server_id *sid)
2257 {
2258         return sizeof(struct ctdb_server_id);
2259 }
2260
2261 void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf)
2262 {
2263         memcpy(buf, sid, sizeof(struct ctdb_server_id));
2264 }
2265
2266 int ctdb_server_id_pull(uint8_t *buf, size_t buflen,
2267                         struct ctdb_server_id *sid)
2268 {
2269         if (buflen < sizeof(struct ctdb_server_id)) {
2270                 return EMSGSIZE;
2271         }
2272
2273         memcpy(sid, buf, sizeof(struct ctdb_server_id));
2274         return 0;
2275 }
2276
2277 size_t ctdb_g_lock_len(struct ctdb_g_lock *lock)
2278 {
2279         return sizeof(struct ctdb_g_lock);
2280 }
2281
2282 void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf)
2283 {
2284         memcpy(buf, lock, sizeof(struct ctdb_g_lock));
2285 }
2286
2287 int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock)
2288 {
2289         if (buflen < sizeof(struct ctdb_g_lock)) {
2290                 return EMSGSIZE;
2291         }
2292
2293         memcpy(lock, buf, sizeof(struct ctdb_g_lock));
2294         return 0;
2295 }
2296
2297 size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list)
2298 {
2299         return lock_list->num * sizeof(struct ctdb_g_lock);
2300 }
2301
2302 void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf)
2303 {
2304         size_t offset = 0;
2305         int i;
2306
2307         for (i=0; i<lock_list->num; i++) {
2308                 ctdb_g_lock_push(&lock_list->lock[i], &buf[offset]);
2309                 offset += sizeof(struct ctdb_g_lock);
2310         }
2311 }
2312
2313 int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2314                           struct ctdb_g_lock_list **out)
2315 {
2316         struct ctdb_g_lock_list *lock_list;
2317         unsigned count;
2318         size_t offset;
2319         int ret, i;
2320
2321         lock_list = talloc_zero(mem_ctx, struct ctdb_g_lock_list);
2322         if (lock_list == NULL) {
2323                 return ENOMEM;
2324         }
2325
2326         count = buflen / sizeof(struct ctdb_g_lock);
2327         lock_list->lock = talloc_array(lock_list, struct ctdb_g_lock, count);
2328         if (lock_list->lock == NULL) {
2329                 talloc_free(lock_list);
2330                 return ENOMEM;
2331         }
2332
2333         offset = 0;
2334         for (i=0; i<count; i++) {
2335                 ret = ctdb_g_lock_pull(&buf[offset], buflen-offset,
2336                                        &lock_list->lock[i]);
2337                 if (ret != 0) {
2338                         talloc_free(lock_list);
2339                         return ret;
2340                 }
2341                 offset += sizeof(struct ctdb_g_lock);
2342         }
2343
2344         lock_list->num = count;
2345
2346         *out = lock_list;
2347         return 0;
2348 }