1 /* 2 ctdb protocol backward compatibility test 3 4 Copyright (C) Amitay Isaacs 2017 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "replace.h" 21 #include "system/filesys.h" 22 23 #include <assert.h> 24 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" 33 34 #include "tests/src/protocol_common.h" 35 #include "tests/src/protocol_common_ctdb.h" 36 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 41 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; \ 50 \ 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); \ 70 } 71 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; \ 81 \ 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); \ 105 } 106 107 #define COMPAT_CTDB5_TEST(TYPE, NAME, OPER) \ 108 static void COMPAT_TEST_FUNC(NAME)(uint32_t opcode) \ 109 { \ 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; \ 116 \ 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); \ 140 } 141 142 #define COMPAT_CTDB6_TEST(TYPE, NAME, OPER) \ 143 static void COMPAT_TEST_FUNC(NAME)(uint32_t opcode) \ 144 { \ 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; \ 151 \ 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); \ 175 } 176 177 #define COMPAT_CTDB7_TEST(TYPE, NAME, OPER) \ 178 static void COMPAT_TEST_FUNC(NAME)(uint64_t srvid) \ 179 { \ 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; \ 186 \ 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); \ 210 } 211 212 213 static size_t ctdb_req_header_len_old(struct ctdb_req_header *in) 214 { 215 return sizeof(struct ctdb_req_header); 216 } 217 218 static void ctdb_req_header_push_old(struct ctdb_req_header *in, uint8_t *buf) 219 { 220 memcpy(buf, in, sizeof(struct ctdb_req_header)); 221 } 222 223 static int ctdb_req_header_pull_old(uint8_t *buf, size_t buflen, 224 struct ctdb_req_header *out) 225 { 226 if (buflen < sizeof(struct ctdb_req_header)) { 227 return EMSGSIZE; 228 } 229 230 memcpy(out, buf, sizeof(struct ctdb_req_header)); 231 return 0; 232 } 233 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[] */ 243 }; 244 245 static size_t ctdb_req_call_len_old(struct ctdb_req_header *h, 246 struct ctdb_req_call *c) 247 { 248 return offsetof(struct ctdb_req_call_wire, data) + 249 ctdb_tdb_data_len(&c->key) + 250 ctdb_tdb_data_len(&c->calldata); 251 } 252 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) 256 { 257 struct ctdb_req_call_wire *wire = 258 (struct ctdb_req_call_wire *)buf; 259 size_t length, np; 260 261 if (c->key.dsize == 0) { 262 return EINVAL; 263 } 264 265 length = ctdb_req_call_len_old(h, c); 266 if (*buflen < length) { 267 *buflen = length; 268 return EMSGSIZE; 269 } 270 271 h->length = *buflen; 272 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 273 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); 282 283 return 0; 284 } 285 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) 290 { 291 struct ctdb_req_call_wire *wire = 292 (struct ctdb_req_call_wire *)buf; 293 size_t length, np; 294 int ret; 295 296 length = offsetof(struct ctdb_req_call_wire, data); 297 if (buflen < length) { 298 return EMSGSIZE; 299 } 300 if (wire->keylen > buflen || wire->calldatalen > buflen) { 301 return EMSGSIZE; 302 } 303 if (length + wire->keylen < length) { 304 return EMSGSIZE; 305 } 306 if (length + wire->keylen + wire->calldatalen < length) { 307 return EMSGSIZE; 308 } 309 if (buflen < length + wire->keylen + wire->calldatalen) { 310 return EMSGSIZE; 311 } 312 313 if (h != NULL) { 314 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 315 h); 316 if (ret != 0) { 317 return ret; 318 } 319 } 320 321 c->flags = wire->flags; 322 c->db_id = wire->db_id; 323 c->callid = wire->callid; 324 c->hopcount = wire->hopcount; 325 326 ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key, 327 &np); 328 if (ret != 0) { 329 return ret; 330 } 331 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; 336 } 337 338 return 0; 339 } 340 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]; 346 }; 347 348 static size_t ctdb_reply_call_len_old(struct ctdb_req_header *h, 349 struct ctdb_reply_call *c) 350 { 351 return offsetof(struct ctdb_reply_call_wire, data) + 352 ctdb_tdb_data_len(&c->data); 353 } 354 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) 358 { 359 struct ctdb_reply_call_wire *wire = 360 (struct ctdb_reply_call_wire *)buf; 361 size_t length, np; 362 363 length = ctdb_reply_call_len_old(h, c); 364 if (*buflen < length) { 365 *buflen = length; 366 return EMSGSIZE; 367 } 368 369 h->length = *buflen; 370 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 371 372 wire->status = c->status; 373 wire->datalen = ctdb_tdb_data_len(&c->data); 374 ctdb_tdb_data_push(&c->data, wire->data, &np); 375 376 return 0; 377 } 378 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) 383 { 384 struct ctdb_reply_call_wire *wire = 385 (struct ctdb_reply_call_wire *)buf; 386 size_t length, np; 387 int ret; 388 389 length = offsetof(struct ctdb_reply_call_wire, data); 390 if (buflen < length) { 391 return EMSGSIZE; 392 } 393 if (wire->datalen > buflen) { 394 return EMSGSIZE; 395 } 396 if (length + wire->datalen < length) { 397 return EMSGSIZE; 398 } 399 if (buflen < length + wire->datalen) { 400 return EMSGSIZE; 401 } 402 403 if (h != NULL) { 404 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 405 h); 406 if (ret != 0) { 407 return ret; 408 } 409 } 410 411 c->status = wire->status; 412 413 ret = ctdb_tdb_data_pull(wire->data, wire->datalen, mem_ctx, &c->data, 414 &np); 415 if (ret != 0) { 416 return ret; 417 } 418 419 return 0; 420 } 421 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]; 427 }; 428 429 static size_t ctdb_reply_error_len_old(struct ctdb_req_header *h, 430 struct ctdb_reply_error *c) 431 { 432 return offsetof(struct ctdb_reply_error_wire, msg) + 433 ctdb_tdb_data_len(&c->msg); 434 } 435 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) 439 { 440 struct ctdb_reply_error_wire *wire = 441 (struct ctdb_reply_error_wire *)buf; 442 size_t length, np; 443 444 length = ctdb_reply_error_len_old(h, c); 445 if (*buflen < length) { 446 *buflen = length; 447 return EMSGSIZE; 448 } 449 450 h->length = *buflen; 451 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 452 453 wire->status = c->status; 454 wire->msglen = ctdb_tdb_data_len(&c->msg); 455 ctdb_tdb_data_push(&c->msg, wire->msg, &np); 456 457 return 0; 458 } 459 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) 464 { 465 struct ctdb_reply_error_wire *wire = 466 (struct ctdb_reply_error_wire *)buf; 467 size_t length, np; 468 int ret; 469 470 length = offsetof(struct ctdb_reply_error_wire, msg); 471 if (buflen < length) { 472 return EMSGSIZE; 473 } 474 if (wire->msglen > buflen) { 475 return EMSGSIZE; 476 } 477 if (length + wire->msglen < length) { 478 return EMSGSIZE; 479 } 480 if (buflen < length + wire->msglen) { 481 return EMSGSIZE; 482 } 483 484 if (h != NULL) { 485 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 486 h); 487 if (ret != 0) { 488 return ret; 489 } 490 } 491 492 c->status = wire->status; 493 494 ret = ctdb_tdb_data_pull(wire->msg, wire->msglen, mem_ctx, &c->msg, 495 &np); 496 if (ret != 0) { 497 return ret; 498 } 499 500 return 0; 501 } 502 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]; 511 }; 512 513 static size_t ctdb_req_dmaster_len_old(struct ctdb_req_header *h, 514 struct ctdb_req_dmaster *c) 515 { 516 return offsetof(struct ctdb_req_dmaster_wire, data) + 517 ctdb_tdb_data_len(&c->key) + ctdb_tdb_data_len(&c->data); 518 } 519 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) 523 { 524 struct ctdb_req_dmaster_wire *wire = 525 (struct ctdb_req_dmaster_wire *)buf; 526 size_t length, np; 527 528 length = ctdb_req_dmaster_len_old(h, c); 529 if (*buflen < length) { 530 *buflen = length; 531 return EMSGSIZE; 532 } 533 534 h->length = *buflen; 535 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 536 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); 544 545 return 0; 546 } 547 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) 552 { 553 struct ctdb_req_dmaster_wire *wire = 554 (struct ctdb_req_dmaster_wire *)buf; 555 size_t length, np; 556 int ret; 557 558 length = offsetof(struct ctdb_req_dmaster_wire, data); 559 if (buflen < length) { 560 return EMSGSIZE; 561 } 562 if (wire->keylen > buflen || wire->datalen > buflen) { 563 return EMSGSIZE; 564 } 565 if (length + wire->keylen < length) { 566 return EMSGSIZE; 567 } 568 if (length + wire->keylen + wire->datalen < length) { 569 return EMSGSIZE; 570 } 571 if (buflen < length + wire->keylen + wire->datalen) { 572 return EMSGSIZE; 573 } 574 575 if (h != NULL) { 576 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 577 h); 578 if (ret != 0) { 579 return ret; 580 } 581 } 582 583 c->db_id = wire->db_id; 584 c->rsn = wire->rsn; 585 c->dmaster = wire->dmaster; 586 587 ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key, 588 &np); 589 if (ret != 0) { 590 return ret; 591 } 592 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; 597 } 598 599 return 0; 600 } 601 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]; 609 }; 610 611 static size_t ctdb_reply_dmaster_len_old(struct ctdb_req_header *h, 612 struct ctdb_reply_dmaster *c) 613 { 614 return offsetof(struct ctdb_reply_dmaster_wire, data) + 615 ctdb_tdb_data_len(&c->key) + ctdb_tdb_data_len(&c->data); 616 } 617 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) 621 { 622 struct ctdb_reply_dmaster_wire *wire = 623 (struct ctdb_reply_dmaster_wire *)buf; 624 size_t length, np; 625 626 length = ctdb_reply_dmaster_len_old(h, c); 627 if (*buflen < length) { 628 *buflen = length; 629 return EMSGSIZE; 630 } 631 632 h->length = *buflen; 633 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 634 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); 641 642 return 0; 643 } 644 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) 649 { 650 struct ctdb_reply_dmaster_wire *wire = 651 (struct ctdb_reply_dmaster_wire *)buf; 652 size_t length, np; 653 int ret; 654 655 length = offsetof(struct ctdb_reply_dmaster_wire, data); 656 if (buflen < length) { 657 return EMSGSIZE; 658 } 659 if (wire->keylen > buflen || wire->datalen > buflen) { 660 return EMSGSIZE; 661 } 662 if (length + wire->keylen < length) { 663 return EMSGSIZE; 664 } 665 if (length + wire->keylen + wire->datalen < length) { 666 return EMSGSIZE; 667 } 668 if (buflen < length + wire->keylen + wire->datalen) { 669 return EMSGSIZE; 670 } 671 672 if (h != NULL) { 673 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 674 h); 675 if (ret != 0) { 676 return ret; 677 } 678 } 679 680 c->db_id = wire->db_id; 681 c->rsn = wire->rsn; 682 683 ret = ctdb_tdb_data_pull(wire->data, wire->keylen, mem_ctx, &c->key, 684 &np); 685 if (ret != 0) { 686 return ret; 687 } 688 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; 693 } 694 695 return 0; 696 } 697 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]; 707 }; 708 709 static size_t ctdb_req_control_len_old(struct ctdb_req_header *h, 710 struct ctdb_req_control *c) 711 { 712 return offsetof(struct ctdb_req_control_wire, data) + 713 ctdb_req_control_data_len(&c->rdata); 714 } 715 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) 719 { 720 struct ctdb_req_control_wire *wire = 721 (struct ctdb_req_control_wire *)buf; 722 size_t length, np; 723 724 length = ctdb_req_control_len_old(h, c); 725 if (*buflen < length) { 726 *buflen = length; 727 return EMSGSIZE; 728 } 729 730 h->length = *buflen; 731 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 732 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; 738 739 wire->datalen = ctdb_req_control_data_len(&c->rdata); 740 ctdb_req_control_data_push(&c->rdata, wire->data, &np); 741 742 return 0; 743 } 744 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) 749 { 750 struct ctdb_req_control_wire *wire = 751 (struct ctdb_req_control_wire *)buf; 752 size_t length, np; 753 int ret; 754 755 length = offsetof(struct ctdb_req_control_wire, data); 756 if (buflen < length) { 757 return EMSGSIZE; 758 } 759 if (wire->datalen > buflen) { 760 return EMSGSIZE; 761 } 762 if (length + wire->datalen < length) { 763 return EMSGSIZE; 764 } 765 if (buflen < length + wire->datalen) { 766 return EMSGSIZE; 767 } 768 769 if (h != NULL) { 770 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 771 h); 772 if (ret != 0) { 773 return ret; 774 } 775 } 776 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; 782 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; 787 } 788 789 return 0; 790 } 791 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]; 798 }; 799 800 static size_t ctdb_reply_control_len_old(struct ctdb_req_header *h, 801 struct ctdb_reply_control *c) 802 { 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)); 807 } 808 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) 812 { 813 struct ctdb_reply_control_wire *wire = 814 (struct ctdb_reply_control_wire *)buf; 815 size_t length, np; 816 817 length = ctdb_reply_control_len_old(h, c); 818 if (*buflen < length) { 819 *buflen = length; 820 return EMSGSIZE; 821 } 822 823 h->length = *buflen; 824 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 825 826 wire->status = c->status; 827 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); 836 } 837 838 return 0; 839 } 840 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) 846 { 847 struct ctdb_reply_control_wire *wire = 848 (struct ctdb_reply_control_wire *)buf; 849 size_t length, np; 850 int ret; 851 852 length = offsetof(struct ctdb_reply_control_wire, data); 853 if (buflen < length) { 854 return EMSGSIZE; 855 } 856 if (wire->datalen > buflen || wire->errorlen > buflen) { 857 return EMSGSIZE; 858 } 859 if (length + wire->datalen < length) { 860 return EMSGSIZE; 861 } 862 if (length + wire->datalen + wire->errorlen < length) { 863 return EMSGSIZE; 864 } 865 if (buflen < length + wire->datalen + wire->errorlen) { 866 return EMSGSIZE; 867 } 868 869 if (h != NULL) { 870 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 871 h); 872 if (ret != 0) { 873 return ret; 874 } 875 } 876 877 c->status = wire->status; 878 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; 885 } 886 } 887 888 ret = ctdb_string_pull(wire->data + wire->datalen, wire->errorlen, 889 mem_ctx, &c->errmsg, &np); 890 if (ret != 0) { 891 return ret; 892 } 893 894 return 0; 895 } 896 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]; 902 }; 903 904 static size_t ctdb_req_message_len_old(struct ctdb_req_header *h, 905 struct ctdb_req_message *c) 906 { 907 return offsetof(struct ctdb_req_message_wire, data) + 908 ctdb_message_data_len(&c->data, c->srvid); 909 } 910 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) 914 { 915 struct ctdb_req_message_wire *wire = 916 (struct ctdb_req_message_wire *)buf; 917 size_t length, np; 918 919 length = ctdb_req_message_len_old(h, c); 920 if (*buflen < length) { 921 *buflen = length; 922 return EMSGSIZE; 923 } 924 925 h->length = *buflen; 926 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 927 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); 931 932 return 0; 933 } 934 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) 939 { 940 struct ctdb_req_message_wire *wire = 941 (struct ctdb_req_message_wire *)buf; 942 size_t length, np; 943 int ret; 944 945 length = offsetof(struct ctdb_req_message_wire, data); 946 if (buflen < length) { 947 return EMSGSIZE; 948 } 949 if (wire->datalen > buflen) { 950 return EMSGSIZE; 951 } 952 if (length + wire->datalen < length) { 953 return EMSGSIZE; 954 } 955 if (buflen < length + wire->datalen) { 956 return EMSGSIZE; 957 } 958 959 if (h != NULL) { 960 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 961 h); 962 if (ret != 0) { 963 return ret; 964 } 965 } 966 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; 971 } 972 973 static size_t ctdb_req_message_data_len_old(struct ctdb_req_header *h, 974 struct ctdb_req_message_data *c) 975 { 976 return offsetof(struct ctdb_req_message_wire, data) + 977 ctdb_tdb_data_len(&c->data); 978 } 979 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) 983 { 984 struct ctdb_req_message_wire *wire = 985 (struct ctdb_req_message_wire *)buf; 986 size_t length, np; 987 988 length = ctdb_req_message_data_len_old(h, c); 989 if (*buflen < length) { 990 *buflen = length; 991 return EMSGSIZE; 992 } 993 994 h->length = *buflen; 995 ctdb_req_header_push(h, (uint8_t *)&wire->hdr, &np); 996 997 wire->srvid = c->srvid; 998 wire->datalen = ctdb_tdb_data_len(&c->data); 999 ctdb_tdb_data_push(&c->data, wire->data, &np); 1000 1001 return 0; 1002 } 1003 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) 1008 { 1009 struct ctdb_req_message_wire *wire = 1010 (struct ctdb_req_message_wire *)buf; 1011 size_t length, np; 1012 int ret; 1013 1014 length = offsetof(struct ctdb_req_message_wire, data); 1015 if (buflen < length) { 1016 return EMSGSIZE; 1017 } 1018 if (wire->datalen > buflen) { 1019 return EMSGSIZE; 1020 } 1021 if (length + wire->datalen < length) { 1022 return EMSGSIZE; 1023 } 1024 if (buflen < length + wire->datalen) { 1025 return EMSGSIZE; 1026 } 1027 1028 if (h != NULL) { 1029 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 1030 h); 1031 if (ret != 0) { 1032 return ret; 1033 } 1034 } 1035 1036 c->srvid = wire->srvid; 1037 1038 ret = ctdb_tdb_data_pull(wire->data, wire->datalen, 1039 mem_ctx, &c->data, &np); 1040 if (ret != 0) { 1041 return ret; 1042 } 1043 1044 return 0; 1045 } 1046 1047 struct ctdb_req_keepalive_wire { 1048 struct ctdb_req_header hdr; 1049 uint32_t version; 1050 uint32_t uptime; 1051 }; 1052 1053 static size_t ctdb_req_keepalive_len_old(struct ctdb_req_header *h, 1054 struct ctdb_req_keepalive *c) 1055 { 1056 return sizeof(struct ctdb_req_keepalive_wire); 1057 } 1058 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) 1062 { 1063 struct ctdb_req_keepalive_wire *wire = 1064 (struct ctdb_req_keepalive_wire *)buf; 1065 size_t length; 1066 1067 length = ctdb_req_keepalive_len_old(h, c); 1068 if (*buflen < length) { 1069 *buflen = length; 1070 return EMSGSIZE; 1071 } 1072 1073 h->length = *buflen; 1074 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 1075 1076 wire->version = c->version; 1077 wire->uptime = c->uptime; 1078 1079 return 0; 1080 } 1081 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) 1086 { 1087 struct ctdb_req_keepalive_wire *wire = 1088 (struct ctdb_req_keepalive_wire *)buf; 1089 size_t length; 1090 int ret; 1091 1092 length = sizeof(struct ctdb_req_keepalive_wire); 1093 if (buflen < length) { 1094 return EMSGSIZE; 1095 } 1096 1097 if (h != NULL) { 1098 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 1099 h); 1100 if (ret != 0) { 1101 return ret; 1102 } 1103 } 1104 1105 c->version = wire->version; 1106 c->uptime = wire->uptime; 1107 1108 return 0; 1109 } 1110 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]; 1117 }; 1118 1119 static size_t ctdb_req_tunnel_len_old(struct ctdb_req_header *h, 1120 struct ctdb_req_tunnel *c) 1121 { 1122 return offsetof(struct ctdb_req_tunnel_wire, data) + 1123 ctdb_tdb_data_len(&c->data); 1124 } 1125 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) 1129 { 1130 struct ctdb_req_tunnel_wire *wire = 1131 (struct ctdb_req_tunnel_wire *)buf; 1132 size_t length, np; 1133 1134 length = ctdb_req_tunnel_len_old(h, c); 1135 if (*buflen < length) { 1136 *buflen = length; 1137 return EMSGSIZE; 1138 } 1139 1140 h->length = *buflen; 1141 ctdb_req_header_push_old(h, (uint8_t *)&wire->hdr); 1142 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); 1147 1148 return 0; 1149 } 1150 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) 1155 { 1156 struct ctdb_req_tunnel_wire *wire = 1157 (struct ctdb_req_tunnel_wire *)buf; 1158 size_t length, np; 1159 int ret; 1160 1161 length = offsetof(struct ctdb_req_tunnel_wire, data); 1162 if (buflen < length) { 1163 return EMSGSIZE; 1164 } 1165 if (wire->datalen > buflen) { 1166 return EMSGSIZE; 1167 } 1168 if (length + wire->datalen < length) { 1169 return EMSGSIZE; 1170 } 1171 if (buflen < length + wire->datalen) { 1172 return EMSGSIZE; 1173 } 1174 1175 if (h != NULL) { 1176 ret = ctdb_req_header_pull_old((uint8_t *)&wire->hdr, buflen, 1177 h); 1178 if (ret != 0) { 1179 return ret; 1180 } 1181 } 1182 1183 c->tunnel_id = wire->tunnel_id; 1184 c->flags = wire->flags; 1185 1186 ret = ctdb_tdb_data_pull(wire->data, wire->datalen, mem_ctx, &c->data, 1187 &np); 1188 if (ret != 0) { 1189 return ret; 1190 } 1191 1192 return 0; 1193 } 1194 1195 1196 COMPAT_CTDB1_TEST(struct ctdb_req_header, ctdb_req_header); 1197 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); 1203 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); 1206 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); 1209 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); 1212 1213 #define NUM_CONTROLS 151 1214 1215 int main(int argc, char *argv[]) 1216 { 1217 uint32_t opcode; 1218 uint64_t test_srvid[] = { 1219 CTDB_SRVID_BANNING, 1220 CTDB_SRVID_ELECTION, 1221 CTDB_SRVID_RECONFIGURE, 1222 CTDB_SRVID_RELEASE_IP, 1223 CTDB_SRVID_TAKE_IP, 1224 CTDB_SRVID_SET_NODE_FLAGS, 1225 CTDB_SRVID_RECD_UPDATE_IP, 1226 CTDB_SRVID_VACUUM_FETCH, 1227 CTDB_SRVID_DETACH_DATABASE, 1228 CTDB_SRVID_MEM_DUMP, 1229 CTDB_SRVID_GETLOG, 1230 CTDB_SRVID_CLEARLOG, 1231 CTDB_SRVID_PUSH_NODE_FLAGS, 1232 CTDB_SRVID_RELOAD_NODES, 1233 CTDB_SRVID_TAKEOVER_RUN, 1234 CTDB_SRVID_REBALANCE_NODE, 1235 CTDB_SRVID_DISABLE_TAKEOVER_RUNS, 1236 CTDB_SRVID_DISABLE_RECOVERIES, 1237 CTDB_SRVID_DISABLE_IP_CHECK, 1238 }; 1239 unsigned int i; 1240 1241 if (argc == 2) { 1242 int seed = atoi(argv[1]); 1243 srandom(seed); 1244 } 1245 1246 COMPAT_TEST_FUNC(ctdb_req_header)(); 1247 1248 COMPAT_TEST_FUNC(ctdb_req_call)(); 1249 COMPAT_TEST_FUNC(ctdb_reply_call)(); 1250 COMPAT_TEST_FUNC(ctdb_reply_error)(); 1251 COMPAT_TEST_FUNC(ctdb_req_dmaster)(); 1252 COMPAT_TEST_FUNC(ctdb_reply_dmaster)(); 1253 1254 for (opcode=0; opcode<NUM_CONTROLS; opcode++) { 1255 COMPAT_TEST_FUNC(ctdb_req_control)(opcode); 1256 } 1257 for (opcode=0; opcode<NUM_CONTROLS; opcode++) { 1258 COMPAT_TEST_FUNC(ctdb_reply_control)(opcode); 1259 } 1260 1261 for (i=0; i<ARRAY_SIZE(test_srvid); i++) { 1262 COMPAT_TEST_FUNC(ctdb_req_message)(test_srvid[i]); 1263 } 1264 COMPAT_TEST_FUNC(ctdb_req_message_data)(); 1265 1266 COMPAT_TEST_FUNC(ctdb_req_keepalive)(); 1267 COMPAT_TEST_FUNC(ctdb_req_tunnel)(); 1268 1269 return 0; 1270 } 1271