ctdb-protocol: Fix marshalling for ctdb_transdb
[vlendec/samba-autobuild/.git] / ctdb / tests / src / protocol_types_compat_test.c
1 /*
2    protocol types backward compatibility test
3
4    Copyright (C) Amitay Isaacs  2015
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/filesys.h"
22
23 #include <assert.h>
24
25 #include "protocol/protocol_basic.c"
26 #include "protocol/protocol_types.c"
27
28 #include "tests/src/protocol_common.h"
29
30 #define COMPAT_TEST_FUNC(NAME)          test_ ##NAME## _compat
31 #define OLD_LEN_FUNC(NAME)              NAME## _len_old
32 #define OLD_PUSH_FUNC(NAME)             NAME## _push_old
33 #define OLD_PULL_FUNC(NAME)             NAME## _pull_old
34
35 #define COMPAT_TYPE1_TEST(TYPE, NAME)   \
36 static void COMPAT_TEST_FUNC(NAME)(void) \
37 { \
38         TALLOC_CTX *mem_ctx; \
39         uint8_t *buf1, *buf2; \
40         TYPE p = { 0 }, p1, p2; \
41         size_t buflen1, buflen2, np = 0; \
42         int ret; \
43 \
44         mem_ctx = talloc_new(NULL); \
45         assert(mem_ctx != NULL); \
46         FILL_FUNC(NAME)(&p); \
47         buflen1 = LEN_FUNC(NAME)(&p); \
48         buflen2 = OLD_LEN_FUNC(NAME)(&p); \
49         assert(buflen1 == buflen2); \
50         buf1 = talloc_zero_size(mem_ctx, buflen1); \
51         assert(buf1 != NULL); \
52         buf2 = talloc_zero_size(mem_ctx, buflen2); \
53         assert(buf2 != NULL); \
54         PUSH_FUNC(NAME)(&p, buf1, &np); \
55         OLD_PUSH_FUNC(NAME)(&p, buf2); \
56         assert(memcmp(buf1, buf2, buflen1) == 0); \
57         ret = PULL_FUNC(NAME)(buf1, buflen1, &p1, &np); \
58         assert(ret == 0); \
59         ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &p2); \
60         VERIFY_FUNC(NAME)(&p1, &p2); \
61         talloc_free(mem_ctx); \
62 }
63
64 #define COMPAT_TYPE3_TEST(TYPE, NAME)   \
65 static void COMPAT_TEST_FUNC(NAME)(void) \
66 { \
67         TALLOC_CTX *mem_ctx; \
68         uint8_t *buf1, *buf2; \
69         TYPE *p, *p1, *p2; \
70         size_t buflen1, buflen2, np = 0; \
71         int ret; \
72 \
73         mem_ctx = talloc_new(NULL); \
74         assert(mem_ctx != NULL); \
75         p = talloc_zero(mem_ctx, TYPE); \
76         assert(p != NULL); \
77         FILL_FUNC(NAME)(p, p); \
78         buflen1 = LEN_FUNC(NAME)(p); \
79         buflen2 = OLD_LEN_FUNC(NAME)(p); \
80         assert(buflen1 == buflen2); \
81         buf1 = talloc_zero_size(mem_ctx, buflen1); \
82         assert(buf1 != NULL); \
83         buf2 = talloc_zero_size(mem_ctx, buflen2); \
84         assert(buf2 != NULL); \
85         PUSH_FUNC(NAME)(p, buf1, &np); \
86         OLD_PUSH_FUNC(NAME)(p, buf2); \
87         assert(memcmp(buf1, buf2, buflen1) == 0); \
88         ret = PULL_FUNC(NAME)(buf1, buflen1, mem_ctx, &p1, &np); \
89         assert(ret == 0); \
90         ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, mem_ctx, &p2); \
91         VERIFY_FUNC(NAME)(p1, p2); \
92         talloc_free(mem_ctx); \
93 }
94
95
96 static size_t ctdb_statistics_len_old(struct ctdb_statistics *in)
97 {
98         return sizeof(struct ctdb_statistics);
99 }
100
101 static void ctdb_statistics_push_old(struct ctdb_statistics *in, uint8_t *buf)
102 {
103         memcpy(buf, in, sizeof(struct ctdb_statistics));
104 }
105
106 static int ctdb_statistics_pull_old(uint8_t *buf, size_t buflen,
107                                     TALLOC_CTX *mem_ctx,
108                                     struct ctdb_statistics **out)
109 {
110         struct ctdb_statistics *val;
111
112         if (buflen < sizeof(struct ctdb_statistics)) {
113                 return EMSGSIZE;
114         }
115
116         val = talloc(mem_ctx, struct ctdb_statistics);
117         if (val == NULL) {
118                 return ENOMEM;
119         }
120
121         memcpy(val, buf, sizeof(struct ctdb_statistics));
122
123         *out = val;
124         return 0;
125 }
126
127 struct ctdb_vnn_map_wire {
128         uint32_t generation;
129         uint32_t size;
130         uint32_t map[1];
131 };
132
133 static size_t ctdb_vnn_map_len_old(struct ctdb_vnn_map *in)
134 {
135         return offsetof(struct ctdb_vnn_map, map) +
136                in->size * sizeof(uint32_t);
137 }
138
139 static void ctdb_vnn_map_push_old(struct ctdb_vnn_map *in, uint8_t *buf)
140 {
141         struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
142
143         memcpy(wire, in, offsetof(struct ctdb_vnn_map, map));
144         memcpy(wire->map, in->map, in->size * sizeof(uint32_t));
145 }
146
147 static int ctdb_vnn_map_pull_old(uint8_t *buf, size_t buflen,
148                                  TALLOC_CTX *mem_ctx,
149                                  struct ctdb_vnn_map **out)
150 {
151         struct ctdb_vnn_map *val;
152         struct ctdb_vnn_map_wire *wire = (struct ctdb_vnn_map_wire *)buf;
153
154         if (buflen < offsetof(struct ctdb_vnn_map_wire, map)) {
155                 return EMSGSIZE;
156         }
157         if (wire->size > buflen / sizeof(uint32_t)) {
158                 return EMSGSIZE;
159         }
160         if (offsetof(struct ctdb_vnn_map_wire, map) +
161             wire->size * sizeof(uint32_t) <
162             offsetof(struct ctdb_vnn_map_wire, map)) {
163                     return EMSGSIZE;
164         }
165         if (buflen < offsetof(struct ctdb_vnn_map_wire, map) +
166                      wire->size * sizeof(uint32_t)) {
167                 return EMSGSIZE;
168         }
169
170         val = talloc(mem_ctx, struct ctdb_vnn_map);
171         if (val == NULL) {
172                 return ENOMEM;
173         }
174
175         memcpy(val, wire, offsetof(struct ctdb_vnn_map, map));
176
177         val->map = talloc_memdup(val, wire->map,
178                                  wire->size * sizeof(uint32_t));
179         if (val->map == NULL) {
180                 talloc_free(val);
181                 return ENOMEM;
182         }
183
184         *out = val;
185         return 0;
186 }
187
188 struct ctdb_dbid_map_wire {
189         uint32_t num;
190         struct ctdb_dbid dbs[1];
191 };
192
193 static size_t ctdb_dbid_map_len_old(struct ctdb_dbid_map *in)
194 {
195         return sizeof(uint32_t) + in->num * sizeof(struct ctdb_dbid);
196 }
197
198 static void ctdb_dbid_map_push_old(struct ctdb_dbid_map *in, uint8_t *buf)
199 {
200         struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
201
202         wire->num = in->num;
203         memcpy(wire->dbs, in->dbs, in->num * sizeof(struct ctdb_dbid));
204 }
205
206 static int ctdb_dbid_map_pull_old(uint8_t *buf, size_t buflen,
207                                   TALLOC_CTX *mem_ctx,
208                                   struct ctdb_dbid_map **out)
209 {
210         struct ctdb_dbid_map *val;
211         struct ctdb_dbid_map_wire *wire = (struct ctdb_dbid_map_wire *)buf;
212
213         if (buflen < sizeof(uint32_t)) {
214                 return EMSGSIZE;
215         }
216         if (wire->num > buflen / sizeof(struct ctdb_dbid)) {
217                 return EMSGSIZE;
218         }
219         if (sizeof(uint32_t) + wire->num * sizeof(struct ctdb_dbid) <
220             sizeof(uint32_t)) {
221                 return EMSGSIZE;
222         }
223         if (buflen < sizeof(uint32_t) + wire->num * sizeof(struct ctdb_dbid)) {
224                 return EMSGSIZE;
225         }
226
227         val = talloc(mem_ctx, struct ctdb_dbid_map);
228         if (val == NULL) {
229                 return ENOMEM;
230         }
231
232         val->num = wire->num;
233
234         val->dbs = talloc_memdup(val, wire->dbs,
235                                  wire->num * sizeof(struct ctdb_dbid));
236         if (val->dbs == NULL) {
237                 talloc_free(val);
238                 return ENOMEM;
239         }
240
241         *out = val;
242         return 0;
243 }
244
245 static size_t ctdb_pulldb_len_old(struct ctdb_pulldb *in)
246 {
247         return sizeof(struct ctdb_pulldb);
248 }
249
250 static void ctdb_pulldb_push_old(struct ctdb_pulldb *in, uint8_t *buf)
251 {
252         memcpy(buf, in, sizeof(struct ctdb_pulldb));
253 }
254
255 static int ctdb_pulldb_pull_old(uint8_t *buf, size_t buflen,
256                                 TALLOC_CTX *mem_ctx, struct ctdb_pulldb **out)
257 {
258         struct ctdb_pulldb *val;
259
260         if (buflen < sizeof(struct ctdb_pulldb)) {
261                 return EMSGSIZE;
262         }
263
264         val = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_pulldb));
265         if (val == NULL) {
266                 return ENOMEM;
267         }
268
269         *out = val;
270         return 0;
271 }
272
273 static size_t ctdb_pulldb_ext_len_old(struct ctdb_pulldb_ext *in)
274 {
275         return sizeof(struct ctdb_pulldb_ext);
276 }
277
278 static void ctdb_pulldb_ext_push_old(struct ctdb_pulldb_ext *in, uint8_t *buf)
279 {
280         memcpy(buf, in, sizeof(struct ctdb_pulldb_ext));
281 }
282
283 static int ctdb_pulldb_ext_pull_old(uint8_t *buf, size_t buflen,
284                                     TALLOC_CTX *mem_ctx,
285                                     struct ctdb_pulldb_ext **out)
286 {
287         struct ctdb_pulldb_ext *val;
288
289         if (buflen < sizeof(struct ctdb_pulldb_ext)) {
290                 return EMSGSIZE;
291         }
292
293         val = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_pulldb_ext));
294         if (val == NULL) {
295                 return ENOMEM;
296         }
297
298         *out = val;
299         return 0;
300 }
301
302 static size_t ctdb_ltdb_header_len_old(struct ctdb_ltdb_header *in)
303 {
304         return sizeof(struct ctdb_ltdb_header);
305 }
306
307 static void ctdb_ltdb_header_push_old(struct ctdb_ltdb_header *in,
308                                       uint8_t *buf)
309 {
310         memcpy(buf, in, sizeof(struct ctdb_ltdb_header));
311 }
312
313 static int ctdb_ltdb_header_pull_old(uint8_t *buf, size_t buflen,
314                                      struct ctdb_ltdb_header *out)
315 {
316         if (buflen < sizeof(struct ctdb_ltdb_header)) {
317                 return EMSGSIZE;
318         }
319
320         memcpy(out, buf, sizeof(struct ctdb_ltdb_header));
321         return 0;
322 }
323
324 struct ctdb_rec_data_wire {
325         uint32_t length;
326         uint32_t reqid;
327         uint32_t keylen;
328         uint32_t datalen;
329         uint8_t data[1];
330 };
331
332 static size_t ctdb_rec_data_len_old(struct ctdb_rec_data *in)
333 {
334         return offsetof(struct ctdb_rec_data_wire, data) +
335                in->key.dsize + in->data.dsize +
336                (in->header == NULL ? 0 : sizeof(struct ctdb_ltdb_header));
337 }
338
339 static void ctdb_rec_data_push_old(struct ctdb_rec_data *in, uint8_t *buf)
340 {
341         struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
342         size_t offset;
343
344         wire->length = ctdb_rec_data_len(in);
345         wire->reqid = in->reqid;
346         wire->keylen = in->key.dsize;
347         wire->datalen = in->data.dsize;
348         if (in->header != NULL) {
349                 wire->datalen += sizeof(struct ctdb_ltdb_header);
350         }
351
352         memcpy(wire->data, in->key.dptr, in->key.dsize);
353         offset = in->key.dsize;
354         if (in->header != NULL) {
355                 memcpy(&wire->data[offset], in->header,
356                        sizeof(struct ctdb_ltdb_header));
357                 offset += sizeof(struct ctdb_ltdb_header);
358         }
359         if (in->data.dsize > 0) {
360                 memcpy(&wire->data[offset], in->data.dptr, in->data.dsize);
361         }
362 }
363
364 static int ctdb_rec_data_pull_data_old(uint8_t *buf, size_t buflen,
365                                        uint32_t *reqid,
366                                        struct ctdb_ltdb_header **header,
367                                        TDB_DATA *key, TDB_DATA *data,
368                                        size_t *reclen)
369 {
370         struct ctdb_rec_data_wire *wire = (struct ctdb_rec_data_wire *)buf;
371         size_t offset;
372
373         if (buflen < offsetof(struct ctdb_rec_data_wire, data)) {
374                 return EMSGSIZE;
375         }
376         if (wire->keylen > buflen || wire->datalen > buflen) {
377                 return EMSGSIZE;
378         }
379         if (offsetof(struct ctdb_rec_data_wire, data) + wire->keylen <
380             offsetof(struct ctdb_rec_data_wire, data)) {
381                 return EMSGSIZE;
382         }
383         if (offsetof(struct ctdb_rec_data_wire, data) +
384                 wire->keylen + wire->datalen <
385             offsetof(struct ctdb_rec_data_wire, data)) {
386                 return EMSGSIZE;
387         }
388         if (buflen < offsetof(struct ctdb_rec_data_wire, data) +
389                         wire->keylen + wire->datalen) {
390                 return EMSGSIZE;
391         }
392
393         *reqid = wire->reqid;
394
395         key->dsize = wire->keylen;
396         key->dptr = wire->data;
397         offset = wire->keylen;
398
399         /* Always set header to NULL.  If it is required, exact it using
400          * ctdb_rec_data_extract_header()
401          */
402         *header = NULL;
403
404         data->dsize = wire->datalen;
405         data->dptr = &wire->data[offset];
406
407         *reclen = offsetof(struct ctdb_rec_data_wire, data) +
408                         wire->keylen + wire->datalen;
409
410         return 0;
411 }
412
413 static int ctdb_rec_data_pull_elems_old(uint8_t *buf, size_t buflen,
414                                         TALLOC_CTX *mem_ctx,
415                                         struct ctdb_rec_data *out)
416 {
417         uint32_t reqid;
418         struct ctdb_ltdb_header *header;
419         TDB_DATA key, data;
420         size_t reclen;
421         int ret;
422
423         ret = ctdb_rec_data_pull_data_old(buf, buflen, &reqid, &header,
424                                           &key, &data, &reclen);
425         if (ret != 0) {
426                 return ret;
427         }
428
429         out->reqid = reqid;
430         out->header = NULL;
431
432         out->key.dsize = key.dsize;
433         if (key.dsize > 0) {
434                 out->key.dptr = talloc_memdup(mem_ctx, key.dptr, key.dsize);
435                 if (out->key.dptr == NULL) {
436                         return ENOMEM;
437                 }
438         }
439
440         out->data.dsize = data.dsize;
441         if (data.dsize > 0) {
442                 out->data.dptr = talloc_memdup(mem_ctx, data.dptr, data.dsize);
443                 if (out->data.dptr == NULL) {
444                         return ENOMEM;
445                 }
446         }
447
448         return 0;
449 }
450
451 static int ctdb_rec_data_pull_old(uint8_t *buf, size_t buflen,
452                                   TALLOC_CTX *mem_ctx,
453                                   struct ctdb_rec_data **out)
454 {
455         struct ctdb_rec_data *val;
456         int ret;
457
458         val = talloc(mem_ctx, struct ctdb_rec_data);
459         if (val == NULL) {
460                 return ENOMEM;
461         }
462
463         ret = ctdb_rec_data_pull_elems_old(buf, buflen, val, val);
464         if (ret != 0) {
465                 TALLOC_FREE(val);
466                 return ret;
467         }
468
469         *out = val;
470         return ret;
471 }
472
473 struct ctdb_rec_buffer_wire {
474         uint32_t db_id;
475         uint32_t count;
476         uint8_t data[1];
477 };
478
479 static size_t ctdb_rec_buffer_len_old(struct ctdb_rec_buffer *in)
480 {
481         return offsetof(struct ctdb_rec_buffer_wire, data) + in->buflen;
482 }
483
484 static void ctdb_rec_buffer_push_old(struct ctdb_rec_buffer *in, uint8_t *buf)
485 {
486         struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
487
488         wire->db_id = in->db_id;
489         wire->count = in->count;
490         if (in->buflen > 0) {
491                 memcpy(wire->data, in->buf, in->buflen);
492         }
493 }
494
495 static int ctdb_rec_buffer_pull_old(uint8_t *buf, size_t buflen,
496                                     TALLOC_CTX *mem_ctx,
497                                     struct ctdb_rec_buffer **out)
498 {
499         struct ctdb_rec_buffer *val;
500         struct ctdb_rec_buffer_wire *wire = (struct ctdb_rec_buffer_wire *)buf;
501         size_t offset;
502
503         if (buflen < offsetof(struct ctdb_rec_buffer_wire, data)) {
504                 return EMSGSIZE;
505         }
506
507         val = talloc(mem_ctx, struct ctdb_rec_buffer);
508         if (val == NULL) {
509                 return ENOMEM;
510         }
511
512         val->db_id = wire->db_id;
513         val->count = wire->count;
514
515         offset = offsetof(struct ctdb_rec_buffer_wire, data);
516         val->buflen = buflen - offset;
517         val->buf = talloc_memdup(val, wire->data, val->buflen);
518         if (val->buf == NULL) {
519                 talloc_free(val);
520                 return ENOMEM;
521         }
522
523         *out = val;
524         return 0;
525 }
526
527 static size_t ctdb_traverse_start_len_old(struct ctdb_traverse_start *in)
528 {
529         return sizeof(struct ctdb_traverse_start);
530 }
531
532 static void ctdb_traverse_start_push_old(struct ctdb_traverse_start *in,
533                                          uint8_t *buf)
534 {
535         memcpy(buf, in, sizeof(struct ctdb_traverse_start));
536 }
537
538 static int ctdb_traverse_start_pull_old(uint8_t *buf, size_t buflen,
539                                         TALLOC_CTX *mem_ctx,
540                                         struct ctdb_traverse_start **out)
541 {
542         struct ctdb_traverse_start *val;
543
544         if (buflen < sizeof(struct ctdb_traverse_start)) {
545                 return EMSGSIZE;
546         }
547
548         val = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_traverse_start));
549         if (val == NULL) {
550                 return ENOMEM;
551         }
552
553         *out = val;
554         return 0;
555 }
556
557 static size_t ctdb_traverse_all_len_old(struct ctdb_traverse_all *in)
558 {
559         return sizeof(struct ctdb_traverse_all);
560 }
561
562 static void ctdb_traverse_all_push_old(struct ctdb_traverse_all *in,
563                                        uint8_t *buf)
564 {
565         memcpy(buf, in, sizeof(struct ctdb_traverse_all));
566 }
567
568 static int ctdb_traverse_all_pull_old(uint8_t *buf, size_t buflen,
569                                       TALLOC_CTX *mem_ctx,
570                                       struct ctdb_traverse_all **out)
571 {
572         struct ctdb_traverse_all *val;
573
574         if (buflen < sizeof(struct ctdb_traverse_all)) {
575                 return EMSGSIZE;
576         }
577
578         val = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_traverse_all));
579         if (val == NULL) {
580                 return ENOMEM;
581         }
582
583         *out = val;
584         return 0;
585 }
586
587 static size_t ctdb_traverse_start_ext_len_old(
588                         struct ctdb_traverse_start_ext *in)
589 {
590         return sizeof(struct ctdb_traverse_start_ext);
591 }
592
593 static void ctdb_traverse_start_ext_push_old(
594                         struct ctdb_traverse_start_ext *in, uint8_t *buf)
595 {
596         memcpy(buf, in, sizeof(struct ctdb_traverse_start_ext));
597 }
598
599 static int ctdb_traverse_start_ext_pull_old(uint8_t *buf, size_t buflen,
600                                             TALLOC_CTX *mem_ctx,
601                                             struct ctdb_traverse_start_ext **out)
602 {
603         struct ctdb_traverse_start_ext *val;
604
605         if (buflen < sizeof(struct ctdb_traverse_start_ext)) {
606                 return EMSGSIZE;
607         }
608
609         val = talloc_memdup(mem_ctx, buf,
610                             sizeof(struct ctdb_traverse_start_ext));
611         if (val == NULL) {
612                 return ENOMEM;
613         }
614
615         *out = val;
616         return 0;
617 }
618
619 static size_t ctdb_traverse_all_ext_len_old(struct ctdb_traverse_all_ext *in)
620 {
621         return sizeof(struct ctdb_traverse_all_ext);
622 }
623
624 static void ctdb_traverse_all_ext_push_old(struct ctdb_traverse_all_ext *in,
625                                            uint8_t *buf)
626 {
627         memcpy(buf, in, sizeof(struct ctdb_traverse_all_ext));
628 }
629
630 static int ctdb_traverse_all_ext_pull_old(uint8_t *buf, size_t buflen,
631                                           TALLOC_CTX *mem_ctx,
632                                           struct ctdb_traverse_all_ext **out)
633 {
634         struct ctdb_traverse_all_ext *val;
635
636         if (buflen < sizeof(struct ctdb_traverse_all_ext)) {
637                 return EMSGSIZE;
638         }
639
640         val = talloc_memdup(mem_ctx, buf,
641                             sizeof(struct ctdb_traverse_all_ext));
642         if (val == NULL) {
643                 return ENOMEM;
644         }
645
646         *out = val;
647         return 0;
648 }
649
650 static size_t ctdb_sock_addr_len_old(ctdb_sock_addr *in)
651 {
652         return sizeof(ctdb_sock_addr);
653 }
654
655 static void ctdb_sock_addr_push_old(ctdb_sock_addr *in, uint8_t *buf)
656 {
657         memcpy(buf, in, sizeof(ctdb_sock_addr));
658 }
659
660 static int ctdb_sock_addr_pull_elems_old(uint8_t *buf, size_t buflen,
661                                          TALLOC_CTX *mem_ctx,
662                                          ctdb_sock_addr *out)
663 {
664         if (buflen < sizeof(ctdb_sock_addr)) {
665                 return EMSGSIZE;
666         }
667
668         memcpy(out, buf, sizeof(ctdb_sock_addr));
669
670         return 0;
671 }
672
673 static int ctdb_sock_addr_pull_old(uint8_t *buf, size_t buflen,
674                                    TALLOC_CTX *mem_ctx, ctdb_sock_addr **out)
675 {
676         ctdb_sock_addr *val;
677         int ret;
678
679         val = talloc(mem_ctx, ctdb_sock_addr);
680         if (val == NULL) {
681                 return ENOMEM;
682         }
683
684         ret = ctdb_sock_addr_pull_elems_old(buf, buflen, val, val);
685         if (ret != 0) {
686                 TALLOC_FREE(val);
687                 return ret;
688         }
689
690         *out = val;
691         return ret;
692 }
693
694 static size_t ctdb_connection_len_old(struct ctdb_connection *in)
695 {
696         return sizeof(struct ctdb_connection);
697 }
698
699 static void ctdb_connection_push_old(struct ctdb_connection *in, uint8_t *buf)
700 {
701         memcpy(buf, in, sizeof(struct ctdb_connection));
702 }
703
704 static int ctdb_connection_pull_elems_old(uint8_t *buf, size_t buflen,
705                                           TALLOC_CTX *mem_ctx,
706                                           struct ctdb_connection *out)
707 {
708         if (buflen < sizeof(struct ctdb_connection)) {
709                 return EMSGSIZE;
710         }
711
712         memcpy(out, buf, sizeof(struct ctdb_connection));
713
714         return 0;
715 }
716
717 static int ctdb_connection_pull_old(uint8_t *buf, size_t buflen,
718                                     TALLOC_CTX *mem_ctx,
719                                     struct ctdb_connection **out)
720 {
721         struct ctdb_connection *val;
722         int ret;
723
724         val = talloc(mem_ctx, struct ctdb_connection);
725         if (val == NULL) {
726                 return ENOMEM;
727         }
728
729         ret = ctdb_connection_pull_elems_old(buf, buflen, val, val);
730         if (ret != 0) {
731                 TALLOC_FREE(val);
732                 return ret;
733         }
734
735         *out = val;
736         return ret;
737 }
738
739 struct ctdb_tunable_wire {
740         uint32_t value;
741         uint32_t length;
742         uint8_t name[1];
743 };
744
745 static size_t ctdb_tunable_len_old(struct ctdb_tunable *in)
746 {
747         return offsetof(struct ctdb_tunable_wire, name) +
748                strlen(in->name) + 1;
749 }
750
751 static void ctdb_tunable_push_old(struct ctdb_tunable *in, uint8_t *buf)
752 {
753         struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
754
755         wire->value = in->value;
756         wire->length = strlen(in->name) + 1;
757         memcpy(wire->name, in->name, wire->length);
758 }
759
760 static int ctdb_tunable_pull_old(uint8_t *buf, size_t buflen,
761                                  TALLOC_CTX *mem_ctx,
762                                  struct ctdb_tunable **out)
763 {
764         struct ctdb_tunable *val;
765         struct ctdb_tunable_wire *wire = (struct ctdb_tunable_wire *)buf;
766
767         if (buflen < offsetof(struct ctdb_tunable_wire, name)) {
768                 return EMSGSIZE;
769         }
770         if (wire->length > buflen) {
771                 return EMSGSIZE;
772         }
773         if (offsetof(struct ctdb_tunable_wire, name) + wire->length <
774             offsetof(struct ctdb_tunable_wire, name)) {
775                 return EMSGSIZE;
776         }
777         if (buflen < offsetof(struct ctdb_tunable_wire, name) + wire->length) {
778                 return EMSGSIZE;
779         }
780
781         val = talloc(mem_ctx, struct ctdb_tunable);
782         if (val == NULL) {
783                 return ENOMEM;
784         }
785
786         val->value = wire->value;
787         val->name = talloc_memdup(val, wire->name, wire->length);
788         if (val->name == NULL) {
789                 talloc_free(val);
790                 return ENOMEM;
791         }
792
793         *out = val;
794         return 0;
795 }
796
797 static size_t ctdb_node_flag_change_len_old(struct ctdb_node_flag_change *in)
798 {
799         return sizeof(struct ctdb_node_flag_change);
800 }
801
802 static void ctdb_node_flag_change_push_old(struct ctdb_node_flag_change *in,
803                                            uint8_t *buf)
804 {
805         memcpy(buf, in, sizeof(struct ctdb_node_flag_change));
806 }
807
808 static int ctdb_node_flag_change_pull_old(uint8_t *buf, size_t buflen,
809                                           TALLOC_CTX *mem_ctx,
810                                           struct ctdb_node_flag_change **out)
811 {
812         struct ctdb_node_flag_change *val;
813
814         if (buflen < sizeof(struct ctdb_node_flag_change)) {
815                 return EMSGSIZE;
816         }
817
818         val = talloc_memdup(mem_ctx, buf,
819                             sizeof(struct ctdb_node_flag_change));
820         if (val == NULL) {
821                 return ENOMEM;
822         }
823
824         *out = val;
825         return 0;
826 }
827
828 struct ctdb_var_list_wire {
829         uint32_t length;
830         char list_str[1];
831 };
832
833 static size_t ctdb_var_list_len_old(struct ctdb_var_list *in)
834 {
835         int i;
836         size_t len = sizeof(uint32_t);
837
838         for (i=0; i<in->count; i++) {
839                 len += strlen(in->var[i]) + 1;
840         }
841         return len;
842 }
843
844 static void ctdb_var_list_push_old(struct ctdb_var_list *in, uint8_t *buf)
845 {
846         struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
847         int i, n;
848         size_t offset = 0;
849
850         if (in->count > 0) {
851                 n = sprintf(wire->list_str, "%s", in->var[0]);
852                 offset += n;
853         }
854         for (i=1; i<in->count; i++) {
855                 n = sprintf(&wire->list_str[offset], ":%s", in->var[i]);
856                 offset += n;
857         }
858         wire->length = offset + 1;
859 }
860
861 static int ctdb_var_list_pull_old(uint8_t *buf, size_t buflen,
862                                   TALLOC_CTX *mem_ctx,
863                                   struct ctdb_var_list **out)
864 {
865         struct ctdb_var_list *val = NULL;
866         struct ctdb_var_list_wire *wire = (struct ctdb_var_list_wire *)buf;
867         char *str, *s, *tok, *ptr;
868         const char **list;
869
870         if (buflen < sizeof(uint32_t)) {
871                 return EMSGSIZE;
872         }
873         if (wire->length > buflen) {
874                 return EMSGSIZE;
875         }
876         if (sizeof(uint32_t) + wire->length < sizeof(uint32_t)) {
877                 return EMSGSIZE;
878         }
879         if (buflen < sizeof(uint32_t) + wire->length) {
880                 return EMSGSIZE;
881         }
882
883         str = talloc_strndup(mem_ctx, (char *)wire->list_str, wire->length);
884         if (str == NULL) {
885                 return ENOMEM;
886         }
887
888         val = talloc_zero(mem_ctx, struct ctdb_var_list);
889         if (val == NULL) {
890                 goto fail;
891         }
892
893         s = str;
894         while ((tok = strtok_r(s, ":", &ptr)) != NULL) {
895                 s = NULL;
896                 list = talloc_realloc(val, val->var, const char *,
897                                       val->count+1);
898                 if (list == NULL) {
899                         goto fail;
900                 }
901
902                 val->var = list;
903                 val->var[val->count] = talloc_strdup(val, tok);
904                 if (val->var[val->count] == NULL) {
905                         goto fail;
906                 }
907                 val->count++;
908         }
909
910         talloc_free(str);
911         *out = val;
912         return 0;
913
914 fail:
915         talloc_free(str);
916         talloc_free(val);
917         return ENOMEM;
918 }
919
920 static size_t ctdb_tunable_list_len_old(struct ctdb_tunable_list *in)
921 {
922         return sizeof(struct ctdb_tunable_list);
923 }
924
925 static void ctdb_tunable_list_push_old(struct ctdb_tunable_list *in,
926                                        uint8_t *buf)
927 {
928         memcpy(buf, in, sizeof(struct ctdb_tunable_list));
929 }
930
931 static int ctdb_tunable_list_pull_old(uint8_t *buf, size_t buflen,
932                                       TALLOC_CTX *mem_ctx,
933                                       struct ctdb_tunable_list **out)
934 {
935         struct ctdb_tunable_list *val;
936
937         if (buflen < sizeof(struct ctdb_tunable_list)) {
938                 return EMSGSIZE;
939         }
940
941         val = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_tunable_list));
942         if (val == NULL) {
943                 return ENOMEM;
944         }
945
946         *out = val;
947         return 0;
948 }
949
950 struct ctdb_tickle_list_wire {
951         ctdb_sock_addr addr;
952         uint32_t num;
953         struct ctdb_connection conn[1];
954 };
955
956 static size_t ctdb_tickle_list_len_old(struct ctdb_tickle_list *in)
957 {
958         return offsetof(struct ctdb_tickle_list, conn) +
959                in->num * sizeof(struct ctdb_connection);
960 }
961
962 static void ctdb_tickle_list_push_old(struct ctdb_tickle_list *in,
963                                       uint8_t *buf)
964 {
965         struct ctdb_tickle_list_wire *wire =
966                 (struct ctdb_tickle_list_wire *)buf;
967         size_t offset;
968         int i;
969
970         memcpy(&wire->addr, &in->addr, sizeof(ctdb_sock_addr));
971         wire->num = in->num;
972
973         offset = offsetof(struct ctdb_tickle_list_wire, conn);
974         for (i=0; i<in->num; i++) {
975                 ctdb_connection_push_old(&in->conn[i], &buf[offset]);
976                 offset += ctdb_connection_len_old(&in->conn[i]);
977         }
978 }
979
980 static int ctdb_tickle_list_pull_old(uint8_t *buf, size_t buflen,
981                                      TALLOC_CTX *mem_ctx,
982                                      struct ctdb_tickle_list **out)
983 {
984         struct ctdb_tickle_list *val;
985         struct ctdb_tickle_list_wire *wire =
986                 (struct ctdb_tickle_list_wire *)buf;
987         size_t offset;
988         int i, ret;
989
990         if (buflen < offsetof(struct ctdb_tickle_list_wire, conn)) {
991                 return EMSGSIZE;
992         }
993         if (wire->num > buflen / sizeof(struct ctdb_connection)) {
994                 return EMSGSIZE;
995         }
996         if (offsetof(struct ctdb_tickle_list_wire, conn) +
997             wire->num * sizeof(struct ctdb_connection) <
998             offsetof(struct ctdb_tickle_list_wire, conn)) {
999                 return EMSGSIZE;
1000         }
1001         if (buflen < offsetof(struct ctdb_tickle_list_wire, conn) +
1002                      wire->num * sizeof(struct ctdb_connection)) {
1003                 return EMSGSIZE;
1004         }
1005
1006         val = talloc(mem_ctx, struct ctdb_tickle_list);
1007         if (val == NULL) {
1008                 return ENOMEM;
1009         }
1010
1011         offset = offsetof(struct ctdb_tickle_list, conn);
1012         memcpy(val, wire, offset);
1013
1014         val->conn = talloc_array(val, struct ctdb_connection, wire->num);
1015         if (val->conn == NULL) {
1016                 talloc_free(val);
1017                 return ENOMEM;
1018         }
1019
1020         for (i=0; i<wire->num; i++) {
1021                 ret = ctdb_connection_pull_elems_old(&buf[offset],
1022                                                      buflen-offset,
1023                                                      val->conn,
1024                                                      &val->conn[i]);
1025                 if (ret != 0) {
1026                         talloc_free(val);
1027                         return ret;
1028                 }
1029                 offset += ctdb_connection_len_old(&val->conn[i]);
1030         }
1031
1032         *out = val;
1033         return 0;
1034 }
1035
1036 struct ctdb_addr_info_wire {
1037         ctdb_sock_addr addr;
1038         uint32_t mask;
1039         uint32_t len;
1040         char iface[1];
1041 };
1042
1043 static size_t ctdb_addr_info_len_old(struct ctdb_addr_info *in)
1044 {
1045         uint32_t len;
1046
1047         len = offsetof(struct ctdb_addr_info_wire, iface);
1048         if (in->iface != NULL) {
1049                len += strlen(in->iface)+1;
1050         }
1051
1052         return len;
1053 }
1054
1055 static void ctdb_addr_info_push_old(struct ctdb_addr_info *in, uint8_t *buf)
1056 {
1057         struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
1058
1059         wire->addr = in->addr;
1060         wire->mask = in->mask;
1061         if (in->iface == NULL) {
1062                 wire->len = 0;
1063         } else {
1064                 wire->len = strlen(in->iface)+1;
1065                 memcpy(wire->iface, in->iface, wire->len);
1066         }
1067 }
1068
1069 static int ctdb_addr_info_pull_old(uint8_t *buf, size_t buflen,
1070                                    TALLOC_CTX *mem_ctx,
1071                                    struct ctdb_addr_info **out)
1072 {
1073         struct ctdb_addr_info *val;
1074         struct ctdb_addr_info_wire *wire = (struct ctdb_addr_info_wire *)buf;
1075
1076         if (buflen < offsetof(struct ctdb_addr_info_wire, iface)) {
1077                 return EMSGSIZE;
1078         }
1079         if (wire->len > buflen) {
1080                 return EMSGSIZE;
1081         }
1082         if (offsetof(struct ctdb_addr_info_wire, iface) + wire->len <
1083             offsetof(struct ctdb_addr_info_wire, iface)) {
1084                 return EMSGSIZE;
1085         }
1086         if (buflen < offsetof(struct ctdb_addr_info_wire, iface) + wire->len) {
1087                 return EMSGSIZE;
1088         }
1089
1090         val = talloc(mem_ctx, struct ctdb_addr_info);
1091         if (val == NULL) {
1092                 return ENOMEM;
1093         }
1094
1095         val->addr = wire->addr;
1096         val->mask = wire->mask;
1097
1098         if (wire->len == 0) {
1099                 val->iface = NULL;
1100         } else {
1101                 val->iface = talloc_strndup(val, wire->iface, wire->len);
1102                 if (val->iface == NULL) {
1103                         talloc_free(val);
1104                         return ENOMEM;
1105                 }
1106         }
1107
1108         *out = val;
1109         return 0;
1110 }
1111
1112 static size_t ctdb_transdb_len_old(struct ctdb_transdb *in)
1113 {
1114         return sizeof(struct ctdb_transdb);
1115 }
1116
1117 static void ctdb_transdb_push_old(struct ctdb_transdb *in, uint8_t *buf)
1118 {
1119         memcpy(buf, in, sizeof(struct ctdb_transdb));
1120 }
1121
1122 static int ctdb_transdb_pull_old(uint8_t *buf, size_t buflen,
1123                                  TALLOC_CTX *mem_ctx,
1124                                  struct ctdb_transdb **out)
1125 {
1126         struct ctdb_transdb *val;
1127
1128         if (buflen < sizeof(struct ctdb_transdb)) {
1129                 return EMSGSIZE;
1130         }
1131
1132         val = talloc_memdup(mem_ctx, buf, sizeof(struct ctdb_transdb));
1133         if (val == NULL) {
1134                 return ENOMEM;
1135         }
1136
1137         *out = val;
1138         return 0;
1139 }
1140
1141
1142 COMPAT_TYPE3_TEST(struct ctdb_statistics, ctdb_statistics);
1143 COMPAT_TYPE3_TEST(struct ctdb_vnn_map, ctdb_vnn_map);
1144 COMPAT_TYPE3_TEST(struct ctdb_dbid_map, ctdb_dbid_map);
1145 COMPAT_TYPE3_TEST(struct ctdb_pulldb, ctdb_pulldb);
1146 COMPAT_TYPE3_TEST(struct ctdb_pulldb_ext, ctdb_pulldb_ext);
1147
1148 COMPAT_TYPE1_TEST(struct ctdb_ltdb_header, ctdb_ltdb_header);
1149
1150 COMPAT_TYPE3_TEST(struct ctdb_rec_data, ctdb_rec_data);
1151 COMPAT_TYPE3_TEST(struct ctdb_rec_buffer, ctdb_rec_buffer);
1152 COMPAT_TYPE3_TEST(struct ctdb_traverse_start, ctdb_traverse_start);
1153 COMPAT_TYPE3_TEST(struct ctdb_traverse_all, ctdb_traverse_all);
1154 COMPAT_TYPE3_TEST(struct ctdb_traverse_start_ext, ctdb_traverse_start_ext);
1155 COMPAT_TYPE3_TEST(struct ctdb_traverse_all_ext, ctdb_traverse_all_ext);
1156 COMPAT_TYPE3_TEST(ctdb_sock_addr, ctdb_sock_addr);
1157 COMPAT_TYPE3_TEST(struct ctdb_connection, ctdb_connection);
1158 COMPAT_TYPE3_TEST(struct ctdb_tunable, ctdb_tunable);
1159 COMPAT_TYPE3_TEST(struct ctdb_node_flag_change, ctdb_node_flag_change);
1160 COMPAT_TYPE3_TEST(struct ctdb_var_list, ctdb_var_list);
1161 COMPAT_TYPE3_TEST(struct ctdb_tunable_list, ctdb_tunable_list);
1162 COMPAT_TYPE3_TEST(struct ctdb_tickle_list, ctdb_tickle_list);
1163 COMPAT_TYPE3_TEST(struct ctdb_addr_info, ctdb_addr_info);
1164 COMPAT_TYPE3_TEST(struct ctdb_transdb, ctdb_transdb);
1165
1166 int main(int argc, char *argv[])
1167 {
1168         if (argc == 2) {
1169                 int seed = atoi(argv[1]);
1170                 srandom(seed);
1171         }
1172
1173         COMPAT_TEST_FUNC(ctdb_statistics)();
1174         COMPAT_TEST_FUNC(ctdb_vnn_map)();
1175         COMPAT_TEST_FUNC(ctdb_dbid_map)();
1176         COMPAT_TEST_FUNC(ctdb_pulldb)();
1177         COMPAT_TEST_FUNC(ctdb_pulldb_ext)();
1178         COMPAT_TEST_FUNC(ctdb_ltdb_header)();
1179         COMPAT_TEST_FUNC(ctdb_rec_data)();
1180         COMPAT_TEST_FUNC(ctdb_rec_buffer)();
1181         COMPAT_TEST_FUNC(ctdb_traverse_start)();
1182         COMPAT_TEST_FUNC(ctdb_traverse_all)();
1183         COMPAT_TEST_FUNC(ctdb_traverse_start_ext)();
1184         COMPAT_TEST_FUNC(ctdb_traverse_all_ext)();
1185         COMPAT_TEST_FUNC(ctdb_sock_addr)();
1186         COMPAT_TEST_FUNC(ctdb_connection)();
1187         COMPAT_TEST_FUNC(ctdb_tunable)();
1188         COMPAT_TEST_FUNC(ctdb_node_flag_change)();
1189         COMPAT_TEST_FUNC(ctdb_var_list)();
1190         COMPAT_TEST_FUNC(ctdb_tunable_list)();
1191         COMPAT_TEST_FUNC(ctdb_tickle_list)();
1192         COMPAT_TEST_FUNC(ctdb_addr_info)();
1193         COMPAT_TEST_FUNC(ctdb_transdb)();
1194
1195         return 0;
1196 }