4e8b575496edfa7a4ed8078c8b1ba295d4e8f242
[vlendec/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_tdb_datan_len(TDB_DATA *in)
71 {
72         uint32_t u32 = ctdb_tdb_data_len(in);
73
74         return ctdb_uint32_len(&u32) + u32;
75 }
76
77 void ctdb_tdb_datan_push(TDB_DATA *in, uint8_t *buf, size_t *npush)
78 {
79         size_t offset = 0, np;
80         uint32_t u32 = ctdb_tdb_data_len(in);
81
82         ctdb_uint32_push(&u32, buf+offset, &np);
83         offset += np;
84
85         ctdb_tdb_data_push(in, buf+offset, &np);
86         offset += np;
87
88         *npush = offset;
89 }
90
91 int ctdb_tdb_datan_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
92                         TDB_DATA *out, size_t *npull)
93 {
94         size_t offset = 0, np;
95         uint32_t u32;
96         int ret;
97
98         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &u32, &np);
99         if (ret != 0) {
100                 return ret;
101         }
102         offset += np;
103
104         if (buflen-offset < u32) {
105                 return EMSGSIZE;
106         }
107
108         ret = ctdb_tdb_data_pull(buf+offset, u32, mem_ctx, out, &np);
109         if (ret != 0) {
110                 return ret;
111         }
112         offset += np;
113
114         *npull = offset;
115         return 0;
116 }
117
118 size_t ctdb_latency_counter_len(struct ctdb_latency_counter *in)
119 {
120         return ctdb_int32_len(&in->num) +
121                 ctdb_padding_len(4) +
122                 ctdb_double_len(&in->min) +
123                 ctdb_double_len(&in->max) +
124                 ctdb_double_len(&in->total);
125 }
126
127 void ctdb_latency_counter_push(struct ctdb_latency_counter *in, uint8_t *buf,
128                                size_t *npush)
129 {
130         size_t offset = 0, np;
131
132         ctdb_int32_push(&in->num, buf+offset, &np);
133         offset += np;
134
135         ctdb_padding_push(4, buf+offset, &np);
136         offset += np;
137
138         ctdb_double_push(&in->min, buf+offset, &np);
139         offset += np;
140
141         ctdb_double_push(&in->max, buf+offset, &np);
142         offset += np;
143
144         ctdb_double_push(&in->total, buf+offset, &np);
145         offset += np;
146
147         *npush = offset;
148 }
149
150 int ctdb_latency_counter_pull(uint8_t *buf, size_t buflen,
151                               struct ctdb_latency_counter *out, size_t *npull)
152 {
153         size_t offset = 0, np;
154         int ret;
155
156         ret = ctdb_int32_pull(buf+offset, buflen-offset, &out->num, &np);
157         if (ret != 0) {
158                 return ret;
159         }
160         offset += np;
161
162         ret = ctdb_padding_pull(buf+offset, buflen-offset, 4, &np);
163         if (ret != 0) {
164                 return ret;
165         }
166         offset += np;
167
168         ret = ctdb_double_pull(buf+offset, buflen-offset, &out->min, &np);
169         if (ret != 0) {
170                 return ret;
171         }
172         offset += np;
173
174         ret = ctdb_double_pull(buf+offset, buflen-offset, &out->max, &np);
175         if (ret != 0) {
176                 return ret;
177         }
178         offset += np;
179
180         ret = ctdb_double_pull(buf+offset, buflen-offset, &out->total, &np);
181         if (ret != 0) {
182                 return ret;
183         }
184         offset += np;
185
186         *npull = offset;
187         return 0;
188 }
189
190 size_t ctdb_statistics_len(struct ctdb_statistics *in)
191 {
192         return ctdb_uint32_len(&in->num_clients) +
193                 ctdb_uint32_len(&in->frozen) +
194                 ctdb_uint32_len(&in->recovering) +
195                 ctdb_uint32_len(&in->client_packets_sent) +
196                 ctdb_uint32_len(&in->client_packets_recv) +
197                 ctdb_uint32_len(&in->node_packets_sent) +
198                 ctdb_uint32_len(&in->node_packets_recv) +
199                 ctdb_uint32_len(&in->keepalive_packets_sent) +
200                 ctdb_uint32_len(&in->keepalive_packets_recv) +
201                 ctdb_uint32_len(&in->node.req_call) +
202                 ctdb_uint32_len(&in->node.reply_call) +
203                 ctdb_uint32_len(&in->node.req_dmaster) +
204                 ctdb_uint32_len(&in->node.reply_dmaster) +
205                 ctdb_uint32_len(&in->node.reply_error) +
206                 ctdb_uint32_len(&in->node.req_message) +
207                 ctdb_uint32_len(&in->node.req_control) +
208                 ctdb_uint32_len(&in->node.reply_control) +
209                 ctdb_uint32_len(&in->client.req_call) +
210                 ctdb_uint32_len(&in->client.req_message) +
211                 ctdb_uint32_len(&in->client.req_control) +
212                 ctdb_uint32_len(&in->timeouts.call) +
213                 ctdb_uint32_len(&in->timeouts.control) +
214                 ctdb_uint32_len(&in->timeouts.traverse) +
215                 ctdb_padding_len(4) +
216                 ctdb_latency_counter_len(&in->reclock.ctdbd) +
217                 ctdb_latency_counter_len(&in->reclock.recd) +
218                 ctdb_uint32_len(&in->locks.num_calls) +
219                 ctdb_uint32_len(&in->locks.num_current) +
220                 ctdb_uint32_len(&in->locks.num_pending) +
221                 ctdb_uint32_len(&in->locks.num_failed) +
222                 ctdb_latency_counter_len(&in->locks.latency) +
223                 MAX_COUNT_BUCKETS * ctdb_uint32_len(&in->locks.buckets[0]) +
224                 ctdb_uint32_len(&in->total_calls) +
225                 ctdb_uint32_len(&in->pending_calls) +
226                 ctdb_uint32_len(&in->childwrite_calls) +
227                 ctdb_uint32_len(&in->pending_childwrite_calls) +
228                 ctdb_uint32_len(&in->memory_used) +
229                 ctdb_uint32_len(&in->__last_counter) +
230                 ctdb_uint32_len(&in->max_hop_count) +
231                 MAX_COUNT_BUCKETS *
232                         ctdb_uint32_len(&in->hop_count_bucket[0]) +
233                 ctdb_padding_len(4) +
234                 ctdb_latency_counter_len(&in->call_latency) +
235                 ctdb_latency_counter_len(&in->childwrite_latency) +
236                 ctdb_uint32_len(&in->num_recoveries) +
237                 ctdb_padding_len(4) +
238                 ctdb_timeval_len(&in->statistics_start_time) +
239                 ctdb_timeval_len(&in->statistics_current_time) +
240                 ctdb_uint32_len(&in->total_ro_delegations) +
241                 ctdb_uint32_len(&in->total_ro_revokes);
242 }
243
244 void ctdb_statistics_push(struct ctdb_statistics *in, uint8_t *buf,
245                           size_t *npush)
246 {
247         size_t offset = 0, np;
248         int i;
249
250         ctdb_uint32_push(&in->num_clients, buf+offset, &np);
251         offset += np;
252
253         ctdb_uint32_push(&in->frozen, buf+offset, &np);
254         offset += np;
255
256         ctdb_uint32_push(&in->recovering, buf+offset, &np);
257         offset += np;
258
259         ctdb_uint32_push(&in->client_packets_sent, buf+offset, &np);
260         offset += np;
261
262         ctdb_uint32_push(&in->client_packets_recv, buf+offset, &np);
263         offset += np;
264
265         ctdb_uint32_push(&in->node_packets_sent, buf+offset, &np);
266         offset += np;
267
268         ctdb_uint32_push(&in->node_packets_recv, buf+offset, &np);
269         offset += np;
270
271         ctdb_uint32_push(&in->keepalive_packets_sent, buf+offset, &np);
272         offset += np;
273
274         ctdb_uint32_push(&in->keepalive_packets_recv, buf+offset, &np);
275         offset += np;
276
277         ctdb_uint32_push(&in->node.req_call, buf+offset, &np);
278         offset += np;
279
280         ctdb_uint32_push(&in->node.reply_call, buf+offset, &np);
281         offset += np;
282
283         ctdb_uint32_push(&in->node.req_dmaster, buf+offset, &np);
284         offset += np;
285
286         ctdb_uint32_push(&in->node.reply_dmaster, buf+offset, &np);
287         offset += np;
288
289         ctdb_uint32_push(&in->node.reply_error, buf+offset, &np);
290         offset += np;
291
292         ctdb_uint32_push(&in->node.req_message, buf+offset, &np);
293         offset += np;
294
295         ctdb_uint32_push(&in->node.req_control, buf+offset, &np);
296         offset += np;
297
298         ctdb_uint32_push(&in->node.reply_control, buf+offset, &np);
299         offset += np;
300
301         ctdb_uint32_push(&in->client.req_call, buf+offset, &np);
302         offset += np;
303
304         ctdb_uint32_push(&in->client.req_message, buf+offset, &np);
305         offset += np;
306
307         ctdb_uint32_push(&in->client.req_control, buf+offset, &np);
308         offset += np;
309
310         ctdb_uint32_push(&in->timeouts.call, buf+offset, &np);
311         offset += np;
312
313         ctdb_uint32_push(&in->timeouts.control, buf+offset, &np);
314         offset += np;
315
316         ctdb_uint32_push(&in->timeouts.traverse, buf+offset, &np);
317         offset += np;
318
319         ctdb_padding_push(4, buf+offset, &np);
320         offset += np;
321
322         ctdb_latency_counter_push(&in->reclock.ctdbd, buf+offset, &np);
323         offset += np;
324
325         ctdb_latency_counter_push(&in->reclock.recd, buf+offset, &np);
326         offset += np;
327
328         ctdb_uint32_push(&in->locks.num_calls, buf+offset, &np);
329         offset += np;
330
331         ctdb_uint32_push(&in->locks.num_current, buf+offset, &np);
332         offset += np;
333
334         ctdb_uint32_push(&in->locks.num_pending, buf+offset, &np);
335         offset += np;
336
337         ctdb_uint32_push(&in->locks.num_failed, buf+offset, &np);
338         offset += np;
339
340         ctdb_latency_counter_push(&in->locks.latency, buf+offset, &np);
341         offset += np;
342
343         for (i=0; i<MAX_COUNT_BUCKETS; i++) {
344                 ctdb_uint32_push(&in->locks.buckets[i], buf+offset, &np);
345                 offset += np;
346         }
347
348         ctdb_uint32_push(&in->total_calls, buf+offset, &np);
349         offset += np;
350
351         ctdb_uint32_push(&in->pending_calls, buf+offset, &np);
352         offset += np;
353
354         ctdb_uint32_push(&in->childwrite_calls, buf+offset, &np);
355         offset += np;
356
357         ctdb_uint32_push(&in->pending_childwrite_calls, buf+offset, &np);
358         offset += np;
359
360         ctdb_uint32_push(&in->memory_used, buf+offset, &np);
361         offset += np;
362
363         ctdb_uint32_push(&in->__last_counter, buf+offset, &np);
364         offset += np;
365
366         ctdb_uint32_push(&in->max_hop_count, buf+offset, &np);
367         offset += np;
368
369         for (i=0; i<MAX_COUNT_BUCKETS; i++) {
370                 ctdb_uint32_push(&in->hop_count_bucket[i], buf+offset, &np);
371                 offset += np;
372         }
373
374         ctdb_padding_push(4, buf+offset, &np);
375         offset += np;
376
377         ctdb_latency_counter_push(&in->call_latency, buf+offset, &np);
378         offset += np;
379
380         ctdb_latency_counter_push(&in->childwrite_latency, buf+offset, &np);
381         offset += np;
382
383         ctdb_uint32_push(&in->num_recoveries, buf+offset, &np);
384         offset += np;
385
386         ctdb_padding_push(4, buf+offset, &np);
387         offset += np;
388
389         ctdb_timeval_push(&in->statistics_start_time, buf+offset, &np);
390         offset += np;
391
392         ctdb_timeval_push(&in->statistics_current_time, buf+offset, &np);
393         offset += np;
394
395         ctdb_uint32_push(&in->total_ro_delegations, buf+offset, &np);
396         offset += np;
397
398         ctdb_uint32_push(&in->total_ro_revokes, buf+offset, &np);
399         offset += np;
400
401         *npush = offset;
402 }
403
404 static int ctdb_statistics_pull_elems(uint8_t *buf, size_t buflen,
405                                       TALLOC_CTX *mem_ctx,
406                                       struct ctdb_statistics *out,
407                                       size_t *npull)
408 {
409         size_t offset = 0, np;
410         int ret, i;
411
412         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->num_clients,
413                                &np);
414         if (ret != 0) {
415                 return ret;
416         }
417         offset += np;
418
419         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->frozen, &np);
420         if (ret != 0) {
421                 return ret;
422         }
423         offset += np;
424
425         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->recovering,
426                                &np);
427         if (ret != 0) {
428                 return ret;
429         }
430         offset += np;
431
432         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
433                                &out->client_packets_sent, &np);
434         if (ret != 0) {
435                 return ret;
436         }
437         offset += np;
438
439         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
440                                &out->client_packets_recv, &np);
441         if (ret != 0) {
442                 return ret;
443         }
444         offset += np;
445
446         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
447                                &out->node_packets_sent, &np);
448         if (ret != 0) {
449                 return ret;
450         }
451         offset += np;
452
453         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
454                                &out->node_packets_recv, &np);
455         if (ret != 0) {
456                 return ret;
457         }
458         offset += np;
459
460         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
461                                &out->keepalive_packets_sent, &np);
462         if (ret != 0) {
463                 return ret;
464         }
465         offset += np;
466
467         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
468                                &out->keepalive_packets_recv, &np);
469         if (ret != 0) {
470                 return ret;
471         }
472         offset += np;
473
474         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
475                                &out->node.req_call, &np);
476         if (ret != 0) {
477                 return ret;
478         }
479         offset += np;
480
481         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
482                                &out->node.reply_call, &np);
483         if (ret != 0) {
484                 return ret;
485         }
486         offset += np;
487
488         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
489                                &out->node.req_dmaster, &np);
490         if (ret != 0) {
491                 return ret;
492         }
493         offset += np;
494
495         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
496                                &out->node.reply_dmaster, &np);
497         if (ret != 0) {
498                 return ret;
499         }
500         offset += np;
501
502         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
503                                &out->node.reply_error, &np);
504         if (ret != 0) {
505                 return ret;
506         }
507         offset += np;
508
509         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
510                                &out->node.req_message, &np);
511         if (ret != 0) {
512                 return ret;
513         }
514         offset += np;
515
516         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
517                                &out->node.req_control, &np);
518         if (ret != 0) {
519                 return ret;
520         }
521         offset += np;
522
523         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
524                                &out->node.reply_control, &np);
525         if (ret != 0) {
526                 return ret;
527         }
528         offset += np;
529
530         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
531                                &out->client.req_call, &np);
532         if (ret != 0) {
533                 return ret;
534         }
535         offset += np;
536
537         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
538                                &out->client.req_message, &np);
539         if (ret != 0) {
540                 return ret;
541         }
542         offset += np;
543
544         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
545                                &out->client.req_control, &np);
546         if (ret != 0) {
547                 return ret;
548         }
549         offset += np;
550
551         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
552                                &out->timeouts.call, &np);
553         if (ret != 0) {
554                 return ret;
555         }
556         offset += np;
557
558         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
559                                &out->timeouts.control, &np);
560         if (ret != 0) {
561                 return ret;
562         }
563         offset += np;
564
565         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
566                                &out->timeouts.traverse, &np);
567         if (ret != 0) {
568                 return ret;
569         }
570         offset += np;
571
572         ret = ctdb_padding_pull(buf+offset, buflen-offset, 4, &np);
573         if (ret != 0) {
574                 return ret;
575         }
576         offset += np;
577
578         ret = ctdb_latency_counter_pull(buf+offset, buflen-offset,
579                                         &out->reclock.ctdbd, &np);
580         if (ret != 0) {
581                 return ret;
582         }
583         offset += np;
584
585         ret = ctdb_latency_counter_pull(buf+offset, buflen-offset,
586                                         &out->reclock.recd, &np);
587         if (ret != 0) {
588                 return ret;
589         }
590         offset += np;
591
592         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
593                                &out->locks.num_calls, &np);
594         if (ret != 0) {
595                 return ret;
596         }
597         offset += np;
598
599         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
600                                &out->locks.num_current, &np);
601         if (ret != 0) {
602                 return ret;
603         }
604         offset += np;
605
606         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
607                                &out->locks.num_pending, &np);
608         if (ret != 0) {
609                 return ret;
610         }
611         offset += np;
612
613         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
614                                &out->locks.num_failed, &np);
615         if (ret != 0) {
616                 return ret;
617         }
618         offset += np;
619
620         ret = ctdb_latency_counter_pull(buf+offset, buflen-offset,
621                                         &out->locks.latency, &np);
622         if (ret != 0) {
623                 return ret;
624         }
625         offset += np;
626
627         for (i=0;  i<MAX_COUNT_BUCKETS; i++) {
628                 ret = ctdb_uint32_pull(buf+offset, buflen-offset,
629                                        &out->locks.buckets[i], &np);
630                 if (ret != 0) {
631                         return ret;
632                 }
633                 offset += np;
634         }
635
636         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
637                                &out->total_calls, &np);
638         if (ret != 0) {
639                 return ret;
640         }
641         offset += np;
642
643         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
644                                &out->pending_calls, &np);
645         if (ret != 0) {
646                 return ret;
647         }
648         offset += np;
649
650         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
651                                &out->childwrite_calls, &np);
652         if (ret != 0) {
653                 return ret;
654         }
655         offset += np;
656
657         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
658                                &out->pending_childwrite_calls, &np);
659         if (ret != 0) {
660                 return ret;
661         }
662         offset += np;
663
664         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->memory_used,
665                                &np);
666         if (ret != 0) {
667                 return ret;
668         }
669         offset += np;
670
671         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
672                                &out->__last_counter, &np);
673         if (ret != 0) {
674                 return ret;
675         }
676         offset += np;
677
678         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
679                                &out->max_hop_count, &np);
680         if (ret != 0) {
681                 return ret;
682         }
683         offset += np;
684
685         for (i=0;  i<MAX_COUNT_BUCKETS; i++) {
686                 ret = ctdb_uint32_pull(buf+offset, buflen-offset,
687                                        &out->hop_count_bucket[i], &np);
688                 if (ret != 0) {
689                         return ret;
690                 }
691                 offset += np;
692         }
693
694         ret = ctdb_padding_pull(buf+offset, buflen-offset, 4, &np);
695         if (ret != 0) {
696                 return ret;
697         }
698         offset += np;
699
700         ret = ctdb_latency_counter_pull(buf+offset, buflen-offset,
701                                         &out->call_latency, &np);
702         if (ret != 0) {
703                 return ret;
704         }
705         offset += np;
706
707         ret = ctdb_latency_counter_pull(buf+offset, buflen-offset,
708                                         &out->childwrite_latency, &np);
709         if (ret != 0) {
710                 return ret;
711         }
712         offset += np;
713
714         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
715                                &out->num_recoveries, &np);
716         if (ret != 0) {
717                 return ret;
718         }
719         offset += np;
720
721         ret = ctdb_padding_pull(buf+offset, buflen-offset, 4, &np);
722         if (ret != 0) {
723                 return ret;
724         }
725         offset += np;
726
727         ret = ctdb_timeval_pull(buf+offset, buflen-offset,
728                                 &out->statistics_start_time, &np);
729         if (ret != 0) {
730                 return ret;
731         }
732         offset += np;
733
734         ret = ctdb_timeval_pull(buf+offset, buflen-offset,
735                                 &out->statistics_current_time, &np);
736         if (ret != 0) {
737                 return ret;
738         }
739         offset += np;
740
741         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
742                                &out->total_ro_delegations, &np);
743         if (ret != 0) {
744                 return ret;
745         }
746         offset += np;
747
748         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
749                                &out->total_ro_revokes, &np);
750         if (ret != 0) {
751                 return ret;
752         }
753         offset += np;
754
755         *npull = offset;
756         return 0;
757 }
758
759 int ctdb_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
760                          struct ctdb_statistics **out, size_t *npull)
761 {
762         struct ctdb_statistics *val;
763         size_t np;
764         int ret;
765
766         val = talloc(mem_ctx, struct ctdb_statistics);
767         if (val == NULL) {
768                 return ENOMEM;
769         }
770
771         ret = ctdb_statistics_pull_elems(buf, buflen, val, val, &np);
772         if (ret != 0) {
773                 talloc_free(val);
774                 return ret;
775         }
776
777         *out = val;
778         *npull = np;
779         return 0;
780 }
781
782 struct ctdb_statistics_list_wire {
783         uint32_t num;
784         struct ctdb_statistics stats[1];
785 };
786
787 size_t ctdb_statistics_list_len(struct ctdb_statistics_list *stats_list)
788 {
789         return offsetof(struct ctdb_statistics_list_wire, stats) +
790                stats_list->num * sizeof(struct ctdb_statistics);
791 }
792
793 void ctdb_statistics_list_push(struct ctdb_statistics_list *stats_list,
794                                uint8_t *buf)
795 {
796         struct ctdb_statistics_list_wire *wire =
797                 (struct ctdb_statistics_list_wire *)buf;
798
799         wire->num = stats_list->num;
800         memcpy(wire->stats, stats_list->stats,
801                stats_list->num * sizeof(struct ctdb_statistics));
802 }
803
804 int ctdb_statistics_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
805                               struct ctdb_statistics_list **out)
806 {
807         struct ctdb_statistics_list *stats_list;
808         struct ctdb_statistics_list_wire *wire =
809                 (struct ctdb_statistics_list_wire *)buf;
810
811         if (buflen < offsetof(struct ctdb_statistics_list_wire, stats)) {
812                 return EMSGSIZE;
813         }
814         if (wire->num > buflen / sizeof(struct ctdb_statistics)) {
815                 return EMSGSIZE;
816         }
817         if (offsetof(struct ctdb_statistics_list_wire, stats) +
818             wire->num * sizeof(struct ctdb_statistics) <
819             offsetof(struct ctdb_statistics_list_wire, stats)) {
820                 return EMSGSIZE;
821         }
822         if (buflen < offsetof(struct ctdb_statistics_list_wire, stats) +
823                      wire->num * sizeof(struct ctdb_statistics)) {
824                 return EMSGSIZE;
825         }
826
827         stats_list = talloc(mem_ctx, struct ctdb_statistics_list);
828         if (stats_list == NULL) {
829                 return ENOMEM;
830         }
831
832         stats_list->num = wire->num;
833
834         stats_list->stats = talloc_array(stats_list, struct ctdb_statistics,
835                                          wire->num);
836         if (stats_list->stats == NULL) {
837                 talloc_free(stats_list);
838                 return ENOMEM;
839         }
840
841         memcpy(stats_list->stats, wire->stats,
842                wire->num * sizeof(struct ctdb_statistics));
843
844         *out = stats_list;
845         return 0;
846 }
847
848 size_t ctdb_vnn_map_len(struct ctdb_vnn_map *in)
849 {
850         size_t len;
851
852         len = ctdb_uint32_len(&in->generation) + ctdb_uint32_len(&in->size);
853         if (in->size > 0) {
854                 len += in->size * ctdb_uint32_len(&in->map[0]);
855         }
856
857         return len;
858 }
859
860 void ctdb_vnn_map_push(struct ctdb_vnn_map *in, uint8_t *buf, size_t *npush)
861 {
862         size_t offset = 0, np;
863         uint32_t i;
864
865         ctdb_uint32_push(&in->generation, buf+offset, &np);
866         offset += np;
867
868         ctdb_uint32_push(&in->size, buf+offset, &np);
869         offset += np;
870
871         for (i=0; i<in->size; i++) {
872                 ctdb_uint32_push(&in->map[i], buf+offset, &np);
873                 offset += np;
874         }
875
876         *npush = offset;
877 }
878
879 int ctdb_vnn_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
880                       struct ctdb_vnn_map **out, size_t *npull)
881 {
882         struct ctdb_vnn_map *val;
883         size_t offset = 0, np;
884         uint32_t i;
885         int ret;
886
887         val = talloc(mem_ctx, struct ctdb_vnn_map);
888         if (val == NULL) {
889                 return ENOMEM;
890         }
891
892         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->generation,
893                                &np);
894         if (ret != 0) {
895                 goto fail;
896         }
897         offset += np;
898
899         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->size, &np);
900         if (ret != 0) {
901                 goto fail;
902         }
903         offset += np;
904
905         if (val->size == 0) {
906                 val->map = NULL;
907                 goto done;
908         }
909
910         val->map = talloc_array(val, uint32_t, val->size);
911         if (val->map == NULL) {
912                 ret = ENOMEM;
913                 goto fail;
914         }
915
916         for (i=0; i<val->size; i++) {
917                 ret = ctdb_uint32_pull(buf+offset, buflen-offset,
918                                        &val->map[i], &np);
919                 if (ret != 0) {
920                         goto fail;
921                 }
922                 offset += np;
923         }
924
925 done:
926         *out = val;
927         *npull = offset;
928         return 0;
929
930 fail:
931         talloc_free(val);
932         return ret;
933 }
934
935 size_t ctdb_dbid_len(struct ctdb_dbid *in)
936 {
937         return ctdb_uint32_len(&in->db_id) +
938                 ctdb_uint8_len(&in->flags) +
939                 ctdb_padding_len(3);
940 }
941
942 void ctdb_dbid_push(struct ctdb_dbid *in, uint8_t *buf, size_t *npush)
943 {
944         size_t offset = 0, np;
945
946         ctdb_uint32_push(&in->db_id, buf+offset, &np);
947         offset += np;
948
949         ctdb_uint8_push(&in->flags, buf+offset, &np);
950         offset += np;
951
952         ctdb_padding_push(3, buf+offset, &np);
953         offset += np;
954
955         *npush = offset;
956 }
957
958 static int ctdb_dbid_pull_elems(uint8_t *buf, size_t buflen,
959                                 TALLOC_CTX *mem_ctx, struct ctdb_dbid *out,
960                                 size_t *npull)
961 {
962         size_t offset = 0, np;
963         int ret;
964
965         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->db_id, &np);
966         if (ret != 0) {
967                 return ret;
968         }
969         offset += np;
970
971         ret = ctdb_uint8_pull(buf+offset, buflen-offset, &out->flags, &np);
972         if (ret != 0) {
973                 return ret;
974         }
975         offset += np;
976
977         ret = ctdb_padding_pull(buf+offset, buflen-offset, 3, &np);
978         if (ret != 0) {
979                 return ret;
980         }
981         offset += np;
982
983         *npull = offset;
984         return 0;
985 }
986
987 int ctdb_dbid_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
988                    struct ctdb_dbid **out, size_t *npull)
989 {
990         struct ctdb_dbid *val;
991         size_t np;
992         int ret;
993
994         val = talloc(mem_ctx, struct ctdb_dbid);
995         if (val == NULL) {
996                 return ENOMEM;
997         }
998
999         ret = ctdb_dbid_pull_elems(buf, buflen, val, val, &np);
1000         if (ret != 0) {
1001                 talloc_free(val);
1002                 return ret;
1003         }
1004
1005         *out = val;
1006         *npull = np;
1007         return 0;
1008 }
1009
1010 size_t ctdb_dbid_map_len(struct ctdb_dbid_map *in)
1011 {
1012         size_t len;
1013
1014         len = ctdb_uint32_len(&in->num);
1015         if (in->num > 0) {
1016                 len += in->num * ctdb_dbid_len(&in->dbs[0]);
1017         }
1018
1019         return len;
1020 }
1021
1022 void ctdb_dbid_map_push(struct ctdb_dbid_map *in, uint8_t *buf, size_t *npush)
1023 {
1024         size_t offset = 0, np;
1025         uint32_t i;
1026
1027         ctdb_uint32_push(&in->num, buf+offset, &np);
1028         offset += np;
1029
1030         for (i=0; i<in->num; i++) {
1031                 ctdb_dbid_push(&in->dbs[i], buf+offset, &np);
1032                 offset += np;
1033         }
1034
1035         *npush = offset;
1036 }
1037
1038 int ctdb_dbid_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1039                        struct ctdb_dbid_map **out, size_t *npull)
1040 {
1041         struct ctdb_dbid_map *val;
1042         size_t offset = 0, np;
1043         uint32_t i;
1044         int ret;
1045
1046         val = talloc(mem_ctx, struct ctdb_dbid_map);
1047         if (val == NULL) {
1048                 return ENOMEM;
1049         }
1050
1051         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->num, &np);
1052         if (ret != 0) {
1053                 goto fail;
1054         }
1055         offset += np;
1056
1057         if (val->num == 0) {
1058                 val->dbs = NULL;
1059                 goto done;
1060         }
1061
1062         val->dbs = talloc_array(val, struct ctdb_dbid, val->num);
1063         if (val->dbs == NULL) {
1064                 ret = ENOMEM;
1065                 goto fail;
1066         }
1067
1068         for (i=0; i<val->num; i++) {
1069                 ret = ctdb_dbid_pull_elems(buf+offset, buflen-offset, val,
1070                                            &val->dbs[i], &np);
1071                 if (ret != 0) {
1072                         goto fail;
1073                 }
1074                 offset += np;
1075         }
1076
1077 done:
1078         *out = val;
1079         *npull = offset;
1080         return 0;
1081
1082 fail:
1083         talloc_free(val);
1084         return ret;
1085 }
1086
1087 size_t ctdb_pulldb_len(struct ctdb_pulldb *in)
1088 {
1089         return ctdb_uint32_len(&in->db_id) +
1090                 ctdb_uint32_len(&in->lmaster);
1091 }
1092
1093 void ctdb_pulldb_push(struct ctdb_pulldb *in, uint8_t *buf, size_t *npush)
1094 {
1095         size_t offset = 0, np;
1096
1097         ctdb_uint32_push(&in->db_id, buf+offset, &np);
1098         offset += np;
1099
1100         ctdb_uint32_push(&in->lmaster, buf+offset, &np);
1101         offset += np;
1102
1103         *npush = offset;
1104 }
1105
1106 int ctdb_pulldb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1107                      struct ctdb_pulldb **out, size_t *npull)
1108 {
1109         struct ctdb_pulldb *val;
1110         size_t offset = 0, np;
1111         int ret;
1112
1113         val = talloc(mem_ctx, struct ctdb_pulldb);
1114         if (val == NULL) {
1115                 return ENOMEM;
1116         }
1117
1118         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
1119         if (ret != 0) {
1120                 talloc_free(val);
1121                 return ret;
1122         }
1123         offset += np;
1124
1125         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->lmaster, &np);
1126         if (ret != 0) {
1127                 talloc_free(val);
1128                 return ret;
1129         }
1130         offset += np;
1131
1132         *out = val;
1133         *npull = offset;
1134         return 0;
1135 }
1136
1137 size_t ctdb_pulldb_ext_len(struct ctdb_pulldb_ext *in)
1138 {
1139         return ctdb_uint32_len(&in->db_id) +
1140                 ctdb_uint32_len(&in->lmaster) +
1141                 ctdb_uint64_len(&in->srvid);
1142 }
1143
1144 void ctdb_pulldb_ext_push(struct ctdb_pulldb_ext *in, uint8_t *buf,
1145                           size_t *npush)
1146 {
1147         size_t offset = 0, np;
1148
1149         ctdb_uint32_push(&in->db_id, buf+offset, &np);
1150         offset += np;
1151
1152         ctdb_uint32_push(&in->lmaster, buf+offset, &np);
1153         offset += np;
1154
1155         ctdb_uint64_push(&in->srvid, buf+offset, &np);
1156         offset += np;
1157
1158         *npush = offset;
1159 }
1160
1161 int ctdb_pulldb_ext_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1162                          struct ctdb_pulldb_ext **out, size_t *npull)
1163 {
1164         struct ctdb_pulldb_ext *val;
1165         size_t offset = 0, np;
1166         int ret;
1167
1168         val = talloc(mem_ctx, struct ctdb_pulldb_ext);
1169         if (val == NULL) {
1170                 return ENOMEM;
1171         }
1172
1173         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
1174         if (ret != 0) {
1175                 goto fail;
1176         }
1177         offset += np;
1178
1179         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->lmaster, &np);
1180         if (ret != 0) {
1181                 goto fail;
1182         }
1183         offset += np;
1184
1185         ret = ctdb_uint64_pull(buf+offset, buflen-offset, &val->srvid, &np);
1186         if (ret != 0) {
1187                 goto fail;
1188         }
1189         offset += np;
1190
1191         *out = val;
1192         *npull = offset;
1193         return 0;
1194
1195 fail:
1196         talloc_free(val);
1197         return ret;
1198 }
1199
1200 size_t ctdb_ltdb_header_len(struct ctdb_ltdb_header *in)
1201 {
1202         return ctdb_uint64_len(&in->rsn) +
1203                 ctdb_uint32_len(&in->dmaster) +
1204                 ctdb_uint32_len(&in->reserved1) +
1205                 ctdb_uint32_len(&in->flags) +
1206                 ctdb_padding_len(4);
1207 }
1208
1209 void ctdb_ltdb_header_push(struct ctdb_ltdb_header *in, uint8_t *buf,
1210                            size_t *npush)
1211 {
1212         size_t offset = 0, np;
1213
1214         ctdb_uint64_push(&in->rsn, buf+offset, &np);
1215         offset += np;
1216
1217         ctdb_uint32_push(&in->dmaster, buf+offset, &np);
1218         offset += np;
1219
1220         ctdb_uint32_push(&in->reserved1, buf+offset, &np);
1221         offset += np;
1222
1223         ctdb_uint32_push(&in->flags, buf+offset, &np);
1224         offset += np;
1225
1226         ctdb_padding_push(4, buf+offset, &np);
1227         offset += np;
1228
1229         *npush = offset;
1230 }
1231
1232 int ctdb_ltdb_header_pull(uint8_t *buf, size_t buflen,
1233                           struct ctdb_ltdb_header *out, size_t *npull)
1234 {
1235         size_t offset = 0, np;
1236         int ret;
1237
1238         ret = ctdb_uint64_pull(buf+offset, buflen-offset, &out->rsn, &np);
1239         if (ret != 0) {
1240                 return ret;
1241         }
1242         offset += np;
1243
1244         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->dmaster, &np);
1245         if (ret != 0) {
1246                 return ret;
1247         }
1248         offset += np;
1249
1250         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->reserved1,
1251                                &np);
1252         if (ret != 0) {
1253                 return ret;
1254         }
1255         offset += np;
1256
1257         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &out->flags, &np);
1258         if (ret != 0) {
1259                 return ret;
1260         }
1261         offset += np;
1262
1263         ret = ctdb_padding_pull(buf+offset, buflen-offset, 4, &np);
1264         if (ret != 0) {
1265                 return ret;
1266         }
1267         offset += np;
1268
1269         *npull = offset;
1270         return 0;
1271 }
1272
1273 int ctdb_ltdb_header_extract(TDB_DATA *data, struct ctdb_ltdb_header *header)
1274 {
1275         size_t np;
1276         int ret;
1277
1278         ret = ctdb_ltdb_header_pull(data->dptr, data->dsize, header, &np);
1279         if (ret != 0) {
1280                 return ret;
1281         }
1282
1283         data->dptr += np;
1284         data->dsize -= np;
1285
1286         return 0;
1287 }
1288
1289 size_t ctdb_rec_data_len(struct ctdb_rec_data *in)
1290 {
1291         uint32_t u32;
1292
1293         u32 = ctdb_uint32_len(&in->reqid) +
1294                 ctdb_tdb_datan_len(&in->key) +
1295                 ctdb_tdb_datan_len(&in->data);
1296
1297         if (in->header != NULL) {
1298                 u32 += ctdb_ltdb_header_len(in->header);
1299         }
1300
1301         return ctdb_uint32_len(&u32) + u32;
1302 }
1303
1304 void ctdb_rec_data_push(struct ctdb_rec_data *in, uint8_t *buf, size_t *npush)
1305 {
1306         size_t offset = 0, np;
1307         uint32_t u32;
1308
1309         u32 = ctdb_rec_data_len(in);
1310         ctdb_uint32_push(&u32, buf+offset, &np);
1311         offset += np;
1312
1313         ctdb_uint32_push(&in->reqid, buf+offset, &np);
1314         offset += np;
1315
1316         u32 = ctdb_tdb_data_len(&in->key);
1317         ctdb_uint32_push(&u32, buf+offset, &np);
1318         offset += np;
1319
1320         u32 = ctdb_tdb_data_len(&in->data);
1321         if (in->header != NULL) {
1322                 u32 += ctdb_ltdb_header_len(in->header);
1323         }
1324
1325         ctdb_uint32_push(&u32, buf+offset, &np);
1326         offset += np;
1327
1328         ctdb_tdb_data_push(&in->key, buf+offset, &np);
1329         offset += np;
1330
1331         /* If ltdb header is not NULL, then it is pushed as part of the data */
1332         if (in->header != NULL) {
1333                 ctdb_ltdb_header_push(in->header, buf+offset, &np);
1334                 offset += np;
1335         }
1336         ctdb_tdb_data_push(&in->data, buf+offset, &np);
1337         offset += np;
1338
1339         *npush = offset;
1340 }
1341
1342 static int ctdb_rec_data_pull_data(uint8_t *buf, size_t buflen,
1343                                    uint32_t *reqid,
1344                                    TDB_DATA *key, TDB_DATA *data,
1345                                    size_t *npull)
1346 {
1347         size_t offset = 0, np;
1348         size_t len;
1349         uint32_t u32;
1350         int ret;
1351
1352         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &u32, &np);
1353         if (ret != 0) {
1354                 return ret;
1355         }
1356         offset += np;
1357
1358         if (buflen < u32) {
1359                 return EMSGSIZE;
1360         }
1361         len = u32;
1362
1363         ret = ctdb_uint32_pull(buf+offset, len-offset, reqid, &np);
1364         if (ret != 0) {
1365                 return ret;
1366         }
1367         offset += np;
1368
1369         ret = ctdb_uint32_pull(buf+offset, len-offset, &u32, &np);
1370         if (ret != 0) {
1371                 return ret;
1372         }
1373         offset += np;
1374         key->dsize = u32;
1375
1376         ret = ctdb_uint32_pull(buf+offset, len-offset, &u32, &np);
1377         if (ret != 0) {
1378                 return ret;
1379         }
1380         offset += np;
1381         data->dsize = u32;
1382
1383         if (len-offset < key->dsize) {
1384                 return EMSGSIZE;
1385         }
1386
1387         key->dptr = buf+offset;
1388         offset += key->dsize;
1389
1390         if (len-offset < data->dsize) {
1391                 return EMSGSIZE;
1392         }
1393
1394         data->dptr = buf+offset;
1395         offset += data->dsize;
1396
1397         *npull = offset;
1398         return 0;
1399 }
1400
1401 static int ctdb_rec_data_pull_elems(uint8_t *buf, size_t buflen,
1402                                     TALLOC_CTX *mem_ctx,
1403                                     struct ctdb_rec_data *out,
1404                                     size_t *npull)
1405 {
1406         uint32_t reqid;
1407         TDB_DATA key, data;
1408         size_t np;
1409         int ret;
1410
1411         ret = ctdb_rec_data_pull_data(buf, buflen, &reqid, &key, &data, &np);
1412         if (ret != 0) {
1413                 return ret;
1414         }
1415
1416         out->reqid = reqid;
1417
1418         /* Always set header to NULL.  If it is required, extract it using
1419          * ctdb_rec_data_extract_header()
1420          */
1421         out->header = NULL;
1422
1423         out->key.dsize = key.dsize;
1424         if (key.dsize > 0) {
1425                 out->key.dptr = talloc_memdup(mem_ctx, key.dptr, key.dsize);
1426                 if (out->key.dptr == NULL) {
1427                         return ENOMEM;
1428                 }
1429         }
1430
1431         out->data.dsize = data.dsize;
1432         if (data.dsize > 0) {
1433                 out->data.dptr = talloc_memdup(mem_ctx, data.dptr, data.dsize);
1434                 if (out->data.dptr == NULL) {
1435                         return ENOMEM;
1436                 }
1437         }
1438
1439         *npull = np;
1440         return 0;
1441 }
1442
1443 int ctdb_rec_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1444                        struct ctdb_rec_data **out, size_t *npull)
1445 {
1446         struct ctdb_rec_data *val;
1447         size_t np;
1448         int ret;
1449
1450         val = talloc(mem_ctx, struct ctdb_rec_data);
1451         if (val == NULL) {
1452                 return ENOMEM;
1453         }
1454
1455         ret = ctdb_rec_data_pull_elems(buf, buflen, val, val, &np);
1456         if (ret != 0) {
1457                 TALLOC_FREE(val);
1458                 return ret;
1459         }
1460
1461         *out = val;
1462         *npull = np;
1463         return ret;
1464 }
1465
1466 size_t ctdb_rec_buffer_len(struct ctdb_rec_buffer *in)
1467 {
1468         return ctdb_uint32_len(&in->db_id) +
1469                 ctdb_uint32_len(&in->count) +
1470                 in->buflen;
1471 }
1472
1473 void ctdb_rec_buffer_push(struct ctdb_rec_buffer *in, uint8_t *buf,
1474                           size_t *npush)
1475 {
1476         size_t offset = 0, np;
1477
1478         ctdb_uint32_push(&in->db_id, buf+offset, &np);
1479         offset += np;
1480
1481         ctdb_uint32_push(&in->count, buf+offset, &np);
1482         offset += np;
1483
1484         memcpy(buf+offset, in->buf, in->buflen);
1485         offset += in->buflen;
1486
1487         *npush = offset;
1488 }
1489
1490 int ctdb_rec_buffer_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1491                          struct ctdb_rec_buffer **out, size_t *npull)
1492 {
1493         struct ctdb_rec_buffer *val;
1494         size_t offset = 0, np;
1495         size_t length;
1496         int ret;
1497
1498         val = talloc(mem_ctx, struct ctdb_rec_buffer);
1499         if (val == NULL) {
1500                 return ENOMEM;
1501         }
1502
1503         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
1504         if (ret != 0) {
1505                 goto fail;
1506         }
1507         offset += np;
1508
1509         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->count, &np);
1510         if (ret != 0) {
1511                 goto fail;
1512         }
1513         offset += np;
1514
1515         /* Since there is no buflen provided, walk the records to
1516          * validate the length of the buffer.
1517          */
1518         val->buf = buf+offset;
1519         val->buflen = buflen-offset;
1520
1521         length = 0;
1522         ret = ctdb_rec_buffer_traverse(val, NULL, &length);
1523         if (ret != 0) {
1524                 goto fail;
1525         }
1526
1527         if (length > buflen-offset) {
1528                 ret = EMSGSIZE;
1529                 goto fail;
1530         }
1531
1532         val->buf = talloc_memdup(val, buf+offset, length);
1533         if (val->buf == NULL) {
1534                 ret = ENOMEM;
1535                 goto fail;
1536         }
1537         val->buflen = length;
1538         offset += length;
1539
1540         *out = val;
1541         *npull = offset;
1542         return 0;
1543
1544 fail:
1545         talloc_free(val);
1546         return ret;
1547 }
1548
1549 struct ctdb_rec_buffer *ctdb_rec_buffer_init(TALLOC_CTX *mem_ctx,
1550                                              uint32_t db_id)
1551 {
1552         struct ctdb_rec_buffer *recbuf;
1553
1554         recbuf = talloc_zero(mem_ctx, struct ctdb_rec_buffer);
1555         if (recbuf == NULL) {
1556                 return recbuf;
1557         }
1558
1559         recbuf->db_id = db_id;
1560
1561         return recbuf;
1562 }
1563
1564 int ctdb_rec_buffer_add(TALLOC_CTX *mem_ctx, struct ctdb_rec_buffer *recbuf,
1565                         uint32_t reqid, struct ctdb_ltdb_header *header,
1566                         TDB_DATA key, TDB_DATA data)
1567 {
1568         struct ctdb_rec_data recdata;
1569         size_t len, np;
1570         uint8_t *ptr;
1571
1572         recdata.reqid = reqid;
1573         recdata.header = header;
1574         recdata.key = key;
1575         recdata.data = data;
1576
1577         len = ctdb_rec_data_len(&recdata);
1578
1579         ptr = talloc_realloc(mem_ctx, recbuf->buf, uint8_t,
1580                              recbuf->buflen + len);
1581         if (ptr == NULL) {
1582                 return ENOMEM;
1583         }
1584
1585         ctdb_rec_data_push(&recdata, &ptr[recbuf->buflen], &np);
1586
1587         recbuf->count++;
1588         recbuf->buf = ptr;
1589         recbuf->buflen += np;
1590         return 0;
1591 }
1592
1593 int ctdb_rec_buffer_traverse(struct ctdb_rec_buffer *recbuf,
1594                              ctdb_rec_parser_func_t func,
1595                              void *private_data)
1596 {
1597         TDB_DATA key, data;
1598         uint32_t reqid;
1599         size_t offset, reclen;
1600         int ret = 0, i;
1601
1602         offset = 0;
1603         for (i=0; i<recbuf->count; i++) {
1604                 ret = ctdb_rec_data_pull_data(&recbuf->buf[offset],
1605                                               recbuf->buflen - offset,
1606                                               &reqid, &key, &data, &reclen);
1607                 if (ret != 0) {
1608                         return ret;
1609                 }
1610
1611                 if (func != NULL) {
1612                         ret = func(reqid, NULL, key, data, private_data);
1613                         if (ret != 0) {
1614                                 break;
1615                         }
1616                 }
1617
1618                 offset += reclen;
1619         }
1620
1621         if (ret != 0) {
1622                 return ret;
1623         }
1624
1625         if (func == NULL) {
1626                 size_t *length = (size_t *)private_data;
1627
1628                 *length = offset;
1629         }
1630
1631         return 0;
1632 }
1633
1634 int ctdb_rec_buffer_write(struct ctdb_rec_buffer *recbuf, int fd)
1635 {
1636         ssize_t n;
1637
1638         n = write(fd, &recbuf->db_id, sizeof(uint32_t));
1639         if (n == -1 || n != sizeof(uint32_t)) {
1640                 return (errno != 0 ? errno : EIO);
1641         }
1642         n = write(fd, &recbuf->count, sizeof(uint32_t));
1643         if (n == -1 || n != sizeof(uint32_t)) {
1644                 return (errno != 0 ? errno : EIO);
1645         }
1646         n = write(fd, &recbuf->buflen, sizeof(size_t));
1647         if (n == -1 || n != sizeof(size_t)) {
1648                 return (errno != 0 ? errno : EIO);
1649         }
1650         n = write(fd, recbuf->buf, recbuf->buflen);
1651         if (n == -1 || n != recbuf->buflen) {
1652                 return (errno != 0 ? errno : EIO);
1653         }
1654
1655         return 0;
1656 }
1657
1658 int ctdb_rec_buffer_read(int fd, TALLOC_CTX *mem_ctx,
1659                          struct ctdb_rec_buffer **out)
1660 {
1661         struct ctdb_rec_buffer *recbuf;
1662         ssize_t n;
1663
1664         recbuf = talloc(mem_ctx, struct ctdb_rec_buffer);
1665         if (recbuf == NULL) {
1666                 return ENOMEM;
1667         }
1668
1669         n = read(fd, &recbuf->db_id, sizeof(uint32_t));
1670         if (n == -1 || n != sizeof(uint32_t)) {
1671                 return (errno != 0 ? errno : EIO);
1672         }
1673         n = read(fd, &recbuf->count, sizeof(uint32_t));
1674         if (n == -1 || n != sizeof(uint32_t)) {
1675                 return (errno != 0 ? errno : EIO);
1676         }
1677         n = read(fd, &recbuf->buflen, sizeof(size_t));
1678         if (n == -1 || n != sizeof(size_t)) {
1679                 return (errno != 0 ? errno : EIO);
1680         }
1681
1682         recbuf->buf = talloc_size(recbuf, recbuf->buflen);
1683         if (recbuf->buf == NULL) {
1684                 return ENOMEM;
1685         }
1686
1687         n = read(fd, recbuf->buf, recbuf->buflen);
1688         if (n == -1 || n != recbuf->buflen) {
1689                 return (errno != 0 ? errno : EIO);
1690         }
1691
1692         *out = recbuf;
1693         return 0;
1694 }
1695
1696 size_t ctdb_traverse_start_len(struct ctdb_traverse_start *in)
1697 {
1698         return ctdb_uint32_len(&in->db_id) +
1699                 ctdb_uint32_len(&in->reqid) +
1700                 ctdb_uint64_len(&in->srvid);
1701 }
1702
1703 void ctdb_traverse_start_push(struct ctdb_traverse_start *in, uint8_t *buf,
1704                               size_t *npush)
1705 {
1706         size_t offset = 0, np;
1707
1708         ctdb_uint32_push(&in->db_id, buf+offset, &np);
1709         offset += np;
1710
1711         ctdb_uint32_push(&in->reqid, buf+offset, &np);
1712         offset += np;
1713
1714         ctdb_uint64_push(&in->srvid, buf+offset, &np);
1715         offset += np;
1716
1717         *npush = offset;
1718 }
1719
1720 int ctdb_traverse_start_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1721                              struct ctdb_traverse_start **out, size_t *npull)
1722 {
1723         struct ctdb_traverse_start *val;
1724         size_t offset = 0, np;
1725         int ret;
1726
1727         val = talloc(mem_ctx, struct ctdb_traverse_start);
1728         if (val == NULL) {
1729                 return ENOMEM;
1730         }
1731
1732         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
1733         if (ret != 0) {
1734                 goto fail;
1735         }
1736         offset += np;
1737
1738         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->reqid, &np);
1739         if (ret != 0) {
1740                 goto fail;
1741         }
1742         offset += np;
1743
1744         ret = ctdb_uint64_pull(buf+offset, buflen-offset, &val->srvid, &np);
1745         if (ret != 0) {
1746                 goto fail;
1747         }
1748         offset += np;
1749
1750         *out = val;
1751         *npull = offset;
1752         return 0;
1753
1754 fail:
1755         talloc_free(val);
1756         return ret;
1757 }
1758
1759 size_t ctdb_traverse_all_len(struct ctdb_traverse_all *in)
1760 {
1761         return ctdb_uint32_len(&in->db_id) +
1762                 ctdb_uint32_len(&in->reqid) +
1763                 ctdb_uint32_len(&in->pnn) +
1764                 ctdb_uint32_len(&in->client_reqid) +
1765                 ctdb_uint64_len(&in->srvid);
1766 }
1767
1768 void ctdb_traverse_all_push(struct ctdb_traverse_all *in, uint8_t *buf,
1769                             size_t *npush)
1770 {
1771         size_t offset = 0, np;
1772
1773         ctdb_uint32_push(&in->db_id, buf+offset, &np);
1774         offset += np;
1775
1776         ctdb_uint32_push(&in->reqid, buf+offset, &np);
1777         offset += np;
1778
1779         ctdb_uint32_push(&in->pnn, buf+offset, &np);
1780         offset += np;
1781
1782         ctdb_uint32_push(&in->client_reqid, buf+offset, &np);
1783         offset += np;
1784
1785         ctdb_uint64_push(&in->srvid, buf+offset, &np);
1786         offset += np;
1787
1788         *npush = offset;
1789 }
1790
1791 int ctdb_traverse_all_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
1792                            struct ctdb_traverse_all **out, size_t *npull)
1793 {
1794         struct ctdb_traverse_all *val;
1795         size_t offset = 0, np;
1796         int ret;
1797
1798         val = talloc(mem_ctx, struct ctdb_traverse_all);
1799         if (val == NULL) {
1800                 return ENOMEM;
1801         }
1802
1803         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
1804         if (ret != 0) {
1805                 goto fail;
1806         }
1807         offset += np;
1808
1809         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->reqid, &np);
1810         if (ret != 0) {
1811                 goto fail;
1812         }
1813         offset += np;
1814
1815         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->pnn, &np);
1816         if (ret != 0) {
1817                 goto fail;
1818         }
1819         offset += np;
1820
1821         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->client_reqid,
1822                                &np);
1823         if (ret != 0) {
1824                 goto fail;
1825         }
1826         offset += np;
1827
1828         ret = ctdb_uint64_pull(buf+offset, buflen-offset, &val->srvid, &np);
1829         if (ret != 0) {
1830                 goto fail;
1831         }
1832         offset += np;
1833
1834         *out = val;
1835         *npull = offset;
1836         return 0;
1837
1838 fail:
1839         talloc_free(val);
1840         return ret;
1841 }
1842
1843 size_t ctdb_traverse_start_ext_len(struct ctdb_traverse_start_ext *in)
1844 {
1845         return ctdb_uint32_len(&in->db_id) +
1846                 ctdb_uint32_len(&in->reqid) +
1847                 ctdb_uint64_len(&in->srvid) +
1848                 ctdb_bool_len(&in->withemptyrecords) +
1849                 ctdb_padding_len(7);
1850 }
1851
1852 void ctdb_traverse_start_ext_push(struct ctdb_traverse_start_ext *in,
1853                                   uint8_t *buf, size_t *npush)
1854 {
1855         size_t offset = 0, np;
1856
1857         ctdb_uint32_push(&in->db_id, buf+offset, &np);
1858         offset += np;
1859
1860         ctdb_uint32_push(&in->reqid, buf+offset, &np);
1861         offset += np;
1862
1863         ctdb_uint64_push(&in->srvid, buf+offset, &np);
1864         offset += np;
1865
1866         ctdb_bool_push(&in->withemptyrecords, buf+offset, &np);
1867         offset += np;
1868
1869         ctdb_padding_push(7, buf+offset, &np);
1870         offset += np;
1871
1872         *npush = offset;
1873 }
1874
1875 int ctdb_traverse_start_ext_pull(uint8_t *buf, size_t buflen,
1876                                  TALLOC_CTX *mem_ctx,
1877                                  struct ctdb_traverse_start_ext **out,
1878                                  size_t *npull)
1879 {
1880         struct ctdb_traverse_start_ext *val;
1881         size_t offset = 0, np;
1882         int ret;
1883
1884         val = talloc(mem_ctx, struct ctdb_traverse_start_ext);
1885         if (val == NULL) {
1886                 return ENOMEM;
1887         }
1888
1889         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
1890         if (ret != 0) {
1891                 goto fail;
1892         }
1893         offset += np;
1894
1895         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->reqid, &np);
1896         if (ret != 0) {
1897                 goto fail;
1898         }
1899         offset += np;
1900
1901         ret = ctdb_uint64_pull(buf+offset, buflen-offset, &val->srvid, &np);
1902         if (ret != 0) {
1903                 goto fail;
1904         }
1905         offset += np;
1906
1907         ret = ctdb_bool_pull(buf+offset, buflen-offset,
1908                              &val->withemptyrecords, &np);
1909         if (ret != 0) {
1910                 goto fail;
1911         }
1912         offset += np;
1913
1914         ret = ctdb_padding_pull(buf+offset, buflen-offset, 7, &np);
1915         if (ret != 0) {
1916                 goto fail;
1917         }
1918         offset += np;
1919
1920         *out = val;
1921         *npull = offset;
1922         return 0;
1923
1924 fail:
1925         talloc_free(val);
1926         return ret;
1927 }
1928
1929 size_t ctdb_traverse_all_ext_len(struct ctdb_traverse_all_ext *in)
1930 {
1931         return ctdb_uint32_len(&in->db_id) +
1932                 ctdb_uint32_len(&in->reqid) +
1933                 ctdb_uint32_len(&in->pnn) +
1934                 ctdb_uint32_len(&in->client_reqid) +
1935                 ctdb_uint64_len(&in->srvid) +
1936                 ctdb_bool_len(&in->withemptyrecords) +
1937                 ctdb_padding_len(7);
1938 }
1939
1940 void ctdb_traverse_all_ext_push(struct ctdb_traverse_all_ext *in,
1941                                 uint8_t *buf, size_t *npush)
1942 {
1943         size_t offset = 0, np;
1944
1945         ctdb_uint32_push(&in->db_id, buf+offset, &np);
1946         offset += np;
1947
1948         ctdb_uint32_push(&in->reqid, buf+offset, &np);
1949         offset += np;
1950
1951         ctdb_uint32_push(&in->pnn, buf+offset, &np);
1952         offset += np;
1953
1954         ctdb_uint32_push(&in->client_reqid, buf+offset, &np);
1955         offset += np;
1956
1957         ctdb_uint64_push(&in->srvid, buf+offset, &np);
1958         offset += np;
1959
1960         ctdb_bool_push(&in->withemptyrecords, buf+offset, &np);
1961         offset += np;
1962
1963         ctdb_padding_push(7, buf+offset, &np);
1964         offset += np;
1965
1966         *npush = offset;
1967 }
1968
1969 int ctdb_traverse_all_ext_pull(uint8_t *buf, size_t buflen,
1970                                TALLOC_CTX *mem_ctx,
1971                                struct ctdb_traverse_all_ext **out,
1972                                size_t *npull)
1973 {
1974         struct ctdb_traverse_all_ext *val;
1975         size_t offset = 0, np;
1976         int ret;
1977
1978         val = talloc(mem_ctx, struct ctdb_traverse_all_ext);
1979         if (val == NULL) {
1980                 return ENOMEM;
1981         }
1982
1983         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
1984         if (ret != 0) {
1985                 goto fail;
1986         }
1987         offset += np;
1988
1989         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->reqid, &np);
1990         if (ret != 0) {
1991                 goto fail;
1992         }
1993         offset += np;
1994
1995         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->pnn, &np);
1996         if (ret != 0) {
1997                 goto fail;
1998         }
1999         offset += np;
2000
2001         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->client_reqid,
2002                                &np);
2003         if (ret != 0) {
2004                 goto fail;
2005         }
2006         offset += np;
2007
2008         ret = ctdb_uint64_pull(buf+offset, buflen-offset, &val->srvid, &np);
2009         if (ret != 0) {
2010                 goto fail;
2011         }
2012         offset += np;
2013
2014         ret = ctdb_bool_pull(buf+offset, buflen-offset,
2015                              &val->withemptyrecords, &np);
2016         if (ret != 0) {
2017                 goto fail;
2018         }
2019         offset += np;
2020
2021         ret = ctdb_padding_pull(buf+offset, buflen-offset, 7, &np);
2022         if (ret != 0) {
2023                 goto fail;
2024         }
2025         offset += np;
2026
2027         *out = val;
2028         *npull = offset;
2029         return 0;
2030
2031 fail:
2032         talloc_free(val);
2033         return ret;
2034 }
2035
2036 size_t ctdb_sock_addr_len(ctdb_sock_addr *in)
2037 {
2038         return sizeof(ctdb_sock_addr);
2039 }
2040
2041 void ctdb_sock_addr_push(ctdb_sock_addr *in, uint8_t *buf, size_t *npush)
2042 {
2043         memcpy(buf, in, sizeof(ctdb_sock_addr));
2044         *npush = sizeof(ctdb_sock_addr);
2045 }
2046
2047 int ctdb_sock_addr_pull_elems(uint8_t *buf, size_t buflen,
2048                               TALLOC_CTX *mem_ctx, ctdb_sock_addr *out,
2049                               size_t *npull)
2050 {
2051         if (buflen < sizeof(ctdb_sock_addr)) {
2052                 return EMSGSIZE;
2053         }
2054
2055         memcpy(out, buf, sizeof(ctdb_sock_addr));
2056         *npull = sizeof(ctdb_sock_addr);
2057
2058         return 0;
2059 }
2060
2061 int ctdb_sock_addr_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2062                         ctdb_sock_addr **out, size_t *npull)
2063 {
2064         ctdb_sock_addr *val;
2065         size_t np;
2066         int ret;
2067
2068         val = talloc(mem_ctx, ctdb_sock_addr);
2069         if (val == NULL) {
2070                 return ENOMEM;
2071         }
2072
2073         ret = ctdb_sock_addr_pull_elems(buf, buflen, val, val, &np);
2074         if (ret != 0) {
2075                 talloc_free(val);
2076                 return ret;
2077         }
2078
2079         *out = val;
2080         *npull = np;
2081         return ret;
2082 }
2083
2084 size_t ctdb_connection_len(struct ctdb_connection *in)
2085 {
2086         return ctdb_sock_addr_len(&in->src) +
2087                 ctdb_sock_addr_len(&in->dst);
2088 }
2089
2090 void ctdb_connection_push(struct ctdb_connection *in, uint8_t *buf,
2091                           size_t *npush)
2092 {
2093         size_t offset = 0, np;
2094
2095         ctdb_sock_addr_push(&in->src, buf+offset, &np);
2096         offset += np;
2097
2098         ctdb_sock_addr_push(&in->dst, buf+offset, &np);
2099         offset += np;
2100
2101         *npush = offset;
2102 }
2103
2104 static int ctdb_connection_pull_elems(uint8_t *buf, size_t buflen,
2105                                       TALLOC_CTX *mem_ctx,
2106                                       struct ctdb_connection *out,
2107                                       size_t *npull)
2108 {
2109         size_t offset = 0, np;
2110         int ret;
2111
2112         ret = ctdb_sock_addr_pull_elems(buf+offset, buflen-offset,
2113                                         mem_ctx, &out->src, &np);
2114         if (ret != 0) {
2115                 return ret;
2116         }
2117         offset += np;
2118
2119         ret = ctdb_sock_addr_pull_elems(buf+offset, buflen-offset,
2120                                         mem_ctx, &out->dst, &np);
2121         if (ret != 0) {
2122                 return ret;
2123         }
2124         offset += np;
2125
2126         *npull = offset;
2127         return 0;
2128 }
2129
2130 int ctdb_connection_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2131                          struct ctdb_connection **out, size_t *npull)
2132 {
2133         struct ctdb_connection *val;
2134         size_t np;
2135         int ret;
2136
2137         val = talloc(mem_ctx, struct ctdb_connection);
2138         if (val == NULL) {
2139                 return ENOMEM;
2140         }
2141
2142         ret = ctdb_connection_pull_elems(buf, buflen, val, val, &np);
2143         if (ret != 0) {
2144                 talloc_free(val);
2145                 return ret;
2146         }
2147
2148         *out = val;
2149         *npull = np;
2150         return ret;
2151 }
2152
2153 size_t ctdb_tunable_len(struct ctdb_tunable *in)
2154 {
2155         return ctdb_uint32_len(&in->value) +
2156                 ctdb_stringn_len(&in->name);
2157 }
2158
2159 void ctdb_tunable_push(struct ctdb_tunable *in, uint8_t *buf, size_t *npush)
2160 {
2161         size_t offset = 0, np;
2162
2163         ctdb_uint32_push(&in->value, buf+offset, &np);
2164         offset += np;
2165
2166         ctdb_stringn_push(&in->name, buf+offset, &np);
2167         offset += np;
2168
2169         *npush = offset;
2170 }
2171
2172 int ctdb_tunable_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2173                       struct ctdb_tunable **out, size_t *npull)
2174 {
2175         struct ctdb_tunable *val;
2176         size_t offset = 0, np;
2177         int ret;
2178
2179         val = talloc(mem_ctx, struct ctdb_tunable);
2180         if (val == NULL) {
2181                 return ENOMEM;
2182         }
2183
2184         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->value, &np);
2185         if (ret != 0) {
2186                 goto fail;
2187         }
2188         offset += np;
2189
2190         ret = ctdb_stringn_pull(buf+offset, buflen-offset, mem_ctx,
2191                                 &val->name, &np);
2192         if (ret != 0) {
2193                 goto fail;
2194         }
2195         offset += np;
2196
2197         *out = val;
2198         *npull = offset;
2199         return 0;
2200
2201 fail:
2202         talloc_free(val);
2203         return ret;
2204 }
2205
2206 size_t ctdb_node_flag_change_len(struct ctdb_node_flag_change *in)
2207 {
2208         return ctdb_uint32_len(&in->pnn) +
2209                 ctdb_uint32_len(&in->new_flags) +
2210                 ctdb_uint32_len(&in->old_flags);
2211 }
2212
2213 void ctdb_node_flag_change_push(struct ctdb_node_flag_change *in,
2214                                 uint8_t *buf, size_t *npush)
2215 {
2216         size_t offset = 0, np;
2217
2218         ctdb_uint32_push(&in->pnn, buf+offset, &np);
2219         offset += np;
2220
2221         ctdb_uint32_push(&in->new_flags, buf+offset, &np);
2222         offset += np;
2223
2224         ctdb_uint32_push(&in->old_flags, buf+offset, &np);
2225         offset += np;
2226
2227         *npush = offset;
2228 }
2229
2230 int ctdb_node_flag_change_pull(uint8_t *buf, size_t buflen,
2231                                TALLOC_CTX *mem_ctx,
2232                                struct ctdb_node_flag_change **out,
2233                                size_t *npull)
2234 {
2235         struct ctdb_node_flag_change *val;
2236         size_t offset = 0, np;
2237         int ret;
2238
2239         val = talloc(mem_ctx, struct ctdb_node_flag_change);
2240         if (val == NULL) {
2241                 return ENOMEM;
2242         }
2243
2244         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->pnn, &np);
2245         if (ret != 0) {
2246                 goto fail;
2247         }
2248         offset += np;
2249
2250         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->new_flags,
2251                                &np);
2252         if (ret != 0) {
2253                 goto fail;
2254         }
2255         offset += np;
2256
2257         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->old_flags,
2258                                &np);
2259         if (ret != 0) {
2260                 goto fail;
2261         }
2262         offset += np;
2263
2264         *out = val;
2265         *npull = offset;
2266         return 0;
2267
2268 fail:
2269         talloc_free(val);
2270         return ret;
2271 }
2272
2273 size_t ctdb_var_list_len(struct ctdb_var_list *in)
2274 {
2275         uint32_t u32 = 0;
2276         int i;
2277
2278         for (i=0; i<in->count; i++) {
2279                 u32 += ctdb_string_len(&in->var[i]);
2280         }
2281
2282         return ctdb_uint32_len(&u32) + u32;
2283 }
2284
2285 void ctdb_var_list_push(struct ctdb_var_list *in, uint8_t *buf, size_t *npush)
2286 {
2287         size_t offset = 0, np;
2288         uint32_t u32;
2289         int i;
2290         uint8_t sep = ':';
2291
2292         /* The length only corresponds to the payload size */
2293         u32 = ctdb_var_list_len(in);
2294         u32 -= ctdb_uint32_len(&u32);
2295
2296         ctdb_uint32_push(&u32, buf+offset, &np);
2297         offset += np;
2298
2299         /* The variables are separated by ':' and the complete string is null
2300          * terminated.
2301          */
2302         for (i=0; i<in->count; i++) {
2303                 ctdb_string_push(&in->var[i], buf+offset, &np);
2304                 offset += np;
2305
2306                 if (i < in->count - 1) {
2307                         /* Replace '\0' with ':' */
2308                         ctdb_uint8_push(&sep, buf+offset-1, &np);
2309                 }
2310         }
2311
2312         *npush = offset;
2313 }
2314
2315 int ctdb_var_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
2316                        struct ctdb_var_list **out, size_t *npull)
2317 {
2318         struct ctdb_var_list *val;
2319         const char *str, **list;
2320         char *s, *tok, *ptr = NULL;
2321         size_t offset = 0, np;
2322         uint32_t u32;
2323         int ret;
2324
2325         val = talloc_zero(mem_ctx, struct ctdb_var_list);
2326         if (val == NULL) {
2327                 return ENOMEM;
2328         }
2329
2330         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &u32, &np);
2331         if (ret != 0) {
2332                 goto fail;
2333         }
2334         offset += np;
2335
2336         if (buflen-offset < u32) {
2337                 ret = EMSGSIZE;
2338                 goto fail;
2339         }
2340
2341         ret = ctdb_string_pull(buf+offset, u32, val, &str, &np);
2342         if (ret != 0) {
2343                 goto fail;
2344         }
2345         offset += np;
2346
2347         s = discard_const(str);
2348         while ((tok = strtok_r(s, ":", &ptr)) != NULL) {
2349                 list = talloc_realloc(val, val->var, const char *,
2350                                       val->count+1);
2351                 if (list == NULL) {
2352                         ret = ENOMEM;
2353                         goto fail;
2354                 }
2355
2356                 val->var = list;
2357
2358                 s = talloc_strdup(val, tok);
2359                 if (s == NULL) {
2360                         ret = ENOMEM;
2361                         goto fail;
2362                 }
2363
2364                 val->var[val->count] = s;
2365                 val->count += 1;
2366                 s = NULL;
2367         }
2368
2369         talloc_free(discard_const(str));
2370         *out = val;
2371         *npull = offset;
2372         return 0;
2373
2374 fail:
2375         talloc_free(val);
2376         return ret;
2377 }
2378
2379 size_t ctdb_tunable_list_len(struct ctdb_tunable_list *in)
2380 {
2381         return ctdb_uint32_len(&in->max_redirect_count) +
2382                 ctdb_uint32_len(&in->seqnum_interval) +
2383                 ctdb_uint32_len(&in->control_timeout) +
2384                 ctdb_uint32_len(&in->traverse_timeout) +
2385                 ctdb_uint32_len(&in->keepalive_interval) +
2386                 ctdb_uint32_len(&in->keepalive_limit) +
2387                 ctdb_uint32_len(&in->recover_timeout) +
2388                 ctdb_uint32_len(&in->recover_interval) +
2389                 ctdb_uint32_len(&in->election_timeout) +
2390                 ctdb_uint32_len(&in->takeover_timeout) +
2391                 ctdb_uint32_len(&in->monitor_interval) +
2392                 ctdb_uint32_len(&in->tickle_update_interval) +
2393                 ctdb_uint32_len(&in->script_timeout) +
2394                 ctdb_uint32_len(&in->monitor_timeout_count) +
2395                 ctdb_uint32_len(&in->script_unhealthy_on_timeout) +
2396                 ctdb_uint32_len(&in->recovery_grace_period) +
2397                 ctdb_uint32_len(&in->recovery_ban_period) +
2398                 ctdb_uint32_len(&in->database_hash_size) +
2399                 ctdb_uint32_len(&in->database_max_dead) +
2400                 ctdb_uint32_len(&in->rerecovery_timeout) +
2401                 ctdb_uint32_len(&in->enable_bans) +
2402                 ctdb_uint32_len(&in->deterministic_public_ips) +
2403                 ctdb_uint32_len(&in->reclock_ping_period) +
2404                 ctdb_uint32_len(&in->no_ip_failback) +
2405                 ctdb_uint32_len(&in->disable_ip_failover) +
2406                 ctdb_uint32_len(&in->verbose_memory_names) +
2407                 ctdb_uint32_len(&in->recd_ping_timeout) +
2408                 ctdb_uint32_len(&in->recd_ping_failcount) +
2409                 ctdb_uint32_len(&in->log_latency_ms) +
2410                 ctdb_uint32_len(&in->reclock_latency_ms) +
2411                 ctdb_uint32_len(&in->recovery_drop_all_ips) +
2412                 ctdb_uint32_len(&in->verify_recovery_lock) +
2413                 ctdb_uint32_len(&in->vacuum_interval) +
2414                 ctdb_uint32_len(&in->vacuum_max_run_time) +
2415                 ctdb_uint32_len(&in->repack_limit) +
2416                 ctdb_uint32_len(&in->vacuum_limit) +
2417                 ctdb_uint32_len(&in->max_queue_depth_drop_msg) +
2418                 ctdb_uint32_len(&in->allow_unhealthy_db_read) +
2419                 ctdb_uint32_len(&in->stat_history_interval) +
2420                 ctdb_uint32_len(&in->deferred_attach_timeout) +
2421                 ctdb_uint32_len(&in->vacuum_fast_path_count) +
2422                 ctdb_uint32_len(&in->lcp2_public_ip_assignment) +
2423                 ctdb_uint32_len(&in->allow_client_db_attach) +
2424                 ctdb_uint32_len(&in->recover_pdb_by_seqnum) +
2425                 ctdb_uint32_len(&in->deferred_rebalance_on_node_add) +
2426                 ctdb_uint32_len(&in->fetch_collapse) +
2427                 ctdb_uint32_len(&in->hopcount_make_sticky) +
2428                 ctdb_uint32_len(&in->sticky_duration) +
2429                 ctdb_uint32_len(&in->sticky_pindown) +
2430                 ctdb_uint32_len(&in->no_ip_takeover) +
2431                 ctdb_uint32_len(&in->db_record_count_warn) +
2432                 ctdb_uint32_len(&in->db_record_size_warn) +
2433                 ctdb_uint32_len(&in->db_size_warn) +
2434                 ctdb_uint32_len(&in->pulldb_preallocation_size) +
2435                 ctdb_uint32_len(&in->no_ip_host_on_all_disabled) +
2436                 ctdb_uint32_len(&in->samba3_hack) +
2437                 ctdb_uint32_len(&in->mutex_enabled) +
2438                 ctdb_uint32_len(&in->lock_processes_per_db) +
2439                 ctdb_uint32_len(&in->rec_buffer_size_limit) +
2440                 ctdb_uint32_len(&in->queue_buffer_size) +
2441                 ctdb_uint32_len(&in->ip_alloc_algorithm) +
2442                 ctdb_uint32_len(&in->allow_mixed_versions);
2443 }
2444
2445 void ctdb_tunable_list_push(struct ctdb_tunable_list *in, uint8_t *buf,
2446                             size_t *npush)
2447 {
2448         size_t offset = 0, np;
2449
2450         ctdb_uint32_push(&in->max_redirect_count, buf+offset, &np);
2451         offset += np;
2452
2453         ctdb_uint32_push(&in->seqnum_interval, buf+offset, &np);
2454         offset += np;
2455
2456         ctdb_uint32_push(&in->control_timeout, buf+offset, &np);
2457         offset += np;
2458
2459         ctdb_uint32_push(&in->traverse_timeout, buf+offset, &np);
2460         offset += np;
2461
2462         ctdb_uint32_push(&in->keepalive_interval, buf+offset, &np);
2463         offset += np;
2464
2465         ctdb_uint32_push(&in->keepalive_limit, buf+offset, &np);
2466         offset += np;
2467
2468         ctdb_uint32_push(&in->recover_timeout, buf+offset, &np);
2469         offset += np;
2470
2471         ctdb_uint32_push(&in->recover_interval, buf+offset, &np);
2472         offset += np;
2473
2474         ctdb_uint32_push(&in->election_timeout, buf+offset, &np);
2475         offset += np;
2476
2477         ctdb_uint32_push(&in->takeover_timeout, buf+offset, &np);
2478         offset += np;
2479
2480         ctdb_uint32_push(&in->monitor_interval, buf+offset, &np);
2481         offset += np;
2482
2483         ctdb_uint32_push(&in->tickle_update_interval, buf+offset, &np);
2484         offset += np;
2485
2486         ctdb_uint32_push(&in->script_timeout, buf+offset, &np);
2487         offset += np;
2488
2489         ctdb_uint32_push(&in->monitor_timeout_count, buf+offset, &np);
2490         offset += np;
2491
2492         ctdb_uint32_push(&in->script_unhealthy_on_timeout, buf+offset, &np);
2493         offset += np;
2494
2495         ctdb_uint32_push(&in->recovery_grace_period, buf+offset, &np);
2496         offset += np;
2497
2498         ctdb_uint32_push(&in->recovery_ban_period, buf+offset, &np);
2499         offset += np;
2500
2501         ctdb_uint32_push(&in->database_hash_size, buf+offset, &np);
2502         offset += np;
2503
2504         ctdb_uint32_push(&in->database_max_dead, buf+offset, &np);
2505         offset += np;
2506
2507         ctdb_uint32_push(&in->rerecovery_timeout, buf+offset, &np);
2508         offset += np;
2509
2510         ctdb_uint32_push(&in->enable_bans, buf+offset, &np);
2511         offset += np;
2512
2513         ctdb_uint32_push(&in->deterministic_public_ips, buf+offset, &np);
2514         offset += np;
2515
2516         ctdb_uint32_push(&in->reclock_ping_period, buf+offset, &np);
2517         offset += np;
2518
2519         ctdb_uint32_push(&in->no_ip_failback, buf+offset, &np);
2520         offset += np;
2521
2522         ctdb_uint32_push(&in->disable_ip_failover, buf+offset, &np);
2523         offset += np;
2524
2525         ctdb_uint32_push(&in->verbose_memory_names, buf+offset, &np);
2526         offset += np;
2527
2528         ctdb_uint32_push(&in->recd_ping_timeout, buf+offset, &np);
2529         offset += np;
2530
2531         ctdb_uint32_push(&in->recd_ping_failcount, buf+offset, &np);
2532         offset += np;
2533
2534         ctdb_uint32_push(&in->log_latency_ms, buf+offset, &np);
2535         offset += np;
2536
2537         ctdb_uint32_push(&in->reclock_latency_ms, buf+offset, &np);
2538         offset += np;
2539
2540         ctdb_uint32_push(&in->recovery_drop_all_ips, buf+offset, &np);
2541         offset += np;
2542
2543         ctdb_uint32_push(&in->verify_recovery_lock, buf+offset, &np);
2544         offset += np;
2545
2546         ctdb_uint32_push(&in->vacuum_interval, buf+offset, &np);
2547         offset += np;
2548
2549         ctdb_uint32_push(&in->vacuum_max_run_time, buf+offset, &np);
2550         offset += np;
2551
2552         ctdb_uint32_push(&in->repack_limit, buf+offset, &np);
2553         offset += np;
2554
2555         ctdb_uint32_push(&in->vacuum_limit, buf+offset, &np);
2556         offset += np;
2557
2558         ctdb_uint32_push(&in->max_queue_depth_drop_msg, buf+offset, &np);
2559         offset += np;
2560
2561         ctdb_uint32_push(&in->allow_unhealthy_db_read, buf+offset, &np);
2562         offset += np;
2563
2564         ctdb_uint32_push(&in->stat_history_interval, buf+offset, &np);
2565         offset += np;
2566
2567         ctdb_uint32_push(&in->deferred_attach_timeout, buf+offset, &np);
2568         offset += np;
2569
2570         ctdb_uint32_push(&in->vacuum_fast_path_count, buf+offset, &np);
2571         offset += np;
2572
2573         ctdb_uint32_push(&in->lcp2_public_ip_assignment, buf+offset, &np);
2574         offset += np;
2575
2576         ctdb_uint32_push(&in->allow_client_db_attach, buf+offset, &np);
2577         offset += np;
2578
2579         ctdb_uint32_push(&in->recover_pdb_by_seqnum, buf+offset, &np);
2580         offset += np;
2581
2582         ctdb_uint32_push(&in->deferred_rebalance_on_node_add, buf+offset, &np);
2583         offset += np;
2584
2585         ctdb_uint32_push(&in->fetch_collapse, buf+offset, &np);
2586         offset += np;
2587
2588         ctdb_uint32_push(&in->hopcount_make_sticky, buf+offset, &np);
2589         offset += np;
2590
2591         ctdb_uint32_push(&in->sticky_duration, buf+offset, &np);
2592         offset += np;
2593
2594         ctdb_uint32_push(&in->sticky_pindown, buf+offset, &np);
2595         offset += np;
2596
2597         ctdb_uint32_push(&in->no_ip_takeover, buf+offset, &np);
2598         offset += np;
2599
2600         ctdb_uint32_push(&in->db_record_count_warn, buf+offset, &np);
2601         offset += np;
2602
2603         ctdb_uint32_push(&in->db_record_size_warn, buf+offset, &np);
2604         offset += np;
2605
2606         ctdb_uint32_push(&in->db_size_warn, buf+offset, &np);
2607         offset += np;
2608
2609         ctdb_uint32_push(&in->pulldb_preallocation_size, buf+offset, &np);
2610         offset += np;
2611
2612         ctdb_uint32_push(&in->no_ip_host_on_all_disabled, buf+offset, &np);
2613         offset += np;
2614
2615         ctdb_uint32_push(&in->samba3_hack, buf+offset, &np);
2616         offset += np;
2617
2618         ctdb_uint32_push(&in->mutex_enabled, buf+offset, &np);
2619         offset += np;
2620
2621         ctdb_uint32_push(&in->lock_processes_per_db, buf+offset, &np);
2622         offset += np;
2623
2624         ctdb_uint32_push(&in->rec_buffer_size_limit, buf+offset, &np);
2625         offset += np;
2626
2627         ctdb_uint32_push(&in->queue_buffer_size, buf+offset, &np);
2628         offset += np;
2629
2630         ctdb_uint32_push(&in->ip_alloc_algorithm, buf+offset, &np);
2631         offset += np;
2632
2633         ctdb_uint32_push(&in->allow_mixed_versions, buf+offset, &np);
2634         offset += np;
2635
2636         *npush = offset;
2637 }
2638
2639 static int ctdb_tunable_list_pull_elems(uint8_t *buf, size_t buflen,
2640                                         TALLOC_CTX *mem_ctx,
2641                                         struct ctdb_tunable_list *out,
2642                                         size_t *npull)
2643 {
2644         size_t offset = 0, np;
2645         int ret;
2646
2647         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2648                                &out->max_redirect_count, &np);
2649         if (ret != 0) {
2650                 return ret;
2651         }
2652         offset += np;
2653
2654         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2655                                &out->seqnum_interval, &np);
2656         if (ret != 0) {
2657                 return ret;
2658         }
2659         offset += np;
2660
2661         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2662                                &out->control_timeout, &np);
2663         if (ret != 0) {
2664                 return ret;
2665         }
2666         offset += np;
2667
2668         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2669                                &out->traverse_timeout, &np);
2670         if (ret != 0) {
2671                 return ret;
2672         }
2673         offset += np;
2674
2675         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2676                                &out->keepalive_interval, &np);
2677         if (ret != 0) {
2678                 return ret;
2679         }
2680         offset += np;
2681
2682         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2683                                &out->keepalive_limit, &np);
2684         if (ret != 0) {
2685                 return ret;
2686         }
2687         offset += np;
2688
2689         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2690                                &out->recover_timeout, &np);
2691         if (ret != 0) {
2692                 return ret;
2693         }
2694         offset += np;
2695
2696         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2697                                &out->recover_interval, &np);
2698         if (ret != 0) {
2699                 return ret;
2700         }
2701         offset += np;
2702
2703         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2704                                &out->election_timeout, &np);
2705         if (ret != 0) {
2706                 return ret;
2707         }
2708         offset += np;
2709
2710         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2711                                &out->takeover_timeout, &np);
2712         if (ret != 0) {
2713                 return ret;
2714         }
2715         offset += np;
2716
2717         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2718                                &out->monitor_interval, &np);
2719         if (ret != 0) {
2720                 return ret;
2721         }
2722         offset += np;
2723
2724         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2725                                &out->tickle_update_interval, &np);
2726         if (ret != 0) {
2727                 return ret;
2728         }
2729         offset += np;
2730
2731         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2732                                &out->script_timeout, &np);
2733         if (ret != 0) {
2734                 return ret;
2735         }
2736         offset += np;
2737
2738         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2739                                &out->monitor_timeout_count, &np);
2740         if (ret != 0) {
2741                 return ret;
2742         }
2743         offset += np;
2744
2745         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2746                                &out->script_unhealthy_on_timeout, &np);
2747         if (ret != 0) {
2748                 return ret;
2749         }
2750         offset += np;
2751
2752         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2753                                &out->recovery_grace_period, &np);
2754         if (ret != 0) {
2755                 return ret;
2756         }
2757         offset += np;
2758
2759         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2760                                &out->recovery_ban_period, &np);
2761         if (ret != 0) {
2762                 return ret;
2763         }
2764         offset += np;
2765
2766         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2767                                &out->database_hash_size, &np);
2768         if (ret != 0) {
2769                 return ret;
2770         }
2771         offset += np;
2772
2773         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2774                                &out->database_max_dead, &np);
2775         if (ret != 0) {
2776                 return ret;
2777         }
2778         offset += np;
2779
2780         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2781                                &out->rerecovery_timeout, &np);
2782         if (ret != 0) {
2783                 return ret;
2784         }
2785         offset += np;
2786
2787         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2788                                &out->enable_bans, &np);
2789         if (ret != 0) {
2790                 return ret;
2791         }
2792         offset += np;
2793
2794         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2795                                &out->deterministic_public_ips, &np);
2796         if (ret != 0) {
2797                 return ret;
2798         }
2799         offset += np;
2800
2801         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2802                                &out->reclock_ping_period, &np);
2803         if (ret != 0) {
2804                 return ret;
2805         }
2806         offset += np;
2807
2808         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2809                                &out->no_ip_failback, &np);
2810         if (ret != 0) {
2811                 return ret;
2812         }
2813         offset += np;
2814
2815         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2816                                &out->disable_ip_failover, &np);
2817         if (ret != 0) {
2818                 return ret;
2819         }
2820         offset += np;
2821
2822         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2823                                &out->verbose_memory_names, &np);
2824         if (ret != 0) {
2825                 return ret;
2826         }
2827         offset += np;
2828
2829         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2830                                &out->recd_ping_timeout, &np);
2831         if (ret != 0) {
2832                 return ret;
2833         }
2834         offset += np;
2835
2836         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2837                                &out->recd_ping_failcount, &np);
2838         if (ret != 0) {
2839                 return ret;
2840         }
2841         offset += np;
2842
2843         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2844                                &out->log_latency_ms, &np);
2845         if (ret != 0) {
2846                 return ret;
2847         }
2848         offset += np;
2849
2850         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2851                                &out->reclock_latency_ms, &np);
2852         if (ret != 0) {
2853                 return ret;
2854         }
2855         offset += np;
2856
2857         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2858                                &out->recovery_drop_all_ips, &np);
2859         if (ret != 0) {
2860                 return ret;
2861         }
2862         offset += np;
2863
2864         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2865                                &out->verify_recovery_lock, &np);
2866         if (ret != 0) {
2867                 return ret;
2868         }
2869         offset += np;
2870
2871         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2872                                &out->vacuum_interval, &np);
2873         if (ret != 0) {
2874                 return ret;
2875         }
2876         offset += np;
2877
2878         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2879                                &out->vacuum_max_run_time, &np);
2880         if (ret != 0) {
2881                 return ret;
2882         }
2883         offset += np;
2884
2885         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2886                                &out->repack_limit, &np);
2887         if (ret != 0) {
2888                 return ret;
2889         }
2890         offset += np;
2891
2892         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2893                                &out->vacuum_limit, &np);
2894         if (ret != 0) {
2895                 return ret;
2896         }
2897         offset += np;
2898
2899         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2900                                &out->max_queue_depth_drop_msg, &np);
2901         if (ret != 0) {
2902                 return ret;
2903         }
2904         offset += np;
2905
2906         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2907                                &out->allow_unhealthy_db_read, &np);
2908         if (ret != 0) {
2909                 return ret;
2910         }
2911         offset += np;
2912
2913         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2914                                &out->stat_history_interval, &np);
2915         if (ret != 0) {
2916                 return ret;
2917         }
2918         offset += np;
2919
2920         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2921                                &out->deferred_attach_timeout, &np);
2922         if (ret != 0) {
2923                 return ret;
2924         }
2925         offset += np;
2926
2927         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2928                                &out->vacuum_fast_path_count, &np);
2929         if (ret != 0) {
2930                 return ret;
2931         }
2932         offset += np;
2933
2934         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2935                                &out->lcp2_public_ip_assignment, &np);
2936         if (ret != 0) {
2937                 return ret;
2938         }
2939         offset += np;
2940
2941         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2942                                &out->allow_client_db_attach, &np);
2943         if (ret != 0) {
2944                 return ret;
2945         }
2946         offset += np;
2947
2948         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2949                                &out->recover_pdb_by_seqnum, &np);
2950         if (ret != 0) {
2951                 return ret;
2952         }
2953         offset += np;
2954
2955         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2956                                &out->deferred_rebalance_on_node_add, &np);
2957         if (ret != 0) {
2958                 return ret;
2959         }
2960         offset += np;
2961
2962         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2963                                &out->fetch_collapse, &np);
2964         if (ret != 0) {
2965                 return ret;
2966         }
2967         offset += np;
2968
2969         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2970                                &out->hopcount_make_sticky, &np);
2971         if (ret != 0) {
2972                 return ret;
2973         }
2974         offset += np;
2975
2976         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2977                                &out->sticky_duration, &np);
2978         if (ret != 0) {
2979                 return ret;
2980         }
2981         offset += np;
2982
2983         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2984                                &out->sticky_pindown, &np);
2985         if (ret != 0) {
2986                 return ret;
2987         }
2988         offset += np;
2989
2990         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2991                                &out->no_ip_takeover, &np);
2992         if (ret != 0) {
2993                 return ret;
2994         }
2995         offset += np;
2996
2997         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
2998                                &out->db_record_count_warn, &np);
2999         if (ret != 0) {
3000                 return ret;
3001         }
3002         offset += np;
3003
3004         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3005                                &out->db_record_size_warn, &np);
3006         if (ret != 0) {
3007                 return ret;
3008         }
3009         offset += np;
3010
3011         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3012                                &out->db_size_warn, &np);
3013         if (ret != 0) {
3014                 return ret;
3015         }
3016         offset += np;
3017
3018         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3019                                &out->pulldb_preallocation_size, &np);
3020         if (ret != 0) {
3021                 return ret;
3022         }
3023         offset += np;
3024
3025         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3026                                &out->no_ip_host_on_all_disabled, &np);
3027         if (ret != 0) {
3028                 return ret;
3029         }
3030         offset += np;
3031
3032         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3033                                &out->samba3_hack, &np);
3034         if (ret != 0) {
3035                 return ret;
3036         }
3037         offset += np;
3038
3039         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3040                                &out->mutex_enabled, &np);
3041         if (ret != 0) {
3042                 return ret;
3043         }
3044         offset += np;
3045
3046         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3047                                &out->lock_processes_per_db, &np);
3048         if (ret != 0) {
3049                 return ret;
3050         }
3051         offset += np;
3052
3053         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3054                                &out->rec_buffer_size_limit, &np);
3055         if (ret != 0) {
3056                 return ret;
3057         }
3058         offset += np;
3059
3060         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3061                                &out->queue_buffer_size, &np);
3062         if (ret != 0) {
3063                 return ret;
3064         }
3065         offset += np;
3066
3067         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3068                                &out->ip_alloc_algorithm, &np);
3069         if (ret != 0) {
3070                 return ret;
3071         }
3072         offset += np;
3073
3074         ret = ctdb_uint32_pull(buf+offset, buflen-offset,
3075                                &out->allow_mixed_versions, &np);
3076         if (ret != 0) {
3077                 return ret;
3078         }
3079         offset += np;
3080
3081         *npull = offset;
3082         return 0;
3083 }
3084
3085 int ctdb_tunable_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3086                            struct ctdb_tunable_list **out, size_t *npull)
3087 {
3088         struct ctdb_tunable_list *val;
3089         size_t np;
3090         int ret;
3091
3092         val = talloc(mem_ctx, struct ctdb_tunable_list);
3093         if (val == NULL) {
3094                 return ENOMEM;
3095         }
3096
3097         ret = ctdb_tunable_list_pull_elems(buf, buflen, val, val, &np);
3098         if (ret != 0) {
3099                 talloc_free(val);
3100                 return ret;
3101         }
3102
3103         *out = val;
3104         *npull = np;
3105         return 0;
3106 }
3107
3108 size_t ctdb_tickle_list_len(struct ctdb_tickle_list *in)
3109 {
3110         size_t len;
3111
3112         len = ctdb_sock_addr_len(&in->addr) +
3113                 ctdb_uint32_len(&in->num);
3114         if (in->num > 0) {
3115                 len += in->num * ctdb_connection_len(&in->conn[0]);
3116         }
3117
3118         return len;
3119 }
3120
3121 void ctdb_tickle_list_push(struct ctdb_tickle_list *in, uint8_t *buf,
3122                            size_t *npush)
3123 {
3124         size_t offset = 0, np;
3125         uint32_t i;
3126
3127         ctdb_sock_addr_push(&in->addr, buf+offset, &np);
3128         offset += np;
3129
3130         ctdb_uint32_push(&in->num, buf+offset, &np);
3131         offset += np;
3132
3133         for (i=0; i<in->num; i++) {
3134                 ctdb_connection_push(&in->conn[i], buf+offset, &np);
3135                 offset += np;
3136         }
3137
3138         *npush = offset;
3139 }
3140
3141 int ctdb_tickle_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3142                            struct ctdb_tickle_list **out, size_t *npull)
3143 {
3144         struct ctdb_tickle_list *val;
3145         size_t offset = 0, np;
3146         uint32_t i;
3147         int ret;
3148
3149         val = talloc(mem_ctx, struct ctdb_tickle_list);
3150         if (val == NULL) {
3151                 return ENOMEM;
3152         }
3153
3154         ret = ctdb_sock_addr_pull_elems(buf+offset, buflen-offset, val,
3155                                         &val->addr, &np);
3156         if (ret != 0) {
3157                 goto fail;
3158         }
3159         offset += np;
3160
3161         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->num, &np);
3162         if (ret != 0) {
3163                 goto fail;
3164         }
3165         offset += np;
3166
3167         if (val->num == 0) {
3168                 val->conn = NULL;
3169                 goto done;
3170         }
3171
3172         val->conn = talloc_array(val, struct ctdb_connection, val->num);
3173         if (val->conn == NULL) {
3174                 ret = ENOMEM;
3175                 goto fail;
3176         }
3177
3178         for (i=0; i<val->num; i++) {
3179                 ret = ctdb_connection_pull_elems(buf+offset, buflen-offset,
3180                                                  val, &val->conn[i], &np);
3181                 if (ret != 0) {
3182                         goto fail;
3183                 }
3184                 offset += np;
3185         }
3186
3187 done:
3188         *out = val;
3189         *npull = offset;
3190         return 0;
3191
3192 fail:
3193         talloc_free(val);
3194         return ret;
3195 }
3196
3197 size_t ctdb_addr_info_len(struct ctdb_addr_info *in)
3198 {
3199         return ctdb_sock_addr_len(&in->addr) +
3200                 ctdb_uint32_len(&in->mask) +
3201                 ctdb_stringn_len(&in->iface);
3202 }
3203
3204 void ctdb_addr_info_push(struct ctdb_addr_info *in, uint8_t *buf,
3205                          size_t *npush)
3206 {
3207         size_t offset = 0, np;
3208
3209         ctdb_sock_addr_push(&in->addr, buf+offset, &np);
3210         offset += np;
3211
3212         ctdb_uint32_push(&in->mask, buf+offset, &np);
3213         offset += np;
3214
3215         ctdb_stringn_push(&in->iface, buf+offset, &np);
3216         offset += np;
3217
3218         *npush = offset;
3219 }
3220
3221 int ctdb_addr_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3222                         struct ctdb_addr_info **out, size_t *npull)
3223 {
3224         struct ctdb_addr_info *val;
3225         size_t offset = 0, np;
3226         int ret;
3227
3228         val = talloc(mem_ctx, struct ctdb_addr_info);
3229         if (val == NULL) {
3230                 return ENOMEM;
3231         }
3232
3233         ret = ctdb_sock_addr_pull_elems(buf+offset, buflen-offset, val,
3234                                         &val->addr, &np);
3235         if (ret != 0) {
3236                 goto fail;
3237         }
3238         offset += np;
3239
3240         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->mask, &np);
3241         if (ret != 0) {
3242                 goto fail;
3243         }
3244         offset += np;
3245
3246         ret = ctdb_stringn_pull(buf+offset, buflen-offset, val, &val->iface,
3247                                 &np);
3248         if (ret != 0) {
3249                 goto fail;
3250         }
3251         offset += np;
3252
3253         *out = val;
3254         *npull = offset;
3255         return 0;
3256
3257 fail:
3258         talloc_free(val);
3259         return ret;
3260 }
3261
3262 size_t ctdb_transdb_len(struct ctdb_transdb *in)
3263 {
3264         return ctdb_uint32_len(&in->db_id) +
3265                 ctdb_uint32_len(&in->tid);
3266 }
3267
3268 void ctdb_transdb_push(struct ctdb_transdb *in, uint8_t *buf, size_t *npush)
3269 {
3270         size_t offset = 0, np;
3271
3272         ctdb_uint32_push(&in->db_id, buf+offset, &np);
3273         offset += np;
3274
3275         ctdb_uint32_push(&in->tid, buf+offset, &np);
3276         offset += np;
3277
3278         *npush = offset;
3279 }
3280
3281 int ctdb_transdb_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3282                      struct ctdb_transdb **out, size_t *npull)
3283 {
3284         struct ctdb_transdb *val;
3285         size_t offset = 0, np;
3286         int ret;
3287
3288         val = talloc(mem_ctx, struct ctdb_transdb);
3289         if (val == NULL) {
3290                 return ENOMEM;
3291         }
3292
3293         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->db_id, &np);
3294         if (ret != 0) {
3295                 goto fail;
3296         }
3297         offset += np;
3298
3299         ret = ctdb_uint32_pull(buf+offset, buflen-offset, &val->tid, &np);
3300         if (ret != 0) {
3301                 goto fail;
3302         }
3303         offset += np;
3304
3305         *out = val;
3306         *npull = offset;
3307         return 0;
3308
3309 fail:
3310         talloc_free(val);
3311         return ret;
3312 }
3313
3314 size_t ctdb_uptime_len(struct ctdb_uptime *in)
3315 {
3316         return ctdb_timeval_len(&in->current_time) +
3317                 ctdb_timeval_len(&in->ctdbd_start_time) +
3318                 ctdb_timeval_len(&in->last_recovery_started) +
3319                 ctdb_timeval_len(&in->last_recovery_finished);
3320 }
3321
3322 void ctdb_uptime_push(struct ctdb_uptime *in, uint8_t *buf, size_t *npush)
3323 {
3324         size_t offset = 0, np;
3325
3326         ctdb_timeval_push(&in->current_time, buf+offset, &np);
3327         offset += np;
3328
3329         ctdb_timeval_push(&in->ctdbd_start_time, buf+offset, &np);
3330         offset += np;
3331
3332         ctdb_timeval_push(&in->last_recovery_started, buf+offset, &np);
3333         offset += np;
3334
3335         ctdb_timeval_push(&in->last_recovery_finished, buf+offset, &np);
3336         offset += np;
3337
3338         *npush = offset;
3339 }
3340
3341 int ctdb_uptime_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3342                      struct ctdb_uptime **out, size_t *npull)
3343 {
3344         struct ctdb_uptime *val;
3345         size_t offset = 0, np;
3346         int ret;
3347
3348         val = talloc(mem_ctx, struct ctdb_uptime);
3349         if (val == NULL) {
3350                 return ENOMEM;
3351         }
3352
3353         ret = ctdb_timeval_pull(buf+offset, buflen-offset, &val->current_time,
3354                                 &np);
3355         if (ret != 0) {
3356                 goto fail;
3357         }
3358         offset += np;
3359
3360         ret = ctdb_timeval_pull(buf+offset, buflen-offset,
3361                                 &val->ctdbd_start_time, &np);
3362         if (ret != 0) {
3363                 goto fail;
3364         }
3365         offset += np;
3366
3367         ret = ctdb_timeval_pull(buf+offset, buflen-offset,
3368                                 &val->last_recovery_started, &np);
3369         if (ret != 0) {
3370                 goto fail;
3371         }
3372         offset += np;
3373
3374         ret = ctdb_timeval_pull(buf+offset, buflen-offset,
3375                                 &val->last_recovery_finished, &np);
3376         if (ret != 0) {
3377                 goto fail;
3378         }
3379         offset += np;
3380
3381         *out = val;
3382         *npull = offset;
3383         return 0;
3384
3385 fail:
3386         talloc_free(val);
3387         return ret;
3388 }
3389
3390 size_t ctdb_public_ip_len(struct ctdb_public_ip *pubip)
3391 {
3392         return sizeof(struct ctdb_public_ip);
3393 }
3394
3395 void ctdb_public_ip_push(struct ctdb_public_ip *pubip, uint8_t *buf)
3396 {
3397         memcpy(buf, pubip, sizeof(struct ctdb_public_ip));
3398 }
3399
3400 static int ctdb_public_ip_pull_elems(uint8_t *buf, size_t buflen,
3401                                      TALLOC_CTX *mem_ctx,
3402                                      struct ctdb_public_ip *out)
3403 {
3404         if (buflen < sizeof(struct ctdb_public_ip)) {
3405                 return EMSGSIZE;
3406         }
3407
3408         memcpy(out, buf, sizeof(struct ctdb_public_ip));
3409
3410         return 0;
3411 }
3412
3413 int ctdb_public_ip_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3414                         struct ctdb_public_ip **out)
3415 {
3416         struct ctdb_public_ip *pubip;
3417         int ret;
3418
3419         pubip = talloc(mem_ctx, struct ctdb_public_ip);
3420         if (pubip == NULL) {
3421                 return ENOMEM;
3422         }
3423
3424         ret = ctdb_public_ip_pull_elems(buf, buflen, pubip, pubip);
3425         if (ret != 0) {
3426                 TALLOC_FREE(pubip);
3427         }
3428
3429         *out = pubip;
3430         return ret;
3431 }
3432
3433 struct ctdb_public_ip_list_wire {
3434         uint32_t num;
3435         struct ctdb_public_ip ip[1];
3436 };
3437
3438 size_t ctdb_public_ip_list_len(struct ctdb_public_ip_list *pubip_list)
3439 {
3440         int i;
3441         size_t len;
3442
3443         len = sizeof(uint32_t);
3444         for (i=0; i<pubip_list->num; i++) {
3445                 len += ctdb_public_ip_len(&pubip_list->ip[i]);
3446         }
3447         return len;
3448 }
3449
3450 void ctdb_public_ip_list_push(struct ctdb_public_ip_list *pubip_list,
3451                               uint8_t *buf)
3452 {
3453         struct ctdb_public_ip_list_wire *wire =
3454                 (struct ctdb_public_ip_list_wire *)buf;
3455         size_t offset;
3456         int i;
3457
3458         wire->num = pubip_list->num;
3459
3460         offset = offsetof(struct ctdb_public_ip_list_wire, ip);
3461         for (i=0; i<pubip_list->num; i++) {
3462                 ctdb_public_ip_push(&pubip_list->ip[i], &buf[offset]);
3463                 offset += ctdb_public_ip_len(&pubip_list->ip[i]);
3464         }
3465 }
3466
3467 int ctdb_public_ip_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3468                              struct ctdb_public_ip_list **out)
3469 {
3470         struct ctdb_public_ip_list *pubip_list;
3471         struct ctdb_public_ip_list_wire *wire =
3472                 (struct ctdb_public_ip_list_wire *)buf;
3473         size_t offset;
3474         int i;
3475         bool ret;
3476
3477         if (buflen < sizeof(uint32_t)) {
3478                 return EMSGSIZE;
3479         }
3480         if (wire->num > buflen / sizeof(struct ctdb_public_ip)) {
3481                 return EMSGSIZE;
3482         }
3483         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_public_ip) <
3484             sizeof(uint32_t)) {
3485                 return EMSGSIZE;
3486         }
3487         if (buflen < sizeof(uint32_t) +
3488                      wire->num * sizeof(struct ctdb_public_ip)) {
3489                 return EMSGSIZE;
3490         }
3491
3492         pubip_list = talloc(mem_ctx, struct ctdb_public_ip_list);
3493         if (pubip_list == NULL) {
3494                 return ENOMEM;
3495         }
3496
3497         pubip_list->num = wire->num;
3498         if (wire->num == 0) {
3499                 pubip_list->ip = NULL;
3500                 *out = pubip_list;
3501                 return 0;
3502         }
3503         pubip_list->ip = talloc_array(pubip_list, struct ctdb_public_ip,
3504                                       wire->num);
3505         if (pubip_list->ip == NULL) {
3506                 talloc_free(pubip_list);
3507                 return ENOMEM;
3508         }
3509
3510         offset = offsetof(struct ctdb_public_ip_list_wire, ip);
3511         for (i=0; i<wire->num; i++) {
3512                 ret = ctdb_public_ip_pull_elems(&buf[offset], buflen-offset,
3513                                                 pubip_list->ip,
3514                                                 &pubip_list->ip[i]);
3515                 if (ret != 0) {
3516                         talloc_free(pubip_list);
3517                         return ret;
3518                 }
3519                 offset += ctdb_public_ip_len(&pubip_list->ip[i]);
3520         }
3521
3522         *out = pubip_list;
3523         return 0;
3524 }
3525
3526 size_t ctdb_node_and_flags_len(struct ctdb_node_and_flags *node)
3527 {
3528         return sizeof(struct ctdb_node_and_flags);
3529 }
3530
3531 void ctdb_node_and_flags_push(struct ctdb_node_and_flags *node, uint8_t *buf)
3532 {
3533         memcpy(buf, node, sizeof(struct ctdb_node_and_flags));
3534 }
3535
3536 static int ctdb_node_and_flags_pull_elems(TALLOC_CTX *mem_ctx,
3537                                           uint8_t *buf, size_t buflen,
3538                                           struct ctdb_node_and_flags *out)
3539 {
3540         if (buflen < sizeof(struct ctdb_node_and_flags)) {
3541                 return EMSGSIZE;
3542         }
3543
3544         memcpy(out, buf, sizeof(struct ctdb_node_and_flags));
3545
3546         return 0;
3547 }
3548
3549 int ctdb_node_and_flags_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3550                               struct ctdb_node_and_flags **out)
3551 {
3552         struct ctdb_node_and_flags *node;
3553         int ret;
3554
3555         node = talloc(mem_ctx, struct ctdb_node_and_flags);
3556         if (node == NULL) {
3557                 return ENOMEM;
3558         }
3559
3560         ret = ctdb_node_and_flags_pull_elems(node, buf, buflen, node);
3561         if (ret != 0) {
3562                 TALLOC_FREE(node);
3563         }
3564
3565         *out = node;
3566         return ret;
3567 }
3568
3569 struct ctdb_node_map_wire {
3570         uint32_t num;
3571         struct ctdb_node_and_flags node[1];
3572 };
3573
3574 size_t ctdb_node_map_len(struct ctdb_node_map *nodemap)
3575 {
3576         return sizeof(uint32_t) +
3577                nodemap->num * sizeof(struct ctdb_node_and_flags);
3578 }
3579
3580 void ctdb_node_map_push(struct ctdb_node_map *nodemap, uint8_t *buf)
3581 {
3582         struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
3583         size_t offset;
3584         int i;
3585
3586         wire->num = nodemap->num;
3587
3588         offset = offsetof(struct ctdb_node_map_wire, node);
3589         for (i=0; i<nodemap->num; i++) {
3590                 ctdb_node_and_flags_push(&nodemap->node[i], &buf[offset]);
3591                 offset += ctdb_node_and_flags_len(&nodemap->node[i]);
3592         }
3593 }
3594
3595 int ctdb_node_map_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3596                        struct ctdb_node_map **out)
3597 {
3598         struct ctdb_node_map *nodemap;
3599         struct ctdb_node_map_wire *wire = (struct ctdb_node_map_wire *)buf;
3600         size_t offset;
3601         int i;
3602         bool ret;
3603
3604         if (buflen < sizeof(uint32_t)) {
3605                 return EMSGSIZE;
3606         }
3607         if (wire->num > buflen / sizeof(struct ctdb_node_and_flags)) {
3608                 return EMSGSIZE;
3609         }
3610         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_node_and_flags) <
3611             sizeof(uint32_t)) {
3612                 return EMSGSIZE;
3613         }
3614         if (buflen < sizeof(uint32_t) +
3615                      wire->num * sizeof(struct ctdb_node_and_flags)) {
3616                 return EMSGSIZE;
3617         }
3618
3619         nodemap = talloc(mem_ctx, struct ctdb_node_map);
3620         if (nodemap == NULL) {
3621                 return ENOMEM;
3622         }
3623
3624         nodemap->num = wire->num;
3625         nodemap->node = talloc_array(nodemap, struct ctdb_node_and_flags,
3626                                      wire->num);
3627         if (nodemap->node == NULL) {
3628                 talloc_free(nodemap);
3629                 return ENOMEM;
3630         }
3631
3632         offset = offsetof(struct ctdb_node_map_wire, node);
3633         for (i=0; i<wire->num; i++) {
3634                 ret = ctdb_node_and_flags_pull_elems(nodemap->node,
3635                                                      &buf[offset],
3636                                                      buflen-offset,
3637                                                      &nodemap->node[i]);
3638                 if (ret != 0) {
3639                         talloc_free(nodemap);
3640                         return ret;
3641                 }
3642                 offset += ctdb_node_and_flags_len(&nodemap->node[i]);
3643         }
3644
3645         *out = nodemap;
3646         return 0;
3647 }
3648
3649 size_t ctdb_script_len(struct ctdb_script *script)
3650 {
3651         return sizeof(struct ctdb_script);
3652 }
3653
3654 void ctdb_script_push(struct ctdb_script *script, uint8_t *buf)
3655 {
3656         memcpy(buf, script, sizeof(struct ctdb_script));
3657 }
3658
3659 static int ctdb_script_pull_elems(uint8_t *buf, size_t buflen,
3660                                   TALLOC_CTX *mem_ctx,
3661                                   struct ctdb_script *out)
3662 {
3663         if (buflen < sizeof(struct ctdb_script)) {
3664                 return EMSGSIZE;
3665         }
3666
3667         memcpy(out, buf, sizeof(struct ctdb_script));
3668
3669         return 0;
3670 }
3671
3672 int ctdb_script_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3673                      struct ctdb_script **out)
3674 {
3675         struct ctdb_script *script;
3676         int ret;
3677
3678         script = talloc(mem_ctx, struct ctdb_script);
3679         if (script == NULL) {
3680                 return ENOMEM;
3681         }
3682
3683         ret = ctdb_script_pull_elems(buf, buflen, script, script);
3684         if (ret != 0) {
3685                 TALLOC_FREE(script);
3686         }
3687
3688         *out = script;
3689         return ret;
3690 }
3691
3692 struct ctdb_script_list_wire {
3693         uint32_t num_scripts;
3694         struct ctdb_script script[1];
3695 };
3696
3697 size_t ctdb_script_list_len(struct ctdb_script_list *script_list)
3698 {
3699         int i;
3700         size_t len;
3701
3702         if (script_list == NULL) {
3703                 return 0;
3704         }
3705
3706         len = offsetof(struct ctdb_script_list_wire, script);
3707         for (i=0; i<script_list->num_scripts; i++) {
3708                 len += ctdb_script_len(&script_list->script[i]);
3709         }
3710         return len;
3711 }
3712
3713 void ctdb_script_list_push(struct ctdb_script_list *script_list, uint8_t *buf)
3714 {
3715         struct ctdb_script_list_wire *wire =
3716                 (struct ctdb_script_list_wire *)buf;
3717         size_t offset;
3718         int i;
3719
3720         if (script_list == NULL) {
3721                 return;
3722         }
3723
3724         wire->num_scripts = script_list->num_scripts;
3725
3726         offset = offsetof(struct ctdb_script_list_wire, script);
3727         for (i=0; i<script_list->num_scripts; i++) {
3728                 ctdb_script_push(&script_list->script[i], &buf[offset]);
3729                 offset += ctdb_script_len(&script_list->script[i]);
3730         }
3731 }
3732
3733 int ctdb_script_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3734                           struct ctdb_script_list **out)
3735 {
3736         struct ctdb_script_list *script_list;
3737         struct ctdb_script_list_wire *wire =
3738                 (struct ctdb_script_list_wire *)buf;
3739         size_t offset;
3740         int i;
3741         bool ret;
3742
3743         /* If event scripts have never been run, the result will be NULL */
3744         if (buflen == 0) {
3745                 *out = NULL;
3746                 return 0;
3747         }
3748
3749         offset = offsetof(struct ctdb_script_list_wire, script);
3750
3751         if (buflen < offset) {
3752                 return EMSGSIZE;
3753         }
3754         if (wire->num_scripts > buflen / sizeof(struct ctdb_script)) {
3755                 return EMSGSIZE;
3756         }
3757         if (offset + wire->num_scripts * sizeof(struct ctdb_script) < offset) {
3758                 return EMSGSIZE;
3759         }
3760         if (buflen < offset + wire->num_scripts * sizeof(struct ctdb_script)) {
3761                 return EMSGSIZE;
3762         }
3763
3764         script_list = talloc(mem_ctx, struct ctdb_script_list);
3765         if (script_list == NULL) {
3766                 return ENOMEM;
3767
3768         }
3769
3770         script_list->num_scripts = wire->num_scripts;
3771         script_list->script = talloc_array(script_list, struct ctdb_script,
3772                                            wire->num_scripts);
3773         if (script_list->script == NULL) {
3774                 talloc_free(script_list);
3775                 return ENOMEM;
3776         }
3777
3778         for (i=0; i<wire->num_scripts; i++) {
3779                 ret = ctdb_script_pull_elems(&buf[offset], buflen-offset,
3780                                              script_list->script,
3781                                              &script_list->script[i]);
3782                 if (ret != 0) {
3783                         talloc_free(script_list);
3784                         return ret;
3785                 }
3786                 offset += ctdb_script_len(&script_list->script[i]);
3787         }
3788
3789         *out = script_list;
3790         return 0;
3791 }
3792
3793 size_t ctdb_ban_state_len(struct ctdb_ban_state *ban_state)
3794 {
3795         return sizeof(struct ctdb_ban_state);
3796 }
3797
3798 void ctdb_ban_state_push(struct ctdb_ban_state *ban_state, uint8_t *buf)
3799 {
3800         memcpy(buf, ban_state, sizeof(struct ctdb_ban_state));
3801 }
3802
3803 int ctdb_ban_state_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3804                         struct ctdb_ban_state **out)
3805 {
3806         struct ctdb_ban_state *ban_state;
3807
3808         if (buflen < sizeof(struct ctdb_ban_state)) {
3809                 return EMSGSIZE;
3810         }
3811
3812         ban_state = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_ban_state));
3813         if (ban_state == NULL) {
3814                 return ENOMEM;
3815         }
3816
3817         *out = ban_state;
3818         return 0;
3819 }
3820
3821 struct ctdb_notify_data_wire {
3822         uint64_t srvid;
3823         uint32_t len;
3824         uint8_t data[1];
3825 };
3826
3827 size_t ctdb_notify_data_len(struct ctdb_notify_data *notify)
3828 {
3829         return offsetof(struct ctdb_notify_data_wire, data) +
3830                notify->data.dsize;
3831 }
3832
3833 void ctdb_notify_data_push(struct ctdb_notify_data *notify, uint8_t *buf)
3834 {
3835         struct ctdb_notify_data_wire *wire =
3836                 (struct ctdb_notify_data_wire *)buf;
3837
3838         wire->srvid = notify->srvid;
3839         wire->len = notify->data.dsize;
3840         memcpy(wire->data, notify->data.dptr, notify->data.dsize);
3841 }
3842
3843 int ctdb_notify_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3844                           struct ctdb_notify_data **out)
3845 {
3846         struct ctdb_notify_data *notify;
3847         struct ctdb_notify_data_wire *wire =
3848                 (struct ctdb_notify_data_wire *)buf;
3849
3850         if (buflen < offsetof(struct ctdb_notify_data_wire, data)) {
3851                 return EMSGSIZE;
3852         }
3853         if (wire->len > buflen) {
3854                 return EMSGSIZE;
3855         }
3856         if (offsetof(struct ctdb_notify_data_wire, data) + wire->len <
3857             offsetof(struct ctdb_notify_data_wire, data)) {
3858                 return EMSGSIZE;
3859         }
3860         if (buflen < offsetof(struct ctdb_notify_data_wire, data) + wire->len) {
3861                 return EMSGSIZE;
3862         }
3863
3864         notify = talloc(mem_ctx, struct ctdb_notify_data);
3865         if (notify == NULL) {
3866                 return ENOMEM;
3867         }
3868
3869         notify->srvid = wire->srvid;
3870         notify->data.dsize = wire->len;
3871         notify->data.dptr = talloc_memdup(notify, wire->data, wire->len);
3872         if (notify->data.dptr == NULL) {
3873                 talloc_free(notify);
3874                 return ENOMEM;
3875         }
3876
3877         *out = notify;
3878         return 0;
3879 }
3880
3881 size_t ctdb_iface_len(struct ctdb_iface *iface)
3882 {
3883         return sizeof(struct ctdb_iface);
3884 }
3885
3886 void ctdb_iface_push(struct ctdb_iface *iface, uint8_t *buf)
3887 {
3888         memcpy(buf, iface, sizeof(struct ctdb_iface));
3889 }
3890
3891 static int ctdb_iface_pull_elems(uint8_t *buf, size_t buflen,
3892                                  TALLOC_CTX *mem_ctx,
3893                                  struct ctdb_iface *out)
3894 {
3895         if (buflen < sizeof(struct ctdb_iface)) {
3896                 return EMSGSIZE;
3897         }
3898
3899         memcpy(out, buf, sizeof(struct ctdb_iface));
3900
3901         return 0;
3902 }
3903
3904 int ctdb_iface_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3905                     struct ctdb_iface **out)
3906 {
3907         struct ctdb_iface *iface;
3908         int ret;
3909
3910         iface = talloc(mem_ctx, struct ctdb_iface);
3911         if (iface == NULL) {
3912                 return ENOMEM;
3913         }
3914
3915         ret = ctdb_iface_pull_elems(buf, buflen, iface, iface);
3916         if (ret != 0) {
3917                 TALLOC_FREE(iface);
3918         }
3919
3920         *out = iface;
3921         return ret;
3922 }
3923
3924 struct ctdb_iface_list_wire {
3925         uint32_t num;
3926         struct ctdb_iface iface[1];
3927 };
3928
3929 size_t ctdb_iface_list_len(struct ctdb_iface_list *iface_list)
3930 {
3931         return sizeof(uint32_t) +
3932                iface_list->num * sizeof(struct ctdb_iface);
3933 }
3934
3935 void ctdb_iface_list_push(struct ctdb_iface_list *iface_list, uint8_t *buf)
3936 {
3937         struct ctdb_iface_list_wire *wire =
3938                 (struct ctdb_iface_list_wire *)buf;
3939
3940         wire->num = iface_list->num;
3941         memcpy(wire->iface, iface_list->iface,
3942                iface_list->num * sizeof(struct ctdb_iface));
3943 }
3944
3945 int ctdb_iface_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
3946                          struct ctdb_iface_list **out)
3947 {
3948         struct ctdb_iface_list *iface_list;
3949         struct ctdb_iface_list_wire *wire =
3950                 (struct ctdb_iface_list_wire *)buf;
3951
3952         if (buflen < sizeof(uint32_t)) {
3953                 return EMSGSIZE;
3954         }
3955         if (wire->num > buflen / sizeof(struct ctdb_iface)) {
3956                 return EMSGSIZE;
3957         }
3958         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_iface) <
3959             sizeof(uint32_t)) {
3960                 return EMSGSIZE;
3961         }
3962         if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_iface)) {
3963                 return EMSGSIZE;
3964         }
3965
3966         iface_list = talloc(mem_ctx, struct ctdb_iface_list);
3967         if (iface_list == NULL) {
3968                 return ENOMEM;
3969         }
3970
3971         iface_list->num = wire->num;
3972         iface_list->iface = talloc_array(iface_list, struct ctdb_iface,
3973                                          wire->num);
3974         if (iface_list->iface == NULL) {
3975                 talloc_free(iface_list);
3976                 return ENOMEM;
3977         }
3978
3979         memcpy(iface_list->iface, wire->iface,
3980                wire->num * sizeof(struct ctdb_iface));
3981
3982         *out = iface_list;
3983         return 0;
3984 }
3985
3986 struct ctdb_public_ip_info_wire {
3987         struct ctdb_public_ip ip;
3988         uint32_t active_idx;
3989         uint32_t num;
3990         struct ctdb_iface ifaces[1];
3991 };
3992
3993 size_t ctdb_public_ip_info_len(struct ctdb_public_ip_info *ipinfo)
3994 {
3995         return offsetof(struct ctdb_public_ip_info_wire, num) +
3996                ctdb_iface_list_len(ipinfo->ifaces);
3997 }
3998
3999 void ctdb_public_ip_info_push(struct ctdb_public_ip_info *ipinfo, uint8_t *buf)
4000 {
4001         struct ctdb_public_ip_info_wire *wire =
4002                 (struct ctdb_public_ip_info_wire *)buf;
4003         size_t offset;
4004
4005         offset = offsetof(struct ctdb_public_ip_info_wire, num);
4006         memcpy(wire, ipinfo, offset);
4007         wire->num = ipinfo->ifaces->num;
4008         memcpy(wire->ifaces, ipinfo->ifaces->iface,
4009                ipinfo->ifaces->num * sizeof(struct ctdb_iface));
4010 }
4011
4012 int ctdb_public_ip_info_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
4013                              struct ctdb_public_ip_info **out)
4014 {
4015         struct ctdb_public_ip_info *ipinfo;
4016         struct ctdb_public_ip_info_wire *wire =
4017                 (struct ctdb_public_ip_info_wire *)buf;
4018
4019         if (buflen < offsetof(struct ctdb_public_ip_info_wire, ifaces)) {
4020                 return EMSGSIZE;
4021         }
4022         if (wire->num > buflen / sizeof(struct ctdb_iface)) {
4023                 return EMSGSIZE;
4024         }
4025         if (offsetof(struct ctdb_public_ip_info_wire, ifaces) +
4026             wire->num * sizeof(struct ctdb_iface) <
4027             offsetof(struct ctdb_public_ip_info_wire, ifaces)) {
4028                 return EMSGSIZE;
4029         }
4030         if (buflen < offsetof(struct ctdb_public_ip_info_wire, ifaces) +
4031                      wire->num * sizeof(struct ctdb_iface)) {
4032                 return EMSGSIZE;
4033         }
4034
4035         ipinfo = talloc(mem_ctx, struct ctdb_public_ip_info);
4036         if (ipinfo == NULL) {
4037                 return ENOMEM;
4038         }
4039
4040         memcpy(ipinfo, wire, offsetof(struct ctdb_public_ip_info_wire, num));
4041
4042         ipinfo->ifaces = talloc(ipinfo, struct ctdb_iface_list);
4043         if (ipinfo->ifaces == NULL) {
4044                 talloc_free(ipinfo);
4045                 return ENOMEM;
4046         }
4047
4048         ipinfo->ifaces->num = wire->num;
4049         ipinfo->ifaces->iface = talloc_array(ipinfo->ifaces, struct ctdb_iface,
4050                                              wire->num);
4051         if (ipinfo->ifaces->iface == NULL) {
4052                 talloc_free(ipinfo);
4053                 return ENOMEM;
4054         }
4055
4056         memcpy(ipinfo->ifaces->iface, wire->ifaces,
4057                wire->num * sizeof(struct ctdb_iface));
4058
4059         *out = ipinfo;
4060         return 0;
4061 }
4062
4063 struct ctdb_key_data_wire {
4064         uint32_t db_id;
4065         struct ctdb_ltdb_header header;
4066         uint32_t keylen;
4067         uint8_t key[1];
4068 };
4069
4070 size_t ctdb_key_data_len(struct ctdb_key_data *key)
4071 {
4072         return offsetof(struct ctdb_key_data_wire, key) + key->key.dsize;
4073 }
4074
4075 void ctdb_key_data_push(struct ctdb_key_data *key, uint8_t *buf)
4076 {
4077         struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
4078
4079         memcpy(wire, key, offsetof(struct ctdb_key_data, key));
4080         wire->keylen = key->key.dsize;
4081         memcpy(wire->key, key->key.dptr, key->key.dsize);
4082 }
4083
4084 int ctdb_key_data_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
4085                        struct ctdb_key_data **out)
4086 {
4087         struct ctdb_key_data *key_data;
4088         struct ctdb_key_data_wire *wire = (struct ctdb_key_data_wire *)buf;
4089
4090         if (buflen < offsetof(struct ctdb_key_data_wire, key)) {
4091                 return EMSGSIZE;
4092         }
4093         if (wire->keylen > buflen) {
4094                 return EMSGSIZE;
4095         }
4096         if (offsetof(struct ctdb_key_data_wire, key) + wire->keylen <
4097             offsetof(struct ctdb_key_data_wire, key)) {
4098                 return EMSGSIZE;
4099         }
4100         if (buflen < offsetof(struct ctdb_key_data_wire, key) + wire->keylen) {
4101                 return EMSGSIZE;
4102         }
4103
4104         key_data = talloc(mem_ctx, struct ctdb_key_data);
4105         if (key_data == NULL) {
4106                 return ENOMEM;
4107         }
4108
4109         memcpy(key_data, wire, offsetof(struct ctdb_key_data, key));
4110
4111         key_data->key.dsize = wire->keylen;
4112         key_data->key.dptr = talloc_memdup(key_data, wire->key, wire->keylen);
4113         if (key_data->key.dptr == NULL) {
4114                 talloc_free(key_data);
4115                 return ENOMEM;
4116         }
4117
4118         *out = key_data;
4119         return 0;
4120 }
4121
4122 struct ctdb_db_statistics_wire {
4123         struct ctdb_db_statistics dbstats;
4124         char hot_keys_wire[1];
4125 };
4126
4127 size_t ctdb_db_statistics_len(struct ctdb_db_statistics *dbstats)
4128 {
4129         size_t len;
4130         int i;
4131
4132         len = sizeof(struct ctdb_db_statistics);
4133         for (i=0; i<MAX_HOT_KEYS; i++) {
4134                 len += dbstats->hot_keys[i].key.dsize;
4135         }
4136         return len;
4137 }
4138
4139 void ctdb_db_statistics_push(struct ctdb_db_statistics *dbstats, void *buf)
4140 {
4141         struct ctdb_db_statistics_wire *wire =
4142                 (struct ctdb_db_statistics_wire *)buf;
4143         size_t offset;
4144         int i;
4145
4146         dbstats->num_hot_keys = MAX_HOT_KEYS;
4147         memcpy(wire, dbstats, sizeof(struct ctdb_db_statistics));
4148
4149         offset = 0;
4150         for (i=0; i<MAX_HOT_KEYS; i++) {
4151                 memcpy(&wire->hot_keys_wire[offset],
4152                        dbstats->hot_keys[i].key.dptr,
4153                        dbstats->hot_keys[i].key.dsize);
4154                 offset += dbstats->hot_keys[i].key.dsize;
4155         }
4156 }
4157
4158 int ctdb_db_statistics_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
4159                             struct ctdb_db_statistics **out)
4160 {
4161         struct ctdb_db_statistics *dbstats;
4162         struct ctdb_db_statistics_wire *wire =
4163                 (struct ctdb_db_statistics_wire *)buf;
4164         size_t offset;
4165         int i;
4166
4167         if (buflen < sizeof(struct ctdb_db_statistics)) {
4168                 return EMSGSIZE;
4169         }
4170
4171         offset = 0;
4172         for (i=0; i<wire->dbstats.num_hot_keys; i++) {
4173                 if (wire->dbstats.hot_keys[i].key.dsize > buflen) {
4174                         return EMSGSIZE;
4175                 }
4176                 if (offset + wire->dbstats.hot_keys[i].key.dsize < offset) {
4177                         return EMSGSIZE;
4178                 }
4179                 offset += wire->dbstats.hot_keys[i].key.dsize;
4180                 if (offset > buflen) {
4181                         return EMSGSIZE;
4182                 }
4183         }
4184         if (sizeof(struct ctdb_db_statistics) + offset <
4185             sizeof(struct ctdb_db_statistics)) {
4186                 return EMSGSIZE;
4187         }
4188         if (buflen < sizeof(struct ctdb_db_statistics) + offset) {
4189                 return EMSGSIZE;
4190         }
4191
4192         dbstats = talloc(mem_ctx, struct ctdb_db_statistics);
4193         if (dbstats == NULL) {
4194                 return ENOMEM;
4195         }
4196
4197         memcpy(dbstats, wire, sizeof(struct ctdb_db_statistics));
4198
4199         offset = 0;
4200         for (i=0; i<wire->dbstats.num_hot_keys; i++) {
4201                 uint8_t *ptr;
4202                 size_t key_size;
4203
4204                 key_size = dbstats->hot_keys[i].key.dsize;
4205                 ptr = talloc_memdup(mem_ctx, &wire->hot_keys_wire[offset],
4206                                     key_size);
4207                 if (ptr == NULL) {
4208                         talloc_free(dbstats);
4209                         return ENOMEM;
4210                 }
4211                 dbstats->hot_keys[i].key.dptr = ptr;
4212                 offset += key_size;
4213         }
4214
4215         *out = dbstats;
4216         return 0;
4217 }
4218
4219 size_t ctdb_election_message_len(struct ctdb_election_message *election)
4220 {
4221         return sizeof(struct ctdb_election_message);
4222 }
4223
4224 void ctdb_election_message_push(struct ctdb_election_message *election,
4225                                 uint8_t *buf)
4226 {
4227         memcpy(buf, election, sizeof(struct ctdb_election_message));
4228 }
4229
4230 int ctdb_election_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
4231                                struct ctdb_election_message **out)
4232 {
4233         struct ctdb_election_message *election;
4234
4235         if (buflen < sizeof(struct ctdb_election_message)) {
4236                 return EMSGSIZE;
4237         }
4238
4239         election = talloc_memdup(mem_ctx, buf,
4240                                  sizeof(struct ctdb_election_message));
4241         if (election == NULL) {
4242                 return ENOMEM;
4243         }
4244
4245         *out = election;
4246         return 0;
4247 }
4248
4249 size_t ctdb_srvid_message_len(struct ctdb_srvid_message *msg)
4250 {
4251         return sizeof(struct ctdb_srvid_message);
4252 }
4253
4254 void ctdb_srvid_message_push(struct ctdb_srvid_message *msg, uint8_t *buf)
4255 {
4256         memcpy(buf, msg, sizeof(struct ctdb_srvid_message));
4257 }
4258
4259 int ctdb_srvid_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
4260                             struct ctdb_srvid_message **out)
4261 {
4262         struct ctdb_srvid_message *msg;
4263
4264         if (buflen < sizeof(struct ctdb_srvid_message)) {
4265                 return EMSGSIZE;
4266         }
4267
4268         msg = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_srvid_message));
4269         if (msg == NULL) {
4270                 return ENOMEM;
4271         }
4272
4273         *out = msg;
4274         return 0;
4275 }
4276
4277 size_t ctdb_disable_message_len(struct ctdb_disable_message *disable)
4278 {
4279         return sizeof(struct ctdb_disable_message);
4280 }
4281
4282 void ctdb_disable_message_push(struct ctdb_disable_message *disable,
4283                                uint8_t *buf)
4284 {
4285         memcpy(buf, disable, sizeof(struct ctdb_disable_message));
4286 }
4287
4288 int ctdb_disable_message_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
4289                               struct ctdb_disable_message **out)
4290 {
4291         struct ctdb_disable_message *disable;
4292
4293         if (buflen < sizeof(struct ctdb_disable_message)) {
4294                 return EMSGSIZE;
4295         }
4296
4297         disable = talloc_memdup(mem_ctx, buf,
4298                                 sizeof(struct ctdb_disable_message));
4299         if (disable == NULL) {
4300                 return ENOMEM;
4301         }
4302
4303         *out = disable;
4304         return 0;
4305 }
4306
4307 size_t ctdb_server_id_len(struct ctdb_server_id *sid)
4308 {
4309         return sizeof(struct ctdb_server_id);
4310 }
4311
4312 void ctdb_server_id_push(struct ctdb_server_id *sid, uint8_t *buf)
4313 {
4314         memcpy(buf, sid, sizeof(struct ctdb_server_id));
4315 }
4316
4317 int ctdb_server_id_pull(uint8_t *buf, size_t buflen,
4318                         struct ctdb_server_id *sid)
4319 {
4320         if (buflen < sizeof(struct ctdb_server_id)) {
4321                 return EMSGSIZE;
4322         }
4323
4324         memcpy(sid, buf, sizeof(struct ctdb_server_id));
4325         return 0;
4326 }
4327
4328 size_t ctdb_g_lock_len(struct ctdb_g_lock *lock)
4329 {
4330         return sizeof(struct ctdb_g_lock);
4331 }
4332
4333 void ctdb_g_lock_push(struct ctdb_g_lock *lock, uint8_t *buf)
4334 {
4335         memcpy(buf, lock, sizeof(struct ctdb_g_lock));
4336 }
4337
4338 int ctdb_g_lock_pull(uint8_t *buf, size_t buflen, struct ctdb_g_lock *lock)
4339 {
4340         if (buflen < sizeof(struct ctdb_g_lock)) {
4341                 return EMSGSIZE;
4342         }
4343
4344         memcpy(lock, buf, sizeof(struct ctdb_g_lock));
4345         return 0;
4346 }
4347
4348 size_t ctdb_g_lock_list_len(struct ctdb_g_lock_list *lock_list)
4349 {
4350         return lock_list->num * sizeof(struct ctdb_g_lock);
4351 }
4352
4353 void ctdb_g_lock_list_push(struct ctdb_g_lock_list *lock_list, uint8_t *buf)
4354 {
4355         size_t offset = 0;
4356         int i;
4357
4358         for (i=0; i<lock_list->num; i++) {
4359                 ctdb_g_lock_push(&lock_list->lock[i], &buf[offset]);
4360                 offset += sizeof(struct ctdb_g_lock);
4361         }
4362 }
4363
4364 int ctdb_g_lock_list_pull(uint8_t *buf, size_t buflen, TALLOC_CTX *mem_ctx,
4365                           struct ctdb_g_lock_list **out)
4366 {
4367         struct ctdb_g_lock_list *lock_list;
4368         unsigned count;
4369         size_t offset;
4370         int ret, i;
4371
4372         lock_list = talloc_zero(mem_ctx, struct ctdb_g_lock_list);
4373         if (lock_list == NULL) {
4374                 return ENOMEM;
4375         }
4376
4377         count = buflen / sizeof(struct ctdb_g_lock);
4378         lock_list->lock = talloc_array(lock_list, struct ctdb_g_lock, count);
4379         if (lock_list->lock == NULL) {
4380                 talloc_free(lock_list);
4381                 return ENOMEM;
4382         }
4383
4384         offset = 0;
4385         for (i=0; i<count; i++) {
4386                 ret = ctdb_g_lock_pull(&buf[offset], buflen-offset,
4387                                        &lock_list->lock[i]);
4388                 if (ret != 0) {
4389                         talloc_free(lock_list);
4390                         return ret;
4391                 }
4392                 offset += sizeof(struct ctdb_g_lock);
4393         }
4394
4395         lock_list->num = count;
4396
4397         *out = lock_list;
4398         return 0;
4399 }