ctdb-protocol: Fix marshalling for ctdb_node_flag_change
[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
829 COMPAT_TYPE3_TEST(struct ctdb_statistics, ctdb_statistics);
830 COMPAT_TYPE3_TEST(struct ctdb_vnn_map, ctdb_vnn_map);
831 COMPAT_TYPE3_TEST(struct ctdb_dbid_map, ctdb_dbid_map);
832 COMPAT_TYPE3_TEST(struct ctdb_pulldb, ctdb_pulldb);
833 COMPAT_TYPE3_TEST(struct ctdb_pulldb_ext, ctdb_pulldb_ext);
834
835 COMPAT_TYPE1_TEST(struct ctdb_ltdb_header, ctdb_ltdb_header);
836
837 COMPAT_TYPE3_TEST(struct ctdb_rec_data, ctdb_rec_data);
838 COMPAT_TYPE3_TEST(struct ctdb_rec_buffer, ctdb_rec_buffer);
839 COMPAT_TYPE3_TEST(struct ctdb_traverse_start, ctdb_traverse_start);
840 COMPAT_TYPE3_TEST(struct ctdb_traverse_all, ctdb_traverse_all);
841 COMPAT_TYPE3_TEST(struct ctdb_traverse_start_ext, ctdb_traverse_start_ext);
842 COMPAT_TYPE3_TEST(struct ctdb_traverse_all_ext, ctdb_traverse_all_ext);
843 COMPAT_TYPE3_TEST(ctdb_sock_addr, ctdb_sock_addr);
844 COMPAT_TYPE3_TEST(struct ctdb_connection, ctdb_connection);
845 COMPAT_TYPE3_TEST(struct ctdb_tunable, ctdb_tunable);
846 COMPAT_TYPE3_TEST(struct ctdb_node_flag_change, ctdb_node_flag_change);
847
848 int main(int argc, char *argv[])
849 {
850         if (argc == 2) {
851                 int seed = atoi(argv[1]);
852                 srandom(seed);
853         }
854
855         COMPAT_TEST_FUNC(ctdb_statistics)();
856         COMPAT_TEST_FUNC(ctdb_vnn_map)();
857         COMPAT_TEST_FUNC(ctdb_dbid_map)();
858         COMPAT_TEST_FUNC(ctdb_pulldb)();
859         COMPAT_TEST_FUNC(ctdb_pulldb_ext)();
860         COMPAT_TEST_FUNC(ctdb_ltdb_header)();
861         COMPAT_TEST_FUNC(ctdb_rec_data)();
862         COMPAT_TEST_FUNC(ctdb_rec_buffer)();
863         COMPAT_TEST_FUNC(ctdb_traverse_start)();
864         COMPAT_TEST_FUNC(ctdb_traverse_all)();
865         COMPAT_TEST_FUNC(ctdb_traverse_start_ext)();
866         COMPAT_TEST_FUNC(ctdb_traverse_all_ext)();
867         COMPAT_TEST_FUNC(ctdb_sock_addr)();
868         COMPAT_TEST_FUNC(ctdb_connection)();
869         COMPAT_TEST_FUNC(ctdb_tunable)();
870         COMPAT_TEST_FUNC(ctdb_node_flag_change)();
871
872         return 0;
873 }