ldb:kv_index: use subtransaction_cancel in transaction_cancel
[samba.git] / ctdb / tests / src / protocol_ctdb_compat_test.c
blobfc9f82e8230e28ed67d4d9792f36084e851f3e6f
1 /*
2 ctdb protocol backward compatibility test
4 Copyright (C) Amitay Isaacs 2017
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.
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.
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/>.
20 #include "replace.h"
21 #include "system/filesys.h"
23 #include <assert.h>
25 #include "protocol/protocol_basic.c"
26 #include "protocol/protocol_types.c"
27 #include "protocol/protocol_header.c"
28 #include "protocol/protocol_call.c"
29 #include "protocol/protocol_control.c"
30 #include "protocol/protocol_message.c"
31 #include "protocol/protocol_keepalive.c"
32 #include "protocol/protocol_tunnel.c"
34 #include "tests/src/protocol_common.h"
35 #include "tests/src/protocol_common_ctdb.h"
37 #define COMPAT_TEST_FUNC(NAME) test_ ##NAME## _compat
38 #define OLD_LEN_FUNC(NAME) NAME## _len_old
39 #define OLD_PUSH_FUNC(NAME) NAME## _push_old
40 #define OLD_PULL_FUNC(NAME) NAME## _pull_old
42 #define COMPAT_CTDB1_TEST(TYPE, NAME) \
43 static void COMPAT_TEST_FUNC(NAME)(void) \
44 { \
45 TALLOC_CTX *mem_ctx; \
46 uint8_t *buf1, *buf2; \
47 TYPE p = { 0 }, p1, p2; \
48 size_t buflen1, buflen2, np = 0; \
49 int ret; \
51 mem_ctx = talloc_new(NULL); \
52 assert(mem_ctx != NULL); \
53 FILL_FUNC(NAME)(&p); \
54 buflen1 = LEN_FUNC(NAME)(&p); \
55 buflen2 = OLD_LEN_FUNC(NAME)(&p); \
56 assert(buflen1 == buflen2); \
57 buf1 = talloc_zero_size(mem_ctx, buflen1); \
58 assert(buf1 != NULL); \
59 buf2 = talloc_zero_size(mem_ctx, buflen2); \
60 assert(buf2 != NULL); \
61 PUSH_FUNC(NAME)(&p, buf1, &np); \
62 OLD_PUSH_FUNC(NAME)(&p, buf2); \
63 assert(memcmp(buf1, buf2, buflen1) == 0); \
64 ret = PULL_FUNC(NAME)(buf1, buflen1, &p1, &np); \
65 assert(ret == 0); \
66 ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &p2); \
67 assert(ret == 0); \
68 VERIFY_FUNC(NAME)(&p1, &p2); \
69 talloc_free(mem_ctx); \
72 #define COMPAT_CTDB4_TEST(TYPE, NAME, OPER) \
73 static void COMPAT_TEST_FUNC(NAME)(void) \
74 { \
75 TALLOC_CTX *mem_ctx; \
76 uint8_t *buf1, *buf2; \
77 struct ctdb_req_header h, h1, h2; \
78 TYPE p = { 0 }, p1, p2; \
79 size_t buflen1, buflen2; \
80 int ret; \
82 mem_ctx = talloc_new(NULL); \
83 assert(mem_ctx != NULL); \
84 fill_ctdb_req_header(&h); \
85 FILL_FUNC(NAME)(mem_ctx, &p); \
86 buflen1 = LEN_FUNC(NAME)(&h, &p); \
87 buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
88 assert(buflen1 == buflen2); \
89 buf1 = talloc_zero_size(mem_ctx, buflen1); \
90 assert(buf1 != NULL); \
91 buf2 = talloc_zero_size(mem_ctx, buflen2); \
92 assert(buf2 != NULL); \
93 ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
94 assert(ret == 0); \
95 ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
96 assert(ret == 0); \
97 assert(memcmp(buf1, buf2, buflen1) == 0); \
98 ret = PULL_FUNC(NAME)(buf1, buflen1, &h1, mem_ctx, &p1); \
99 assert(ret == 0); \
100 ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &h2, mem_ctx, &p2); \
101 assert(ret == 0); \
102 verify_ctdb_req_header(&h1, &h2); \
103 VERIFY_FUNC(NAME)(&p1, &p2); \
104 talloc_free(mem_ctx); \
107 #define COMPAT_CTDB5_TEST(TYPE, NAME, OPER) \
108 static void COMPAT_TEST_FUNC(NAME)(uint32_t opcode) \
110 TALLOC_CTX *mem_ctx; \
111 uint8_t *buf1, *buf2; \
112 struct ctdb_req_header h, h1, h2; \
113 TYPE p = { 0 }, p1, p2; \
114 size_t buflen1, buflen2; \
115 int ret; \
117 mem_ctx = talloc_new(NULL); \
118 assert(mem_ctx != NULL); \
119 fill_ctdb_req_header(&h); \
120 FILL_FUNC(NAME)(mem_ctx, &p, opcode); \
121 buflen1 = LEN_FUNC(NAME)(&h, &p); \
122 buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
123 assert(buflen1 == buflen2); \
124 buf1 = talloc_zero_size(mem_ctx, buflen1); \
125 assert(buf1 != NULL); \
126 buf2 = talloc_zero_size(mem_ctx, buflen2); \
127 assert(buf2 != NULL); \
128 ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
129 assert(ret == 0); \
130 ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
131 assert(ret == 0); \
132 assert(memcmp(buf1, buf2, buflen1) == 0); \
133 ret = PULL_FUNC(NAME)(buf1, buflen1, &h1, mem_ctx, &p1); \
134 assert(ret == 0); \
135 ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &h2, mem_ctx, &p2); \
136 assert(ret == 0); \
137 verify_ctdb_req_header(&h1, &h2); \
138 VERIFY_FUNC(NAME)(&p1, &p2); \
139 talloc_free(mem_ctx); \
142 #define COMPAT_CTDB6_TEST(TYPE, NAME, OPER) \
143 static void COMPAT_TEST_FUNC(NAME)(uint32_t opcode) \
145 TALLOC_CTX *mem_ctx; \
146 uint8_t *buf1, *buf2; \
147 struct ctdb_req_header h, h1, h2; \
148 TYPE p = { 0 }, p1, p2; \
149 size_t buflen1, buflen2; \
150 int ret; \
152 mem_ctx = talloc_new(NULL); \
153 assert(mem_ctx != NULL); \
154 fill_ctdb_req_header(&h); \
155 FILL_FUNC(NAME)(mem_ctx, &p, opcode); \
156 buflen1 = LEN_FUNC(NAME)(&h, &p); \
157 buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
158 assert(buflen1 == buflen2); \
159 buf1 = talloc_zero_size(mem_ctx, buflen1); \
160 assert(buf1 != NULL); \
161 buf2 = talloc_zero_size(mem_ctx, buflen2); \
162 assert(buf2 != NULL); \
163 ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
164 assert(ret == 0); \
165 ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
166 assert(ret == 0); \
167 assert(memcmp(buf1, buf2, buflen1) == 0); \
168 ret = PULL_FUNC(NAME)(buf1, buflen1, opcode, &h1, mem_ctx, &p1); \
169 assert(ret == 0); \
170 ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, opcode, &h2, mem_ctx, &p2); \
171 assert(ret == 0); \
172 verify_ctdb_req_header(&h1, &h2); \
173 VERIFY_FUNC(NAME)(&p1, &p2); \
174 talloc_free(mem_ctx); \
177 #define COMPAT_CTDB7_TEST(TYPE, NAME, OPER) \
178 static void COMPAT_TEST_FUNC(NAME)(uint64_t srvid) \
180 TALLOC_CTX *mem_ctx; \
181 uint8_t *buf1, *buf2; \
182 struct ctdb_req_header h, h1, h2; \
183 TYPE p = { 0 }, p1, p2; \
184 size_t buflen1, buflen2; \
185 int ret; \
187 mem_ctx = talloc_new(NULL); \
188 assert(mem_ctx != NULL); \
189 fill_ctdb_req_header(&h); \
190 FILL_FUNC(NAME)(mem_ctx, &p, srvid); \
191 buflen1 = LEN_FUNC(NAME)(&h, &p); \
192 buflen2 = OLD_LEN_FUNC(NAME)(&h, &p); \
193 assert(buflen1 == buflen2); \
194 buf1 = talloc_zero_size(mem_ctx, buflen1); \
195 assert(buf1 != NULL); \
196 buf2 = talloc_zero_size(mem_ctx, buflen2); \
197 assert(buf2 != NULL); \
198 ret = PUSH_FUNC(NAME)(&h, &p, buf1, &buflen1); \
199 assert(ret == 0); \
200 ret = OLD_PUSH_FUNC(NAME)(&h, &p, buf2, &buflen2); \
201 assert(ret == 0); \
202 assert(memcmp(buf1, buf2, buflen1) == 0); \
203 ret = PULL_FUNC(NAME)(buf1, buflen1, &h1, mem_ctx, &p1); \
204 assert(ret == 0); \
205 ret = OLD_PULL_FUNC(NAME)(buf2, buflen2, &h2, mem_ctx, &p2); \
206 assert(ret == 0); \
207 verify_ctdb_req_header(&h1, &h2); \
208 VERIFY_FUNC(NAME)(&p1, &p2); \
209 talloc_free(mem_ctx); \
213 static size_t ctdb_req_header_len_old(struct ctdb_req_header *in)
215 return sizeof(struct ctdb_req_header);
218 static void ctdb_req_header_push_old(struct ctdb_req_header *in, uint8_t *buf)
220 memcpy(buf, in, sizeof(struct ctdb_req_header));
223 static int ctdb_req_header_pull_old(uint8_t *buf, size_t buflen,
224 struct ctdb_req_header *out)
226 if (buflen < sizeof(struct ctdb_req_header)) {
227 return EMSGSIZE;
230 memcpy(out, buf, sizeof(struct ctdb_req_header));
231 return 0;
234 struct ctdb_req_call_wire {
235 struct ctdb_req_header hdr;
236 uint32_t flags;
237 uint32_t db_id;
238 uint32_t callid;
239 uint32_t hopcount;
240 uint32_t keylen;
241 uint32_t calldatalen;
242 uint8_t data[1]; /* key[] followed by calldata[] */
245 static size_t ctdb_req_call_len_old(struct ctdb_req_header *h,
246 struct ctdb_req_call *c)
248 return offsetof(struct ctdb_req_call_wire, data) +
249 ctdb_tdb_data_len(&c->key) +
250 ctdb_tdb_data_len(&c->calldata);
253 static int ctdb_req_call_push_old(struct ctdb_req_header *h,
254 struct ctdb_req_call *c,
255 uint8_t *buf, size_t *buflen)
257 struct ctdb_req_call_wire *wire =
258 (struct ctdb_req_call_wire *)buf;
259 size_t length, np;
261 if (c->key.dsize == 0) {
262 return EINVAL;
265 length = ctdb_req_call_len_old(h, c);
266 if (*buflen < length) {
267 *buflen = length;
268 return EMSGSIZE;
271 h->length = *buflen;
272 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
274 wire->flags = c->flags;
275 wire->db_id = c->db_id;
276 wire->callid = c->callid;
277 wire->hopcount = c->hopcount;
278 wire->keylen = ctdb_tdb_data_len(&c->key);
279 wire->calldatalen = ctdb_tdb_data_len(&c->calldata);
280 ctdb_tdb_data_push(&c->key, wire->data, &np);
281 ctdb_tdb_data_push(&c->calldata, wire->data + wire->keylen, &np);
283 return 0;
286 static int ctdb_req_call_pull_old(uint8_t *buf, size_t buflen,
287 struct ctdb_req_header *h,
288 TALLOC_CTX *mem_ctx,
289 struct ctdb_req_call *c)
291 struct ctdb_req_call_wire *wire =
292 (struct ctdb_req_call_wire *)buf;
293 size_t length, np;
294 int ret;
296 length = offsetof(struct ctdb_req_call_wire, data);
297 if (buflen < length) {
298 return EMSGSIZE;
300 if (wire->keylen > buflen || wire->calldatalen > buflen) {
301 return EMSGSIZE;
303 if (length + wire->keylen < length) {
304 return EMSGSIZE;
306 if (length + wire->keylen + wire->calldatalen < length) {
307 return EMSGSIZE;
309 if (buflen < length + wire->keylen + wire->calldatalen) {
310 return EMSGSIZE;
313 if (h != NULL) {
314 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
316 if (ret != 0) {
317 return ret;
321 c->flags = wire->flags;
322 c->db_id = wire->db_id;
323 c->callid = wire->callid;
324 c->hopcount = wire->hopcount;
326 ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key,
327 &np);
328 if (ret != 0) {
329 return ret;
332 ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->calldatalen,
333 mem_ctx, &c->calldata, &np);
334 if (ret != 0) {
335 return ret;
338 return 0;
341 struct ctdb_reply_call_wire {
342 struct ctdb_req_header hdr;
343 uint32_t status;
344 uint32_t datalen;
345 uint8_t data[1];
348 static size_t ctdb_reply_call_len_old(struct ctdb_req_header *h,
349 struct ctdb_reply_call *c)
351 return offsetof(struct ctdb_reply_call_wire, data) +
352 ctdb_tdb_data_len(&c->data);
355 static int ctdb_reply_call_push_old(struct ctdb_req_header *h,
356 struct ctdb_reply_call *c,
357 uint8_t *buf, size_t *buflen)
359 struct ctdb_reply_call_wire *wire =
360 (struct ctdb_reply_call_wire *)buf;
361 size_t length, np;
363 length = ctdb_reply_call_len_old(h, c);
364 if (*buflen < length) {
365 *buflen = length;
366 return EMSGSIZE;
369 h->length = *buflen;
370 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
372 wire->status = c->status;
373 wire->datalen = ctdb_tdb_data_len(&c->data);
374 ctdb_tdb_data_push(&c->data, wire->data, &np);
376 return 0;
379 static int ctdb_reply_call_pull_old(uint8_t *buf, size_t buflen,
380 struct ctdb_req_header *h,
381 TALLOC_CTX *mem_ctx,
382 struct ctdb_reply_call *c)
384 struct ctdb_reply_call_wire *wire =
385 (struct ctdb_reply_call_wire *)buf;
386 size_t length, np;
387 int ret;
389 length = offsetof(struct ctdb_reply_call_wire, data);
390 if (buflen < length) {
391 return EMSGSIZE;
393 if (wire->datalen > buflen) {
394 return EMSGSIZE;
396 if (length + wire->datalen < length) {
397 return EMSGSIZE;
399 if (buflen < length + wire->datalen) {
400 return EMSGSIZE;
403 if (h != NULL) {
404 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
406 if (ret != 0) {
407 return ret;
411 c->status = wire->status;
413 ret = ctdb_tdb_data_pull(wire->data, wire->datalen, mem_ctx, &c->data,
414 &np);
415 if (ret != 0) {
416 return ret;
419 return 0;
422 struct ctdb_reply_error_wire {
423 struct ctdb_req_header hdr;
424 uint32_t status;
425 uint32_t msglen;
426 uint8_t msg[1];
429 static size_t ctdb_reply_error_len_old(struct ctdb_req_header *h,
430 struct ctdb_reply_error *c)
432 return offsetof(struct ctdb_reply_error_wire, msg) +
433 ctdb_tdb_data_len(&c->msg);
436 static int ctdb_reply_error_push_old(struct ctdb_req_header *h,
437 struct ctdb_reply_error *c,
438 uint8_t *buf, size_t *buflen)
440 struct ctdb_reply_error_wire *wire =
441 (struct ctdb_reply_error_wire *)buf;
442 size_t length, np;
444 length = ctdb_reply_error_len_old(h, c);
445 if (*buflen < length) {
446 *buflen = length;
447 return EMSGSIZE;
450 h->length = *buflen;
451 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
453 wire->status = c->status;
454 wire->msglen = ctdb_tdb_data_len(&c->msg);
455 ctdb_tdb_data_push(&c->msg, wire->msg, &np);
457 return 0;
460 static int ctdb_reply_error_pull_old(uint8_t *buf, size_t buflen,
461 struct ctdb_req_header *h,
462 TALLOC_CTX *mem_ctx,
463 struct ctdb_reply_error *c)
465 struct ctdb_reply_error_wire *wire =
466 (struct ctdb_reply_error_wire *)buf;
467 size_t length, np;
468 int ret;
470 length = offsetof(struct ctdb_reply_error_wire, msg);
471 if (buflen < length) {
472 return EMSGSIZE;
474 if (wire->msglen > buflen) {
475 return EMSGSIZE;
477 if (length + wire->msglen < length) {
478 return EMSGSIZE;
480 if (buflen < length + wire->msglen) {
481 return EMSGSIZE;
484 if (h != NULL) {
485 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
487 if (ret != 0) {
488 return ret;
492 c->status = wire->status;
494 ret = ctdb_tdb_data_pull(wire->msg, wire->msglen, mem_ctx, &c->msg,
495 &np);
496 if (ret != 0) {
497 return ret;
500 return 0;
503 struct ctdb_req_dmaster_wire {
504 struct ctdb_req_header hdr;
505 uint32_t db_id;
506 uint64_t rsn;
507 uint32_t dmaster;
508 uint32_t keylen;
509 uint32_t datalen;
510 uint8_t data[1];
513 static size_t ctdb_req_dmaster_len_old(struct ctdb_req_header *h,
514 struct ctdb_req_dmaster *c)
516 return offsetof(struct ctdb_req_dmaster_wire, data) +
517 ctdb_tdb_data_len(&c->key) + ctdb_tdb_data_len(&c->data);
520 static int ctdb_req_dmaster_push_old(struct ctdb_req_header *h,
521 struct ctdb_req_dmaster *c,
522 uint8_t *buf, size_t *buflen)
524 struct ctdb_req_dmaster_wire *wire =
525 (struct ctdb_req_dmaster_wire *)buf;
526 size_t length, np;
528 length = ctdb_req_dmaster_len_old(h, c);
529 if (*buflen < length) {
530 *buflen = length;
531 return EMSGSIZE;
534 h->length = *buflen;
535 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
537 wire->db_id = c->db_id;
538 wire->rsn = c->rsn;
539 wire->dmaster = c->dmaster;
540 wire->keylen = ctdb_tdb_data_len(&c->key);
541 wire->datalen = ctdb_tdb_data_len(&c->data);
542 ctdb_tdb_data_push(&c->key, wire->data, &np);
543 ctdb_tdb_data_push(&c->data, wire->data + wire->keylen, &np);
545 return 0;
548 static int ctdb_req_dmaster_pull_old(uint8_t *buf, size_t buflen,
549 struct ctdb_req_header *h,
550 TALLOC_CTX *mem_ctx,
551 struct ctdb_req_dmaster *c)
553 struct ctdb_req_dmaster_wire *wire =
554 (struct ctdb_req_dmaster_wire *)buf;
555 size_t length, np;
556 int ret;
558 length = offsetof(struct ctdb_req_dmaster_wire, data);
559 if (buflen < length) {
560 return EMSGSIZE;
562 if (wire->keylen > buflen || wire->datalen > buflen) {
563 return EMSGSIZE;
565 if (length + wire->keylen < length) {
566 return EMSGSIZE;
568 if (length + wire->keylen + wire->datalen < length) {
569 return EMSGSIZE;
571 if (buflen < length + wire->keylen + wire->datalen) {
572 return EMSGSIZE;
575 if (h != NULL) {
576 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
578 if (ret != 0) {
579 return ret;
583 c->db_id = wire->db_id;
584 c->rsn = wire->rsn;
585 c->dmaster = wire->dmaster;
587 ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key,
588 &np);
589 if (ret != 0) {
590 return ret;
593 ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen,
594 mem_ctx, &c->data, &np);
595 if (ret != 0) {
596 return ret;
599 return 0;
602 struct ctdb_reply_dmaster_wire {
603 struct ctdb_req_header hdr;
604 uint32_t db_id;
605 uint64_t rsn;
606 uint32_t keylen;
607 uint32_t datalen;
608 uint8_t data[1];
611 static size_t ctdb_reply_dmaster_len_old(struct ctdb_req_header *h,
612 struct ctdb_reply_dmaster *c)
614 return offsetof(struct ctdb_reply_dmaster_wire, data) +
615 ctdb_tdb_data_len(&c->key) + ctdb_tdb_data_len(&c->data);
618 static int ctdb_reply_dmaster_push_old(struct ctdb_req_header *h,
619 struct ctdb_reply_dmaster *c,
620 uint8_t *buf, size_t *buflen)
622 struct ctdb_reply_dmaster_wire *wire =
623 (struct ctdb_reply_dmaster_wire *)buf;
624 size_t length, np;
626 length = ctdb_reply_dmaster_len_old(h, c);
627 if (*buflen < length) {
628 *buflen = length;
629 return EMSGSIZE;
632 h->length = *buflen;
633 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
635 wire->db_id = c->db_id;
636 wire->rsn = c->rsn;
637 wire->keylen = ctdb_tdb_data_len(&c->key);
638 wire->datalen = ctdb_tdb_data_len(&c->data);
639 ctdb_tdb_data_push(&c->key, wire->data, &np);
640 ctdb_tdb_data_push(&c->data, wire->data + wire->keylen, &np);
642 return 0;
645 static int ctdb_reply_dmaster_pull_old(uint8_t *buf, size_t buflen,
646 struct ctdb_req_header *h,
647 TALLOC_CTX *mem_ctx,
648 struct ctdb_reply_dmaster *c)
650 struct ctdb_reply_dmaster_wire *wire =
651 (struct ctdb_reply_dmaster_wire *)buf;
652 size_t length, np;
653 int ret;
655 length = offsetof(struct ctdb_reply_dmaster_wire, data);
656 if (buflen < length) {
657 return EMSGSIZE;
659 if (wire->keylen > buflen || wire->datalen > buflen) {
660 return EMSGSIZE;
662 if (length + wire->keylen < length) {
663 return EMSGSIZE;
665 if (length + wire->keylen + wire->datalen < length) {
666 return EMSGSIZE;
668 if (buflen < length + wire->keylen + wire->datalen) {
669 return EMSGSIZE;
672 if (h != NULL) {
673 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
675 if (ret != 0) {
676 return ret;
680 c->db_id = wire->db_id;
681 c->rsn = wire->rsn;
683 ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key,
684 &np);
685 if (ret != 0) {
686 return ret;
689 ret = ctdb_tdb_data_pull(wire->data + wire->keylen, wire->datalen,
690 mem_ctx, &c->data, &np);
691 if (ret != 0) {
692 return ret;
695 return 0;
698 struct ctdb_req_control_wire {
699 struct ctdb_req_header hdr;
700 uint32_t opcode;
701 uint32_t pad;
702 uint64_t srvid;
703 uint32_t client_id;
704 uint32_t flags;
705 uint32_t datalen;
706 uint8_t data[1];
709 static size_t ctdb_req_control_len_old(struct ctdb_req_header *h,
710 struct ctdb_req_control *c)
712 return offsetof(struct ctdb_req_control_wire, data) +
713 ctdb_req_control_data_len(&c->rdata);
716 static int ctdb_req_control_push_old(struct ctdb_req_header *h,
717 struct ctdb_req_control *c,
718 uint8_t *buf, size_t *buflen)
720 struct ctdb_req_control_wire *wire =
721 (struct ctdb_req_control_wire *)buf;
722 size_t length, np;
724 length = ctdb_req_control_len_old(h, c);
725 if (*buflen < length) {
726 *buflen = length;
727 return EMSGSIZE;
730 h->length = *buflen;
731 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
733 wire->opcode = c->opcode;
734 wire->pad = c->pad;
735 wire->srvid = c->srvid;
736 wire->client_id = c->client_id;
737 wire->flags = c->flags;
739 wire->datalen = ctdb_req_control_data_len(&c->rdata);
740 ctdb_req_control_data_push(&c->rdata, wire->data, &np);
742 return 0;
745 static int ctdb_req_control_pull_old(uint8_t *buf, size_t buflen,
746 struct ctdb_req_header *h,
747 TALLOC_CTX *mem_ctx,
748 struct ctdb_req_control *c)
750 struct ctdb_req_control_wire *wire =
751 (struct ctdb_req_control_wire *)buf;
752 size_t length, np;
753 int ret;
755 length = offsetof(struct ctdb_req_control_wire, data);
756 if (buflen < length) {
757 return EMSGSIZE;
759 if (wire->datalen > buflen) {
760 return EMSGSIZE;
762 if (length + wire->datalen < length) {
763 return EMSGSIZE;
765 if (buflen < length + wire->datalen) {
766 return EMSGSIZE;
769 if (h != NULL) {
770 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
772 if (ret != 0) {
773 return ret;
777 c->opcode = wire->opcode;
778 c->pad = wire->pad;
779 c->srvid = wire->srvid;
780 c->client_id = wire->client_id;
781 c->flags = wire->flags;
783 ret = ctdb_req_control_data_pull(wire->data, wire->datalen,
784 c->opcode, mem_ctx, &c->rdata, &np);
785 if (ret != 0) {
786 return ret;
789 return 0;
792 struct ctdb_reply_control_wire {
793 struct ctdb_req_header hdr;
794 int32_t status;
795 uint32_t datalen;
796 uint32_t errorlen;
797 uint8_t data[1];
800 static size_t ctdb_reply_control_len_old(struct ctdb_req_header *h,
801 struct ctdb_reply_control *c)
803 return offsetof(struct ctdb_reply_control_wire, data) +
804 (c->status == 0 ?
805 ctdb_reply_control_data_len(&c->rdata) :
806 ctdb_string_len(&c->errmsg));
809 static int ctdb_reply_control_push_old(struct ctdb_req_header *h,
810 struct ctdb_reply_control *c,
811 uint8_t *buf, size_t *buflen)
813 struct ctdb_reply_control_wire *wire =
814 (struct ctdb_reply_control_wire *)buf;
815 size_t length, np;
817 length = ctdb_reply_control_len_old(h, c);
818 if (*buflen < length) {
819 *buflen = length;
820 return EMSGSIZE;
823 h->length = *buflen;
824 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
826 wire->status = c->status;
828 if (c->status == 0) {
829 wire->datalen = ctdb_reply_control_data_len(&c->rdata);
830 wire->errorlen = 0;
831 ctdb_reply_control_data_push(&c->rdata, wire->data, &np);
832 } else {
833 wire->datalen = 0;
834 wire->errorlen = ctdb_string_len(&c->errmsg);
835 ctdb_string_push(&c->errmsg, wire->data + wire->datalen, &np);
838 return 0;
841 static int ctdb_reply_control_pull_old(uint8_t *buf, size_t buflen,
842 uint32_t opcode,
843 struct ctdb_req_header *h,
844 TALLOC_CTX *mem_ctx,
845 struct ctdb_reply_control *c)
847 struct ctdb_reply_control_wire *wire =
848 (struct ctdb_reply_control_wire *)buf;
849 size_t length, np;
850 int ret;
852 length = offsetof(struct ctdb_reply_control_wire, data);
853 if (buflen < length) {
854 return EMSGSIZE;
856 if (wire->datalen > buflen || wire->errorlen > buflen) {
857 return EMSGSIZE;
859 if (length + wire->datalen < length) {
860 return EMSGSIZE;
862 if (length + wire->datalen + wire->errorlen < length) {
863 return EMSGSIZE;
865 if (buflen < length + wire->datalen + wire->errorlen) {
866 return EMSGSIZE;
869 if (h != NULL) {
870 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
872 if (ret != 0) {
873 return ret;
877 c->status = wire->status;
879 if (c->status != -1) {
880 ret = ctdb_reply_control_data_pull(wire->data, wire->datalen,
881 opcode, mem_ctx,
882 &c->rdata, &np);
883 if (ret != 0) {
884 return ret;
888 ret = ctdb_string_pull(wire->data + wire->datalen, wire->errorlen,
889 mem_ctx, &c->errmsg, &np);
890 if (ret != 0) {
891 return ret;
894 return 0;
897 struct ctdb_req_message_wire {
898 struct ctdb_req_header hdr;
899 uint64_t srvid;
900 uint32_t datalen;
901 uint8_t data[1];
904 static size_t ctdb_req_message_len_old(struct ctdb_req_header *h,
905 struct ctdb_req_message *c)
907 return offsetof(struct ctdb_req_message_wire, data) +
908 ctdb_message_data_len(&c->data, c->srvid);
911 static int ctdb_req_message_push_old(struct ctdb_req_header *h,
912 struct ctdb_req_message *c,
913 uint8_t *buf, size_t *buflen)
915 struct ctdb_req_message_wire *wire =
916 (struct ctdb_req_message_wire *)buf;
917 size_t length, np;
919 length = ctdb_req_message_len_old(h, c);
920 if (*buflen < length) {
921 *buflen = length;
922 return EMSGSIZE;
925 h->length = *buflen;
926 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
928 wire->srvid = c->srvid;
929 wire->datalen = ctdb_message_data_len(&c->data, c->srvid);
930 ctdb_message_data_push(&c->data, c->srvid, wire->data, &np);
932 return 0;
935 static int ctdb_req_message_pull_old(uint8_t *buf, size_t buflen,
936 struct ctdb_req_header *h,
937 TALLOC_CTX *mem_ctx,
938 struct ctdb_req_message *c)
940 struct ctdb_req_message_wire *wire =
941 (struct ctdb_req_message_wire *)buf;
942 size_t length, np;
943 int ret;
945 length = offsetof(struct ctdb_req_message_wire, data);
946 if (buflen < length) {
947 return EMSGSIZE;
949 if (wire->datalen > buflen) {
950 return EMSGSIZE;
952 if (length + wire->datalen < length) {
953 return EMSGSIZE;
955 if (buflen < length + wire->datalen) {
956 return EMSGSIZE;
959 if (h != NULL) {
960 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
962 if (ret != 0) {
963 return ret;
967 c->srvid = wire->srvid;
968 ret = ctdb_message_data_pull(wire->data, wire->datalen, wire->srvid,
969 mem_ctx, &c->data, &np);
970 return ret;
973 static size_t ctdb_req_message_data_len_old(struct ctdb_req_header *h,
974 struct ctdb_req_message_data *c)
976 return offsetof(struct ctdb_req_message_wire, data) +
977 ctdb_tdb_data_len(&c->data);
980 static int ctdb_req_message_data_push_old(struct ctdb_req_header *h,
981 struct ctdb_req_message_data *c,
982 uint8_t *buf, size_t *buflen)
984 struct ctdb_req_message_wire *wire =
985 (struct ctdb_req_message_wire *)buf;
986 size_t length, np;
988 length = ctdb_req_message_data_len_old(h, c);
989 if (*buflen < length) {
990 *buflen = length;
991 return EMSGSIZE;
994 h->length = *buflen;
995 ctdb_req_header_push(h, (uint8_t *)&wire->hdr, &np);
997 wire->srvid = c->srvid;
998 wire->datalen = ctdb_tdb_data_len(&c->data);
999 ctdb_tdb_data_push(&c->data, wire->data, &np);
1001 return 0;
1004 static int ctdb_req_message_data_pull_old(uint8_t *buf, size_t buflen,
1005 struct ctdb_req_header *h,
1006 TALLOC_CTX *mem_ctx,
1007 struct ctdb_req_message_data *c)
1009 struct ctdb_req_message_wire *wire =
1010 (struct ctdb_req_message_wire *)buf;
1011 size_t length, np;
1012 int ret;
1014 length = offsetof(struct ctdb_req_message_wire, data);
1015 if (buflen < length) {
1016 return EMSGSIZE;
1018 if (wire->datalen > buflen) {
1019 return EMSGSIZE;
1021 if (length + wire->datalen < length) {
1022 return EMSGSIZE;
1024 if (buflen < length + wire->datalen) {
1025 return EMSGSIZE;
1028 if (h != NULL) {
1029 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
1031 if (ret != 0) {
1032 return ret;
1036 c->srvid = wire->srvid;
1038 ret = ctdb_tdb_data_pull(wire->data, wire->datalen,
1039 mem_ctx, &c->data, &np);
1040 if (ret != 0) {
1041 return ret;
1044 return 0;
1047 struct ctdb_req_keepalive_wire {
1048 struct ctdb_req_header hdr;
1049 uint32_t version;
1050 uint32_t uptime;
1053 static size_t ctdb_req_keepalive_len_old(struct ctdb_req_header *h,
1054 struct ctdb_req_keepalive *c)
1056 return sizeof(struct ctdb_req_keepalive_wire);
1059 static int ctdb_req_keepalive_push_old(struct ctdb_req_header *h,
1060 struct ctdb_req_keepalive *c,
1061 uint8_t *buf, size_t *buflen)
1063 struct ctdb_req_keepalive_wire *wire =
1064 (struct ctdb_req_keepalive_wire *)buf;
1065 size_t length;
1067 length = ctdb_req_keepalive_len_old(h, c);
1068 if (*buflen < length) {
1069 *buflen = length;
1070 return EMSGSIZE;
1073 h->length = *buflen;
1074 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
1076 wire->version = c->version;
1077 wire->uptime = c->uptime;
1079 return 0;
1082 static int ctdb_req_keepalive_pull_old(uint8_t *buf, size_t buflen,
1083 struct ctdb_req_header *h,
1084 TALLOC_CTX *mem_ctx,
1085 struct ctdb_req_keepalive *c)
1087 struct ctdb_req_keepalive_wire *wire =
1088 (struct ctdb_req_keepalive_wire *)buf;
1089 size_t length;
1090 int ret;
1092 length = sizeof(struct ctdb_req_keepalive_wire);
1093 if (buflen < length) {
1094 return EMSGSIZE;
1097 if (h != NULL) {
1098 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
1100 if (ret != 0) {
1101 return ret;
1105 c->version = wire->version;
1106 c->uptime = wire->uptime;
1108 return 0;
1111 struct ctdb_req_tunnel_wire {
1112 struct ctdb_req_header hdr;
1113 uint64_t tunnel_id;
1114 uint32_t flags;
1115 uint32_t datalen;
1116 uint8_t data[1];
1119 static size_t ctdb_req_tunnel_len_old(struct ctdb_req_header *h,
1120 struct ctdb_req_tunnel *c)
1122 return offsetof(struct ctdb_req_tunnel_wire, data) +
1123 ctdb_tdb_data_len(&c->data);
1126 static int ctdb_req_tunnel_push_old(struct ctdb_req_header *h,
1127 struct ctdb_req_tunnel *c,
1128 uint8_t *buf, size_t *buflen)
1130 struct ctdb_req_tunnel_wire *wire =
1131 (struct ctdb_req_tunnel_wire *)buf;
1132 size_t length, np;
1134 length = ctdb_req_tunnel_len_old(h, c);
1135 if (*buflen < length) {
1136 *buflen = length;
1137 return EMSGSIZE;
1140 h->length = *buflen;
1141 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr);
1143 wire->tunnel_id = c->tunnel_id;
1144 wire->flags = c->flags;
1145 wire->datalen = ctdb_tdb_data_len(&c->data);
1146 ctdb_tdb_data_push(&c->data, wire->data, &np);
1148 return 0;
1151 static int ctdb_req_tunnel_pull_old(uint8_t *buf, size_t buflen,
1152 struct ctdb_req_header *h,
1153 TALLOC_CTX *mem_ctx,
1154 struct ctdb_req_tunnel *c)
1156 struct ctdb_req_tunnel_wire *wire =
1157 (struct ctdb_req_tunnel_wire *)buf;
1158 size_t length, np;
1159 int ret;
1161 length = offsetof(struct ctdb_req_tunnel_wire, data);
1162 if (buflen < length) {
1163 return EMSGSIZE;
1165 if (wire->datalen > buflen) {
1166 return EMSGSIZE;
1168 if (length + wire->datalen < length) {
1169 return EMSGSIZE;
1171 if (buflen < length + wire->datalen) {
1172 return EMSGSIZE;
1175 if (h != NULL) {
1176 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen,
1178 if (ret != 0) {
1179 return ret;
1183 c->tunnel_id = wire->tunnel_id;
1184 c->flags = wire->flags;
1186 ret = ctdb_tdb_data_pull(wire->data, wire->datalen, mem_ctx, &c->data,
1187 &np);
1188 if (ret != 0) {
1189 return ret;
1192 return 0;
1196 COMPAT_CTDB1_TEST(struct ctdb_req_header, ctdb_req_header);
1198 COMPAT_CTDB4_TEST(struct ctdb_req_call, ctdb_req_call, CTDB_REQ_CALL);
1199 COMPAT_CTDB4_TEST(struct ctdb_reply_call, ctdb_reply_call, CTDB_REPLY_CALL);
1200 COMPAT_CTDB4_TEST(struct ctdb_reply_error, ctdb_reply_error, CTDB_REPLY_ERROR);
1201 COMPAT_CTDB4_TEST(struct ctdb_req_dmaster, ctdb_req_dmaster, CTDB_REQ_DMASTER);
1202 COMPAT_CTDB4_TEST(struct ctdb_reply_dmaster, ctdb_reply_dmaster, CTDB_REPLY_DMASTER);
1204 COMPAT_CTDB5_TEST(struct ctdb_req_control, ctdb_req_control, CTDB_REQ_CONTROL);
1205 COMPAT_CTDB6_TEST(struct ctdb_reply_control, ctdb_reply_control, CTDB_REPLY_CONTROL);
1207 COMPAT_CTDB7_TEST(struct ctdb_req_message, ctdb_req_message, CTDB_REQ_MESSAGE);
1208 COMPAT_CTDB4_TEST(struct ctdb_req_message_data, ctdb_req_message_data, CTDB_REQ_MESSAGE);
1210 COMPAT_CTDB4_TEST(struct ctdb_req_keepalive, ctdb_req_keepalive, CTDB_REQ_KEEPALIVE);
1211 COMPAT_CTDB4_TEST(struct ctdb_req_tunnel, ctdb_req_tunnel, CTDB_REQ_TUNNEL);
1213 #define NUM_CONTROLS 151
1215 static void protocol_ctdb_compat_test(void)
1217 uint32_t opcode;
1218 uint64_t test_srvid[] = {
1219 CTDB_SRVID_BANNING,
1220 CTDB_SRVID_ELECTION,
1221 CTDB_SRVID_LEADER,
1222 CTDB_SRVID_RECONFIGURE,
1223 CTDB_SRVID_RELEASE_IP,
1224 CTDB_SRVID_TAKE_IP,
1225 CTDB_SRVID_SET_NODE_FLAGS,
1226 CTDB_SRVID_RECD_UPDATE_IP,
1227 CTDB_SRVID_VACUUM_FETCH,
1228 CTDB_SRVID_DETACH_DATABASE,
1229 CTDB_SRVID_MEM_DUMP,
1230 CTDB_SRVID_GETLOG,
1231 CTDB_SRVID_CLEARLOG,
1232 CTDB_SRVID_PUSH_NODE_FLAGS,
1233 CTDB_SRVID_RELOAD_NODES,
1234 CTDB_SRVID_TAKEOVER_RUN,
1235 CTDB_SRVID_REBALANCE_NODE,
1236 CTDB_SRVID_DISABLE_TAKEOVER_RUNS,
1237 CTDB_SRVID_DISABLE_RECOVERIES,
1238 CTDB_SRVID_DISABLE_IP_CHECK,
1240 unsigned int i;
1242 COMPAT_TEST_FUNC(ctdb_req_header)();
1244 COMPAT_TEST_FUNC(ctdb_req_call)();
1245 COMPAT_TEST_FUNC(ctdb_reply_call)();
1246 COMPAT_TEST_FUNC(ctdb_reply_error)();
1247 COMPAT_TEST_FUNC(ctdb_req_dmaster)();
1248 COMPAT_TEST_FUNC(ctdb_reply_dmaster)();
1250 for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
1251 COMPAT_TEST_FUNC(ctdb_req_control)(opcode);
1253 for (opcode=0; opcode<NUM_CONTROLS; opcode++) {
1254 COMPAT_TEST_FUNC(ctdb_reply_control)(opcode);
1257 for (i=0; i<ARRAY_SIZE(test_srvid); i++) {
1258 COMPAT_TEST_FUNC(ctdb_req_message)(test_srvid[i]);
1260 COMPAT_TEST_FUNC(ctdb_req_message_data)();
1262 COMPAT_TEST_FUNC(ctdb_req_keepalive)();
1263 COMPAT_TEST_FUNC(ctdb_req_tunnel)();
1266 int main(int argc, const char *argv[])
1268 protocol_test_iterate(argc, argv, protocol_ctdb_compat_test);
1269 return 0;