2 Unix SMB/CIFS implementation.
4 WINS replication testing
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libcli/nbt/libnbt.h"
25 #include "libcli/wrepl/winsrepl.h"
27 #define CHECK_STATUS(status, correct) do { \
28 if (!NT_STATUS_EQUAL(status, correct)) { \
29 printf("(%s) Incorrect status %s - should be %s\n", \
30 __location__, nt_errstr(status), nt_errstr(correct)); \
35 #define CHECK_VALUE(v, correct) do { \
36 if ((v) != (correct)) { \
37 printf("(%s) Incorrect value %s=%d - should be %d\n", \
38 __location__, #v, v, correct); \
43 #define _NBT_NAME(n,t,s) {\
49 static const char *wrepl_name_type_string(enum wrepl_name_type type)
52 case WREPL_TYPE_UNIQUE: return "UNIQUE";
53 case WREPL_TYPE_GROUP: return "GROUP";
54 case WREPL_TYPE_SGROUP: return "SGROUP";
55 case WREPL_TYPE_MHOMED: return "MHOMED";
57 return "UNKNOWN_TYPE";
60 static const char *wrepl_name_state_string(enum wrepl_name_state state)
63 case WREPL_STATE_ACTIVE: return "ACTIVE";
64 case WREPL_STATE_RELEASED: return "RELEASED";
65 case WREPL_STATE_TOMBSTONE: return "TOMBSTONE";
66 case WREPL_STATE_RESERVED: return "RESERVED";
68 return "UNKNOWN_STATE";
72 test how assoc_ctx's are only usable on the connection
75 static BOOL test_assoc_ctx1(TALLOC_CTX *mem_ctx, const char *address)
78 struct wrepl_request *req;
79 struct wrepl_socket *wrepl_socket1;
80 struct wrepl_associate associate1;
81 struct wrepl_socket *wrepl_socket2;
82 struct wrepl_associate associate2;
83 struct wrepl_pull_table pull_table;
84 struct wrepl_packet *rep_packet;
85 struct wrepl_associate_stop assoc_stop;
88 if (!lp_parm_bool(-1, "torture", "dangerous", False)) {
89 printf("winsrepl: cross connection assoc_ctx usage disabled - enable dangerous tests to use\n");
93 printf("Test if assoc_ctx is only valid on the conection it was created on\n");
95 wrepl_socket1 = wrepl_socket_init(mem_ctx, NULL);
96 wrepl_socket2 = wrepl_socket_init(mem_ctx, NULL);
98 printf("Setup 2 wrepl connections\n");
99 status = wrepl_connect(wrepl_socket1, NULL, address);
100 CHECK_STATUS(status, NT_STATUS_OK);
102 status = wrepl_connect(wrepl_socket2, NULL, address);
103 CHECK_STATUS(status, NT_STATUS_OK);
105 printf("Send a start association request (conn1)\n");
106 status = wrepl_associate(wrepl_socket1, &associate1);
107 CHECK_STATUS(status, NT_STATUS_OK);
109 printf("association context (conn1): 0x%x\n", associate1.out.assoc_ctx);
111 printf("Send a start association request (conn2)\n");
112 status = wrepl_associate(wrepl_socket2, &associate2);
113 CHECK_STATUS(status, NT_STATUS_OK);
115 printf("association context (conn2): 0x%x\n", associate2.out.assoc_ctx);
117 printf("Send a replication table query, with assoc 1 (conn2), the anwser should be on conn1\n");
118 pull_table.in.assoc_ctx = associate1.out.assoc_ctx;
119 req = wrepl_pull_table_send(wrepl_socket2, &pull_table);
120 req->send_only = True;
121 status = wrepl_request_recv(req, mem_ctx, &rep_packet);
122 CHECK_STATUS(status, NT_STATUS_OK);
124 printf("Send a association request (conn2), to make sure the last request was ignored\n");
125 status = wrepl_associate(wrepl_socket2, &associate2);
126 CHECK_STATUS(status, NT_STATUS_OK);
128 printf("Send a replication table query, with invalid assoc (conn1), receive answer from conn2\n");
129 pull_table.in.assoc_ctx = 0;
130 req = wrepl_pull_table_send(wrepl_socket1, &pull_table);
131 status = wrepl_request_recv(req, mem_ctx, &rep_packet);
132 CHECK_STATUS(status, NT_STATUS_OK);
134 printf("Send a association request (conn1), to make sure the last request was handled correct\n");
135 status = wrepl_associate(wrepl_socket1, &associate2);
136 CHECK_STATUS(status, NT_STATUS_OK);
138 assoc_stop.in.assoc_ctx = associate1.out.assoc_ctx;
139 assoc_stop.in.reason = 4;
140 printf("Send a association stop request (conn1), reson: %u\n", assoc_stop.in.reason);
141 status = wrepl_associate_stop(wrepl_socket1, &assoc_stop);
142 CHECK_STATUS(status, NT_STATUS_END_OF_FILE);
144 assoc_stop.in.assoc_ctx = associate2.out.assoc_ctx;
145 assoc_stop.in.reason = 0;
146 printf("Send a association stop request (conn2), reson: %u\n", assoc_stop.in.reason);
147 status = wrepl_associate_stop(wrepl_socket2, &assoc_stop);
148 CHECK_STATUS(status, NT_STATUS_OK);
151 printf("Close 2 wrepl connections\n");
152 talloc_free(wrepl_socket1);
153 talloc_free(wrepl_socket2);
158 test if we always get back the same assoc_ctx
160 static BOOL test_assoc_ctx2(TALLOC_CTX *mem_ctx, const char *address)
163 struct wrepl_socket *wrepl_socket;
164 struct wrepl_associate associate;
168 printf("Test if we always get back the same assoc_ctx\n");
170 wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
172 printf("Setup wrepl connections\n");
173 status = wrepl_connect(wrepl_socket, NULL, address);
174 CHECK_STATUS(status, NT_STATUS_OK);
177 printf("Send 1st start association request\n");
178 status = wrepl_associate(wrepl_socket, &associate);
179 CHECK_STATUS(status, NT_STATUS_OK);
180 assoc_ctx1 = associate.out.assoc_ctx;
181 printf("1st association context: 0x%x\n", associate.out.assoc_ctx);
183 printf("Send 2nd start association request\n");
184 status = wrepl_associate(wrepl_socket, &associate);
185 CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
186 CHECK_STATUS(status, NT_STATUS_OK);
187 printf("2nd association context: 0x%x\n", associate.out.assoc_ctx);
189 printf("Send 3rd start association request\n");
190 status = wrepl_associate(wrepl_socket, &associate);
191 CHECK_VALUE(associate.out.assoc_ctx, assoc_ctx1);
192 CHECK_STATUS(status, NT_STATUS_OK);
193 printf("3rd association context: 0x%x\n", associate.out.assoc_ctx);
196 printf("Close wrepl connections\n");
197 talloc_free(wrepl_socket);
203 display a replication entry
205 static void display_entry(TALLOC_CTX *mem_ctx, struct wrepl_name *name)
209 printf("%s\n", nbt_name_string(mem_ctx, &name->name));
210 printf("\tTYPE:%u STATE:%u NODE:%u STATIC:%u VERSION_ID: %llu\n",
211 name->type, name->state, name->node, name->is_static, name->version_id);
212 printf("\tRAW_FLAGS: 0x%08X OWNER: %-15s\n",
213 name->raw_flags, name->owner);
214 for (i=0;i<name->num_addresses;i++) {
215 printf("\tADDR: %-15s OWNER: %-15s\n",
216 name->addresses[i].address, name->addresses[i].owner);
221 test a full replication dump from a WINS server
223 static BOOL test_wins_replication(TALLOC_CTX *mem_ctx, const char *address)
226 struct wrepl_socket *wrepl_socket;
229 struct wrepl_associate associate;
230 struct wrepl_pull_table pull_table;
231 struct wrepl_pull_names pull_names;
233 printf("Test one pull replication cycle\n");
235 wrepl_socket = wrepl_socket_init(mem_ctx, NULL);
237 printf("Setup wrepl connections\n");
238 status = wrepl_connect(wrepl_socket, NULL, address);
239 CHECK_STATUS(status, NT_STATUS_OK);
241 printf("Send a start association request\n");
243 status = wrepl_associate(wrepl_socket, &associate);
244 CHECK_STATUS(status, NT_STATUS_OK);
246 printf("association context: 0x%x\n", associate.out.assoc_ctx);
248 printf("Send a replication table query\n");
249 pull_table.in.assoc_ctx = associate.out.assoc_ctx;
251 status = wrepl_pull_table(wrepl_socket, mem_ctx, &pull_table);
252 if (NT_STATUS_EQUAL(NT_STATUS_NETWORK_ACCESS_DENIED,status)) {
253 struct wrepl_packet packet;
254 struct wrepl_request *req;
257 packet.opcode = WREPL_OPCODE_BITS;
258 packet.assoc_ctx = associate.out.assoc_ctx;
259 packet.mess_type = WREPL_STOP_ASSOCIATION;
260 packet.message.stop.reason = 0;
262 req = wrepl_request_send(wrepl_socket, &packet);
265 printf("failed - We are not a valid pull partner for the server\n");
269 CHECK_STATUS(status, NT_STATUS_OK);
271 printf("Found %d replication partners\n", pull_table.out.num_partners);
273 for (i=0;i<pull_table.out.num_partners;i++) {
274 struct wrepl_wins_owner *partner = &pull_table.out.partners[i];
275 printf("%s max_version=%6llu min_version=%6llu type=%d\n",
277 partner->max_version,
278 partner->min_version,
281 pull_names.in.assoc_ctx = associate.out.assoc_ctx;
282 pull_names.in.partner = *partner;
284 status = wrepl_pull_names(wrepl_socket, mem_ctx, &pull_names);
285 CHECK_STATUS(status, NT_STATUS_OK);
287 printf("Received %d names\n", pull_names.out.num_names);
289 for (j=0;j<pull_names.out.num_names;j++) {
290 display_entry(mem_ctx, &pull_names.out.names[j]);
295 printf("Close wrepl connections\n");
296 talloc_free(wrepl_socket);
300 struct test_wrepl_conflict_conn {
302 struct wrepl_socket *pull;
305 #define TEST_OWNER_A_ADDRESS "127.65.65.1"
306 #define TEST_ADDRESS_A_PREFIX "127.0.65"
307 #define TEST_OWNER_B_ADDRESS "127.66.66.1"
308 #define TEST_ADDRESS_B_PREFIX "127.0.66"
310 struct wrepl_wins_owner a, b;
313 static const struct wrepl_ip addresses_A_1[] = {
315 .owner = TEST_OWNER_A_ADDRESS,
316 .ip = TEST_ADDRESS_A_PREFIX".1"
319 static const struct wrepl_ip addresses_A_2[] = {
321 .owner = TEST_OWNER_A_ADDRESS,
322 .ip = TEST_ADDRESS_A_PREFIX".2"
326 static const struct wrepl_ip addresses_B_1[] = {
328 .owner = TEST_OWNER_B_ADDRESS,
329 .ip = TEST_ADDRESS_B_PREFIX".1"
332 static const struct wrepl_ip addresses_B_2[] = {
334 .owner = TEST_OWNER_B_ADDRESS,
335 .ip = TEST_ADDRESS_B_PREFIX".2"
339 static struct test_wrepl_conflict_conn *test_create_conflict_ctx(TALLOC_CTX *mem_ctx,
342 struct test_wrepl_conflict_conn *ctx;
343 struct wrepl_associate associate;
344 struct wrepl_pull_table pull_table;
348 ctx = talloc_zero(mem_ctx, struct test_wrepl_conflict_conn);
349 if (!ctx) return NULL;
351 ctx->address = address;
352 ctx->pull = wrepl_socket_init(ctx, NULL);
353 if (!ctx->pull) return NULL;
355 printf("Setup wrepl conflict pull connection\n");
356 status = wrepl_connect(ctx->pull, NULL, ctx->address);
357 if (!NT_STATUS_IS_OK(status)) return NULL;
359 status = wrepl_associate(ctx->pull, &associate);
360 if (!NT_STATUS_IS_OK(status)) return NULL;
362 ctx->pull_assoc = associate.out.assoc_ctx;
364 ctx->a.address = TEST_OWNER_A_ADDRESS;
365 ctx->a.max_version = 0;
366 ctx->a.min_version = 0;
369 ctx->b.address = TEST_OWNER_B_ADDRESS;
370 ctx->b.max_version = 0;
371 ctx->b.min_version = 0;
374 pull_table.in.assoc_ctx = ctx->pull_assoc;
375 status = wrepl_pull_table(ctx->pull, ctx->pull, &pull_table);
376 if (!NT_STATUS_IS_OK(status)) return NULL;
378 for (i=0; i < pull_table.out.num_partners; i++) {
379 if (strcmp(TEST_OWNER_A_ADDRESS,pull_table.out.partners[i].address)==0) {
380 ctx->a.max_version = pull_table.out.partners[i].max_version;
381 ctx->a.min_version = pull_table.out.partners[i].min_version;
383 if (strcmp(TEST_OWNER_B_ADDRESS,pull_table.out.partners[i].address)==0) {
384 ctx->b.max_version = pull_table.out.partners[i].max_version;
385 ctx->b.min_version = pull_table.out.partners[i].min_version;
389 talloc_free(pull_table.out.partners);
394 static BOOL test_wrepl_update_one(struct test_wrepl_conflict_conn *ctx,
395 const struct wrepl_wins_owner *owner,
396 const struct wrepl_wins_name *name)
399 struct wrepl_socket *wrepl_socket;
400 struct wrepl_associate associate;
401 struct wrepl_packet update_packet, repl_send;
402 struct wrepl_table *update;
403 struct wrepl_wins_owner wrepl_wins_owners[1];
404 struct wrepl_packet *repl_recv;
405 struct wrepl_wins_owner *send_request;
406 struct wrepl_send_reply *send_reply;
407 struct wrepl_wins_name wrepl_wins_names[1];
411 wrepl_socket = wrepl_socket_init(ctx, NULL);
413 status = wrepl_connect(wrepl_socket, NULL, ctx->address);
414 CHECK_STATUS(status, NT_STATUS_OK);
416 status = wrepl_associate(wrepl_socket, &associate);
417 CHECK_STATUS(status, NT_STATUS_OK);
418 assoc_ctx = associate.out.assoc_ctx;
420 /* now send a WREPL_REPL_UPDATE message */
421 ZERO_STRUCT(update_packet);
422 update_packet.opcode = WREPL_OPCODE_BITS;
423 update_packet.assoc_ctx = assoc_ctx;
424 update_packet.mess_type = WREPL_REPLICATION;
425 update_packet.message.replication.command = WREPL_REPL_UPDATE;
426 update = &update_packet.message.replication.info.table;
428 update->partner_count = ARRAY_SIZE(wrepl_wins_owners);
429 update->partners = wrepl_wins_owners;
430 update->initiator = "0.0.0.0";
432 wrepl_wins_owners[0] = *owner;
434 status = wrepl_request(wrepl_socket, wrepl_socket,
435 &update_packet, &repl_recv);
436 CHECK_STATUS(status, NT_STATUS_OK);
437 CHECK_VALUE(repl_recv->mess_type, WREPL_REPLICATION);
438 CHECK_VALUE(repl_recv->message.replication.command, WREPL_REPL_SEND_REQUEST);
439 send_request = &repl_recv->message.replication.info.owner;
441 ZERO_STRUCT(repl_send);
442 repl_send.opcode = WREPL_OPCODE_BITS;
443 repl_send.assoc_ctx = assoc_ctx;
444 repl_send.mess_type = WREPL_REPLICATION;
445 repl_send.message.replication.command = WREPL_REPL_SEND_REPLY;
446 send_reply = &repl_send.message.replication.info.reply;
448 send_reply->num_names = ARRAY_SIZE(wrepl_wins_names);
449 send_reply->names = wrepl_wins_names;
451 wrepl_wins_names[0] = *name;
453 status = wrepl_request(wrepl_socket, wrepl_socket,
454 &repl_send, &repl_recv);
455 CHECK_STATUS(status, NT_STATUS_OK);
456 CHECK_VALUE(repl_recv->mess_type, WREPL_STOP_ASSOCIATION);
457 CHECK_VALUE(repl_recv->message.stop.reason, 0);
460 talloc_free(wrepl_socket);
464 static BOOL test_wrepl_is_applied(struct test_wrepl_conflict_conn *ctx,
465 const struct wrepl_wins_owner *owner,
466 const struct wrepl_wins_name *name,
471 struct wrepl_pull_names pull_names;
473 pull_names.in.assoc_ctx = ctx->pull_assoc;
474 pull_names.in.partner = *owner;
475 pull_names.in.partner.min_version = pull_names.in.partner.max_version;
477 status = wrepl_pull_names(ctx->pull, ctx->pull, &pull_names);
478 CHECK_STATUS(status, NT_STATUS_OK);
479 CHECK_VALUE(pull_names.out.num_names, (expected?1:0));
482 talloc_free(pull_names.out.names);
486 static BOOL test_conflict_same_owner(struct test_wrepl_conflict_conn *ctx)
489 struct nbt_name name;
490 struct wrepl_wins_name wins_name1;
491 struct wrepl_wins_name wins_name2;
492 struct wrepl_wins_name *wins_name_tmp;
493 struct wrepl_wins_name *wins_name_last;
494 struct wrepl_wins_name *wins_name_cur;
496 uint8_t types[] = { 0x00, 0x1C };
498 enum wrepl_name_type type;
499 enum wrepl_name_state state;
500 enum wrepl_name_node node;
503 const struct wrepl_ip *ips;
506 .type = WREPL_TYPE_GROUP,
507 .state = WREPL_STATE_ACTIVE,
508 .node = WREPL_NODE_B,
510 .num_ips = ARRAY_SIZE(addresses_A_1),
511 .ips = addresses_A_1,
513 .type = WREPL_TYPE_UNIQUE,
514 .state = WREPL_STATE_ACTIVE,
515 .node = WREPL_NODE_B,
517 .num_ips = ARRAY_SIZE(addresses_A_1),
518 .ips = addresses_A_1,
520 .type = WREPL_TYPE_UNIQUE,
521 .state = WREPL_STATE_ACTIVE,
522 .node = WREPL_NODE_B,
524 .num_ips = ARRAY_SIZE(addresses_A_2),
525 .ips = addresses_A_2,
527 .type = WREPL_TYPE_UNIQUE,
528 .state = WREPL_STATE_ACTIVE,
529 .node = WREPL_NODE_B,
531 .num_ips = ARRAY_SIZE(addresses_A_1),
532 .ips = addresses_A_1,
534 .type = WREPL_TYPE_UNIQUE,
535 .state = WREPL_STATE_ACTIVE,
536 .node = WREPL_NODE_B,
538 .num_ips = ARRAY_SIZE(addresses_A_2),
539 .ips = addresses_A_2,
541 .type = WREPL_TYPE_SGROUP,
542 .state = WREPL_STATE_TOMBSTONE,
543 .node = WREPL_NODE_B,
545 .num_ips = ARRAY_SIZE(addresses_A_2),
546 .ips = addresses_A_2,
548 .type = WREPL_TYPE_MHOMED,
549 .state = WREPL_STATE_TOMBSTONE,
550 .node = WREPL_NODE_B,
552 .num_ips = ARRAY_SIZE(addresses_A_1),
553 .ips = addresses_A_1,
555 .type = WREPL_TYPE_MHOMED,
556 .state = WREPL_STATE_RELEASED,
557 .node = WREPL_NODE_B,
559 .num_ips = ARRAY_SIZE(addresses_A_2),
560 .ips = addresses_A_2,
562 .type = WREPL_TYPE_SGROUP,
563 .state = WREPL_STATE_ACTIVE,
564 .node = WREPL_NODE_B,
566 .num_ips = ARRAY_SIZE(addresses_A_1),
567 .ips = addresses_A_1,
569 /* the last one should always be a unique,tomstone record! */
570 .type = WREPL_TYPE_UNIQUE,
571 .state = WREPL_STATE_TOMBSTONE,
572 .node = WREPL_NODE_B,
574 .num_ips = ARRAY_SIZE(addresses_A_1),
575 .ips = addresses_A_1,
579 if (!ctx) return False;
581 name.name = "_SAME_OWNER_A";
585 wins_name_tmp = NULL;
586 wins_name_last = &wins_name2;
587 wins_name_cur = &wins_name1;
589 for (j=0; ret && j < ARRAY_SIZE(types); j++) {
590 name.type = types[j];
591 printf("Test Replica Conflicts with same owner[%s] for %s\n",
592 nbt_name_string(ctx, &name), ctx->a.address);
594 for(i=0; ret && i < ARRAY_SIZE(records); i++) {
595 wins_name_tmp = wins_name_last;
596 wins_name_last = wins_name_cur;
597 wins_name_cur = wins_name_tmp;
600 printf("%s,%s%s vs, %s,%s%s with %s ip(s) => %s\n",
601 wrepl_name_type_string(records[i-1].type),
602 wrepl_name_state_string(records[i-1].state),
603 (records[i-1].is_static?",static":""),
604 wrepl_name_type_string(records[i].type),
605 wrepl_name_state_string(records[i].state),
606 (records[i].is_static?",static":""),
607 (records[i-1].ips==records[i].ips?"same":"different"),
611 wins_name_cur->name = &name;
612 wins_name_cur->flags = WREPL_NAME_FLAGS(records[i].type,
615 records[i].is_static);
616 wins_name_cur->id = ++ctx->a.max_version;
617 if (wins_name_cur->flags & 2) {
618 wins_name_cur->addresses.addresses.num_ips = records[i].num_ips;
619 wins_name_cur->addresses.addresses.ips = discard_const(records[i].ips);
621 wins_name_cur->addresses.ip = records[i].ips[0].ip;
623 wins_name_cur->unknown = "255.255.255.255";
625 ret &= test_wrepl_update_one(ctx, &ctx->a,wins_name_cur);
626 if (records[i].state == WREPL_STATE_RELEASED) {
627 ret &= test_wrepl_is_applied(ctx, &ctx->a, wins_name_last, False);
628 ret &= test_wrepl_is_applied(ctx, &ctx->a, wins_name_cur, False);
630 ret &= test_wrepl_is_applied(ctx, &ctx->a, wins_name_cur, True);
633 /* the first one is a cleanup run */
634 if (!ret && i == 0) ret = True;
637 printf("conflict handled wrong or record[%u]: %s\n", i, __location__);
645 static BOOL test_conflict_different_owner(struct test_wrepl_conflict_conn *ctx)
648 struct wrepl_wins_name wins_name1;
649 struct wrepl_wins_name wins_name2;
650 struct wrepl_wins_name *wins_name_r1;
651 struct wrepl_wins_name *wins_name_r2;
654 const char *line; /* just better debugging */
655 struct nbt_name name;
657 struct wrepl_wins_owner *owner;
658 enum wrepl_name_type type;
659 enum wrepl_name_state state;
660 enum wrepl_name_node node;
663 const struct wrepl_ip *ips;
668 * NOTE: the first record and the last applied one
669 * needs to be from the same owner,
670 * to not conflict in the next smbtorture run!!!
673 .line = __location__,
674 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
677 .type = WREPL_TYPE_UNIQUE,
678 .state = WREPL_STATE_TOMBSTONE,
679 .node = WREPL_NODE_B,
681 .num_ips = ARRAY_SIZE(addresses_B_1),
682 .ips = addresses_B_1,
683 .apply_expected = True /* ignored */
687 .type = WREPL_TYPE_UNIQUE,
688 .state = WREPL_STATE_TOMBSTONE,
689 .node = WREPL_NODE_B,
691 .num_ips = ARRAY_SIZE(addresses_A_1),
692 .ips = addresses_A_1,
693 .apply_expected = True /* ignored */
698 * unique vs unique section
701 * unique,active vs. unique,active the same ip
702 * => should be replaced
705 .line = __location__,
706 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
709 .type = WREPL_TYPE_UNIQUE,
710 .state = WREPL_STATE_ACTIVE,
711 .node = WREPL_NODE_B,
713 .num_ips = ARRAY_SIZE(addresses_A_1),
714 .ips = addresses_A_1,
715 .apply_expected = True
719 .type = WREPL_TYPE_UNIQUE,
720 .state = WREPL_STATE_ACTIVE,
721 .node = WREPL_NODE_B,
723 .num_ips = ARRAY_SIZE(addresses_A_1),
724 .ips = addresses_A_1,
725 .apply_expected = True
730 * unique,active vs. unique,tombstone the same ips
731 * => should NOT be replaced
734 .line = __location__,
735 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
738 .type = WREPL_TYPE_UNIQUE,
739 .state = WREPL_STATE_ACTIVE,
740 .node = WREPL_NODE_B,
742 .num_ips = ARRAY_SIZE(addresses_B_1),
743 .ips = addresses_B_1,
744 .apply_expected = True
748 .type = WREPL_TYPE_UNIQUE,
749 .state = WREPL_STATE_TOMBSTONE,
750 .node = WREPL_NODE_B,
752 .num_ips = ARRAY_SIZE(addresses_B_1),
753 .ips = addresses_B_1,
754 .apply_expected = False
759 * unique,tombstone vs. unique,active the same ips
760 * => should NOT be replaced
763 .line = __location__,
764 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
767 .type = WREPL_TYPE_UNIQUE,
768 .state = WREPL_STATE_TOMBSTONE,
769 .node = WREPL_NODE_B,
771 .num_ips = ARRAY_SIZE(addresses_B_1),
772 .ips = addresses_B_1,
773 .apply_expected = True
777 .type = WREPL_TYPE_UNIQUE,
778 .state = WREPL_STATE_ACTIVE,
779 .node = WREPL_NODE_B,
781 .num_ips = ARRAY_SIZE(addresses_B_1),
782 .ips = addresses_B_1,
783 .apply_expected = True
788 * unique,tombstone vs. unique,tombstone the same ips
789 * => should be replaced
792 .line = __location__,
793 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
796 .type = WREPL_TYPE_UNIQUE,
797 .state = WREPL_STATE_TOMBSTONE,
798 .node = WREPL_NODE_B,
800 .num_ips = ARRAY_SIZE(addresses_A_1),
801 .ips = addresses_A_1,
802 .apply_expected = True
806 .type = WREPL_TYPE_UNIQUE,
807 .state = WREPL_STATE_TOMBSTONE,
808 .node = WREPL_NODE_B,
810 .num_ips = ARRAY_SIZE(addresses_A_1),
811 .ips = addresses_A_1,
812 .apply_expected = True
817 * unique,active vs. unique,active the different ips
818 * => should be replaced
821 .line = __location__,
822 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
825 .type = WREPL_TYPE_UNIQUE,
826 .state = WREPL_STATE_ACTIVE,
827 .node = WREPL_NODE_B,
829 .num_ips = ARRAY_SIZE(addresses_A_1),
830 .ips = addresses_A_1,
831 .apply_expected = True
835 .type = WREPL_TYPE_UNIQUE,
836 .state = WREPL_STATE_ACTIVE,
837 .node = WREPL_NODE_B,
839 .num_ips = ARRAY_SIZE(addresses_B_1),
840 .ips = addresses_B_1,
841 .apply_expected = True
846 * unique,active vs. unique,tombstone the different ips
847 * => should NOT be replaced
850 .line = __location__,
851 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
854 .type = WREPL_TYPE_UNIQUE,
855 .state = WREPL_STATE_ACTIVE,
856 .node = WREPL_NODE_B,
858 .num_ips = ARRAY_SIZE(addresses_B_1),
859 .ips = addresses_B_1,
860 .apply_expected = True
864 .type = WREPL_TYPE_UNIQUE,
865 .state = WREPL_STATE_TOMBSTONE,
866 .node = WREPL_NODE_B,
868 .num_ips = ARRAY_SIZE(addresses_A_1),
869 .ips = addresses_A_1,
870 .apply_expected = False
875 * unique,tombstone vs. unique,active the different ips
876 * => should be replaced
879 .line = __location__,
880 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
883 .type = WREPL_TYPE_UNIQUE,
884 .state = WREPL_STATE_TOMBSTONE,
885 .node = WREPL_NODE_B,
887 .num_ips = ARRAY_SIZE(addresses_B_1),
888 .ips = addresses_B_1,
889 .apply_expected = True
893 .type = WREPL_TYPE_UNIQUE,
894 .state = WREPL_STATE_ACTIVE,
895 .node = WREPL_NODE_B,
897 .num_ips = ARRAY_SIZE(addresses_A_1),
898 .ips = addresses_A_1,
899 .apply_expected = True
904 * unique,tombstone vs. unique,tombstone the different ips
905 * => should be replaced
908 .line = __location__,
909 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
912 .type = WREPL_TYPE_UNIQUE,
913 .state = WREPL_STATE_TOMBSTONE,
914 .node = WREPL_NODE_B,
916 .num_ips = ARRAY_SIZE(addresses_A_1),
917 .ips = addresses_A_1,
918 .apply_expected = True
922 .type = WREPL_TYPE_UNIQUE,
923 .state = WREPL_STATE_TOMBSTONE,
924 .node = WREPL_NODE_B,
926 .num_ips = ARRAY_SIZE(addresses_B_1),
927 .ips = addresses_B_1,
928 .apply_expected = True
933 * unique vs normal groups section,
934 * TODO: group,released!
937 * unique,active vs. group,active
938 * => should be replaced
941 .line = __location__,
942 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
945 .type = WREPL_TYPE_UNIQUE,
946 .state = WREPL_STATE_ACTIVE,
947 .node = WREPL_NODE_B,
949 .num_ips = ARRAY_SIZE(addresses_B_1),
950 .ips = addresses_B_1,
951 .apply_expected = True
955 .type = WREPL_TYPE_GROUP,
956 .state = WREPL_STATE_ACTIVE,
957 .node = WREPL_NODE_B,
959 .num_ips = ARRAY_SIZE(addresses_A_1),
960 .ips = addresses_A_1,
961 .apply_expected = True
966 * unique,active vs. group,tombstone same ip
967 * => should NOT be replaced
970 .line = __location__,
971 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
974 .type = WREPL_TYPE_UNIQUE,
975 .state = WREPL_STATE_ACTIVE,
976 .node = WREPL_NODE_B,
978 .num_ips = ARRAY_SIZE(addresses_A_1),
979 .ips = addresses_A_1,
980 .apply_expected = True
984 .type = WREPL_TYPE_GROUP,
985 .state = WREPL_STATE_TOMBSTONE,
986 .node = WREPL_NODE_B,
988 .num_ips = ARRAY_SIZE(addresses_A_1),
989 .ips = addresses_A_1,
990 .apply_expected = False
995 * unique,active vs. group,tombstone different ip
996 * => should NOT be replaced
999 .line = __location__,
1000 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1003 .type = WREPL_TYPE_UNIQUE,
1004 .state = WREPL_STATE_ACTIVE,
1005 .node = WREPL_NODE_B,
1007 .num_ips = ARRAY_SIZE(addresses_A_1),
1008 .ips = addresses_A_1,
1009 .apply_expected = True
1013 .type = WREPL_TYPE_GROUP,
1014 .state = WREPL_STATE_TOMBSTONE,
1015 .node = WREPL_NODE_B,
1017 .num_ips = ARRAY_SIZE(addresses_B_1),
1018 .ips = addresses_B_1,
1019 .apply_expected = False
1024 * unique,active vs. group,released
1025 * => should NOT be replaced
1028 .line = __location__,
1029 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1032 .type = WREPL_TYPE_UNIQUE,
1033 .state = WREPL_STATE_ACTIVE,
1034 .node = WREPL_NODE_B,
1036 .num_ips = ARRAY_SIZE(addresses_A_1),
1037 .ips = addresses_A_1,
1038 .apply_expected = True
1042 .type = WREPL_TYPE_GROUP,
1043 .state = WREPL_STATE_RELEASED,
1044 .node = WREPL_NODE_B,
1046 .num_ips = ARRAY_SIZE(addresses_B_1),
1047 .ips = addresses_B_1,
1048 .apply_expected = False
1053 * unique,tombstone vs. group,active
1054 * => should be replaced
1057 .line = __location__,
1058 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1061 .type = WREPL_TYPE_UNIQUE,
1062 .state = WREPL_STATE_TOMBSTONE,
1063 .node = WREPL_NODE_B,
1065 .num_ips = ARRAY_SIZE(addresses_A_1),
1066 .ips = addresses_A_1,
1067 .apply_expected = True
1071 .type = WREPL_TYPE_GROUP,
1072 .state = WREPL_STATE_ACTIVE,
1073 .node = WREPL_NODE_B,
1075 .num_ips = ARRAY_SIZE(addresses_B_1),
1076 .ips = addresses_B_1,
1077 .apply_expected = True
1082 * unique,tombstone vs. group,tombstone
1083 * => should be replaced
1086 .line = __location__,
1087 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1090 .type = WREPL_TYPE_UNIQUE,
1091 .state = WREPL_STATE_TOMBSTONE,
1092 .node = WREPL_NODE_B,
1094 .num_ips = ARRAY_SIZE(addresses_B_1),
1095 .ips = addresses_B_1,
1096 .apply_expected = True
1100 .type = WREPL_TYPE_GROUP,
1101 .state = WREPL_STATE_TOMBSTONE,
1102 .node = WREPL_NODE_B,
1104 .num_ips = ARRAY_SIZE(addresses_A_1),
1105 .ips = addresses_A_1,
1106 .apply_expected = True
1111 * unique,tombstone vs. group,released
1112 * => should be replaced
1115 .line = __location__,
1116 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1119 .type = WREPL_TYPE_UNIQUE,
1120 .state = WREPL_STATE_TOMBSTONE,
1121 .node = WREPL_NODE_B,
1123 .num_ips = ARRAY_SIZE(addresses_A_1),
1124 .ips = addresses_A_1,
1125 .apply_expected = True
1129 .type = WREPL_TYPE_GROUP,
1130 .state = WREPL_STATE_RELEASED,
1131 .node = WREPL_NODE_B,
1133 .num_ips = ARRAY_SIZE(addresses_B_1),
1134 .ips = addresses_B_1,
1135 .apply_expected = True
1140 * unique,released vs. group,released
1141 * => should be replaced
1144 .line = __location__,
1145 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1148 .type = WREPL_TYPE_UNIQUE,
1149 .state = WREPL_STATE_RELEASED,
1150 .node = WREPL_NODE_B,
1152 .num_ips = ARRAY_SIZE(addresses_B_1),
1153 .ips = addresses_B_1,
1154 .apply_expected = False
1158 .type = WREPL_TYPE_GROUP,
1159 .state = WREPL_STATE_RELEASED,
1160 .node = WREPL_NODE_B,
1162 .num_ips = ARRAY_SIZE(addresses_A_1),
1163 .ips = addresses_A_1,
1164 .apply_expected = True
1169 * unique,released vs. group,released
1170 * => should be replaced
1173 .line = __location__,
1174 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1177 .type = WREPL_TYPE_UNIQUE,
1178 .state = WREPL_STATE_RELEASED,
1179 .node = WREPL_NODE_B,
1181 .num_ips = ARRAY_SIZE(addresses_A_1),
1182 .ips = addresses_A_1,
1183 .apply_expected = False
1187 .type = WREPL_TYPE_GROUP,
1188 .state = WREPL_STATE_TOMBSTONE,
1189 .node = WREPL_NODE_B,
1191 .num_ips = ARRAY_SIZE(addresses_B_1),
1192 .ips = addresses_B_1,
1193 .apply_expected = True
1198 * group,active vs. unique,active
1199 * => should NOT be replaced
1202 .line = __location__,
1203 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1206 .type = WREPL_TYPE_GROUP,
1207 .state = WREPL_STATE_ACTIVE,
1208 .node = WREPL_NODE_B,
1210 .num_ips = ARRAY_SIZE(addresses_A_1),
1211 .ips = addresses_A_1,
1212 .apply_expected = True
1216 .type = WREPL_TYPE_UNIQUE,
1217 .state = WREPL_STATE_TOMBSTONE,
1218 .node = WREPL_NODE_B,
1220 .num_ips = ARRAY_SIZE(addresses_B_1),
1221 .ips = addresses_B_1,
1222 .apply_expected = False
1227 * group,active vs. unique,tombstone
1228 * => should NOT be replaced
1231 .line = __location__,
1232 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1235 .type = WREPL_TYPE_GROUP,
1236 .state = WREPL_STATE_ACTIVE,
1237 .node = WREPL_NODE_B,
1239 .num_ips = ARRAY_SIZE(addresses_A_1),
1240 .ips = addresses_A_1,
1241 .apply_expected = True
1245 .type = WREPL_TYPE_UNIQUE,
1246 .state = WREPL_STATE_TOMBSTONE,
1247 .node = WREPL_NODE_B,
1249 .num_ips = ARRAY_SIZE(addresses_B_1),
1250 .ips = addresses_B_1,
1251 .apply_expected = False
1256 * group,released vs. unique,active
1257 * => should NOT be replaced
1260 .line = __location__,
1261 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1264 .type = WREPL_TYPE_GROUP,
1265 .state = WREPL_STATE_RELEASED,
1266 .node = WREPL_NODE_B,
1268 .num_ips = ARRAY_SIZE(addresses_A_1),
1269 .ips = addresses_A_1,
1270 .apply_expected = False
1274 .type = WREPL_TYPE_UNIQUE,
1275 .state = WREPL_STATE_ACTIVE,
1276 .node = WREPL_NODE_B,
1278 .num_ips = ARRAY_SIZE(addresses_B_1),
1279 .ips = addresses_B_1,
1280 .apply_expected = False
1285 * group,released vs. unique,tombstone
1286 * => should NOT be replaced
1289 .line = __location__,
1290 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1293 .type = WREPL_TYPE_GROUP,
1294 .state = WREPL_STATE_RELEASED,
1295 .node = WREPL_NODE_B,
1297 .num_ips = ARRAY_SIZE(addresses_A_1),
1298 .ips = addresses_A_1,
1299 .apply_expected = False
1303 .type = WREPL_TYPE_UNIQUE,
1304 .state = WREPL_STATE_TOMBSTONE,
1305 .node = WREPL_NODE_B,
1307 .num_ips = ARRAY_SIZE(addresses_B_1),
1308 .ips = addresses_B_1,
1309 .apply_expected = False
1314 * group,tombstone vs. unique,active
1315 * => should NOT be replaced
1318 .line = __location__,
1319 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1322 .type = WREPL_TYPE_GROUP,
1323 .state = WREPL_STATE_TOMBSTONE,
1324 .node = WREPL_NODE_B,
1326 .num_ips = ARRAY_SIZE(addresses_A_1),
1327 .ips = addresses_A_1,
1328 .apply_expected = True
1332 .type = WREPL_TYPE_UNIQUE,
1333 .state = WREPL_STATE_ACTIVE,
1334 .node = WREPL_NODE_B,
1336 .num_ips = ARRAY_SIZE(addresses_B_1),
1337 .ips = addresses_B_1,
1338 .apply_expected = False
1343 * group,tombstone vs. unique,tombstone
1344 * => should NOT be replaced
1347 .line = __location__,
1348 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1351 .type = WREPL_TYPE_GROUP,
1352 .state = WREPL_STATE_TOMBSTONE,
1353 .node = WREPL_NODE_B,
1355 .num_ips = ARRAY_SIZE(addresses_A_1),
1356 .ips = addresses_A_1,
1357 .apply_expected = True
1361 .type = WREPL_TYPE_UNIQUE,
1362 .state = WREPL_STATE_TOMBSTONE,
1363 .node = WREPL_NODE_B,
1365 .num_ips = ARRAY_SIZE(addresses_B_1),
1366 .ips = addresses_B_1,
1367 .apply_expected = False
1372 * This should be the last record in this array,
1373 * we need to make sure the we leave a tombstoned unique entry
1377 .line = __location__,
1378 .name = _NBT_NAME("_DIFF_OWNER", 0x00, NULL),
1381 .type = WREPL_TYPE_UNIQUE,
1382 .state = WREPL_STATE_TOMBSTONE,
1383 .node = WREPL_NODE_B,
1385 .num_ips = ARRAY_SIZE(addresses_A_1),
1386 .ips = addresses_A_1,
1387 .apply_expected = True
1391 .type = WREPL_TYPE_UNIQUE,
1392 .state = WREPL_STATE_TOMBSTONE,
1393 .node = WREPL_NODE_B,
1395 .num_ips = ARRAY_SIZE(addresses_A_1),
1396 .ips = addresses_A_1,
1397 .apply_expected = True
1399 }}; /* do not add entries here, this should be the last record! */
1401 if (!ctx) return False;
1403 wins_name_r1 = &wins_name1;
1404 wins_name_r2 = &wins_name2;
1406 printf("Test Replica Conflicts with different owners\n");
1408 for(i=0; ret && i < ARRAY_SIZE(records); i++) {
1411 printf("%s,%s%s vs, %s,%s%s with %s ip(s) => %s\n",
1412 wrepl_name_type_string(records[i].r1.type),
1413 wrepl_name_state_string(records[i].r1.state),
1414 (records[i].r1.is_static?",static":""),
1415 wrepl_name_type_string(records[i].r2.type),
1416 wrepl_name_state_string(records[i].r2.state),
1417 (records[i].r2.is_static?",static":""),
1418 (records[i].r1.ips==records[i].r2.ips?"same":"different"),
1419 (records[i].r2.apply_expected?"REPLACE":"NOT REPLACE"));
1425 wins_name_r1->name = &records[i].name;
1426 wins_name_r1->flags = WREPL_NAME_FLAGS(records[i].r1.type,
1427 records[i].r1.state,
1429 records[i].r1.is_static);
1430 wins_name_r1->id = ++records[i].r1.owner->max_version;
1431 if (wins_name_r1->flags & 2) {
1432 wins_name_r1->addresses.addresses.num_ips = records[i].r1.num_ips;
1433 wins_name_r1->addresses.addresses.ips = discard_const(records[i].r1.ips);
1435 wins_name_r1->addresses.ip = records[i].r1.ips[0].ip;
1437 wins_name_r1->unknown = "255.255.255.255";
1440 ret &= test_wrepl_update_one(ctx, records[i].r1.owner, wins_name_r1);
1441 ret &= test_wrepl_is_applied(ctx, records[i].r1.owner,
1442 wins_name_r1, records[i].r1.apply_expected);
1447 wins_name_r2->name = &records[i].name;
1448 wins_name_r2->flags = WREPL_NAME_FLAGS(records[i].r2.type,
1449 records[i].r2.state,
1451 records[i].r2.is_static);
1452 wins_name_r2->id = ++records[i].r2.owner->max_version;
1453 if (wins_name_r2->flags & 2) {
1454 wins_name_r2->addresses.addresses.num_ips = records[i].r2.num_ips;
1455 wins_name_r2->addresses.addresses.ips = discard_const(records[i].r2.ips);
1457 wins_name_r2->addresses.ip = records[i].r2.ips[0].ip;
1459 wins_name_r2->unknown = "255.255.255.255";
1462 ret &= test_wrepl_update_one(ctx, records[i].r2.owner, wins_name_r2);
1463 if (records[i].r2.apply_expected &&
1464 (records[i].r1.state == WREPL_STATE_RELEASED ||
1465 records[i].r2.state == WREPL_STATE_RELEASED)) {
1466 ret &= test_wrepl_is_applied(ctx, records[i].r1.owner,
1467 wins_name_r1, False);
1469 if (records[i].r2.state == WREPL_STATE_RELEASED) {
1470 ret &= test_wrepl_is_applied(ctx, records[i].r2.owner,
1471 wins_name_r2, False);
1473 ret &= test_wrepl_is_applied(ctx, records[i].r2.owner,
1474 wins_name_r2, records[i].r2.apply_expected);
1477 /* the first one is a cleanup run */
1478 if (!ret && i == 0) ret = True;
1481 printf("conflict handled wrong or record[%u]: %s\n", i, records[i].line);
1490 test WINS replication operations
1492 BOOL torture_nbt_winsreplication(void)
1494 const char *address;
1495 struct nbt_name name;
1496 TALLOC_CTX *mem_ctx = talloc_new(NULL);
1499 struct test_wrepl_conflict_conn *ctx;
1501 make_nbt_name_server(&name, lp_parm_string(-1, "torture", "host"));
1503 /* do an initial name resolution to find its IP */
1504 status = resolve_name(&name, mem_ctx, &address, NULL);
1505 if (!NT_STATUS_IS_OK(status)) {
1506 printf("Failed to resolve %s - %s\n",
1507 name.name, nt_errstr(status));
1508 talloc_free(mem_ctx);
1512 ret &= test_assoc_ctx1(mem_ctx, address);
1513 ret &= test_assoc_ctx2(mem_ctx, address);
1515 ret &= test_wins_replication(mem_ctx, address);
1517 ctx = test_create_conflict_ctx(mem_ctx, address);
1519 ret &= test_conflict_same_owner(ctx);
1520 ret &= test_conflict_different_owner(ctx);
1522 talloc_free(mem_ctx);