1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2011, 2013 Oracle and/or its affiliates. All rights reserved.
5 */
6
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <db.h>
10 #include <assert.h>
11 #include <string.h>
12 #include <time.h>
13 #include <stdlib.h>
14 #include <errno.h>
15 #ifndef _WIN32
16 #include <pthread.h>
17 #include <unistd.h>
18 #include <sys/select.h>
19 #include <sys/uio.h>
20 #endif
21
22 #include "CuTest.h"
23 #include "test_util.h"
24
25 #define MAX_SEGS 10
26 #define MAX_MSGS 10
27
28 #undef LOCK_MUTEX
29 #undef UNLOCK_MUTEX
30 #ifdef _WIN32
31 #define sleep(s) Sleep(1000 * (s))
32 typedef HANDLE mutex_t;
33 #define mutex_init(m) \
34 (((*(m) = CreateMutex(NULL, FALSE, NULL)) != NULL) ? 0 : -1)
35 #define mutex_lock(m) \
36 ((WaitForSingleObject(*(m), INFINITE) == WAIT_OBJECT_0) ? \
37 0 : GetLastError())
38 #define mutex_unlock(m) (ReleaseMutex(*(m)) ? 0 : GetLastError())
39 #define mutex_destroy(m) (CloseHandle(*(m)) ? 0 : GetLastError())
40 typedef HANDLE cond_t;
41 #define cond_init(c) ((*(c) = CreateEvent(NULL, \
42 TRUE, FALSE, NULL)) == NULL ? GetLastError() : 0)
43 #define cond_wait(c, m) (SignalObjectAndWait(*(m), *(c), INFINITE, FALSE) == WAIT_OBJECT_0 ? \
44 0 : GetLastError())
45 #define cond_wake(c) (SetEvent(*(c)) ? 0 : GetLastError())
46 #else
47 typedef pthread_mutex_t mutex_t;
48 #define mutex_init(m) pthread_mutex_init((m), NULL)
49 #define mutex_lock(m) pthread_mutex_lock(m)
50 #define mutex_unlock(m) pthread_mutex_unlock(m)
51 #define mutex_destroy(m) pthread_mutex_destroy(m)
52 typedef pthread_cond_t cond_t;
53 #define cond_init(c) pthread_cond_init((c), NULL)
54 #define cond_wait(c, m) pthread_cond_wait((c), (m))
55 #define cond_wake(c) pthread_cond_broadcast(c)
56 #endif
57
58 struct channel_test_globals {
59 CuTest *test;
60 mutex_t mtx;
61 cond_t cond;
62 u_int *ports;
63 int ports_cnt;
64 };
65
66 struct report {
67 int dbt_count;
68 DBT dbt[MAX_SEGS];
69
70 int msg_count;
71 char *msg[MAX_MSGS];
72
73 int done, ret;
74 };
75
76 struct reports {
77 mutex_t m;
78 int count;
79 struct report rpt[2];
80 };
81
82 struct env_info {
83 struct report *rpt;
84 struct reports *rpts;
85 struct channel_test_globals *g;
86 int startupdone;
87 };
88
89 struct msginfo {
90 DB_ENV *dbenv;
91 int count;
92 };
93
94 typedef int (*PRED) __P((void *));
95
96 static int await_condition __P((PRED, void *, long));
97 static int check_dbt_string __P((DBT *, const char *));
98 static void clear_rpt __P((DB_ENV *));
99 static void clear_rpt_int __P((struct report *));
100 static int env_done __P((void *));
101 static struct report *get_rpt __P((const DB_ENV *));
102 static int fortify __P((DB_ENV *, struct channel_test_globals *));
103 static int get_avail_ports __P((u_int *, int));
104 static int has_msgs __P((void *));
105 static void msg_disp __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
106 static void msg_disp2 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
107 static void msg_disp3 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
108 static void msg_disp4 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
109 static void msg_disp5 __P((DB_ENV *, DB_CHANNEL *, DBT *, u_int32_t, u_int32_t));
110 static int mystrcmp __P((char *, const char *));
111 static void notify __P((DB_ENV *, u_int32_t, void *));
112 static int is_started __P((void *));
113 static void td __P((DB_ENV *));
114 static void test_data_init __P((DBT *, char *));
115 static void test_zeroes __P((DB_CHANNEL *, DB_ENV *, CuTest *));
116 static int two_done __P((void *));
117
118 #define LOCK_MUTEX(m) do { \
119 int __ret; \
120 __ret = mutex_lock(m); \
121 assert(__ret == 0); \
122 } while (0)
123
124 #define UNLOCK_MUTEX(m) do { \
125 int __ret; \
126 __ret = mutex_unlock(m); \
127 assert(__ret == 0); \
128 } while (0)
129
TestChannelSuiteSetup(CuSuite * suite)130 int TestChannelSuiteSetup(CuSuite *suite) {
131 return (0);
132 }
133
TestChannelSuiteTeardown(CuSuite * suite)134 int TestChannelSuiteTeardown(CuSuite *suite) {
135 return (0);
136 }
137
TestChannelTestSetup(CuTest * test)138 int TestChannelTestSetup(CuTest *test) {
139 struct channel_test_globals *g;
140 int ret;
141
142 if ((g = calloc(1, sizeof(*g))) == NULL)
143 return (ENOMEM);
144 if ((ret = mutex_init(&g->mtx)) != 0) {
145 free(g);
146 return (ret);
147 }
148 if ((ret = cond_init(&g->cond)) != 0) {
149 mutex_destroy(&g->mtx);
150 free(g);
151 return (ret);
152 }
153 g->test = test;
154 test->context = g;
155 return (0);
156 }
157
TestChannelTestTeardown(CuTest * test)158 int TestChannelTestTeardown(CuTest *test) {
159 struct channel_test_globals *g;
160 int ret;
161
162 g = test->context;
163 assert(g != NULL);
164 ret = mutex_destroy(&g->mtx);
165 free(g);
166 test->context = NULL;
167 return (ret);
168 }
169
170 static void
myerrcall(const DB_ENV * dbenv,const char * errpfx,const char * msg)171 myerrcall(const DB_ENV *dbenv, const char *errpfx, const char *msg) {
172 struct report *rpt = get_rpt(dbenv);
173
174 assert(rpt->msg_count < MAX_MSGS);
175 assert((rpt->msg[rpt->msg_count++] = strdup(msg)) != NULL);
176 }
177
178 static int
fortify(dbenv,g)179 fortify(dbenv, g)
180 DB_ENV *dbenv;
181 struct channel_test_globals *g;
182 {
183 struct report *rpt;
184 struct env_info *info;
185
186 if ((info = calloc(1, sizeof(*info))) == NULL)
187 return (ENOMEM);
188 if ((rpt = calloc(1, sizeof(*rpt))) == NULL) {
189 free(info);
190 return (ENOMEM);
191 }
192 info->rpt = rpt;
193 info->rpts = NULL;
194 info->g = g;
195 info->startupdone = 0;
196 dbenv->app_private = info;
197 return (0);
198 }
199
200 static int
setup(envp1,envp2,envp3,g)201 setup(envp1, envp2, envp3, g)
202 DB_ENV **envp1, **envp2, **envp3;
203 struct channel_test_globals *g;
204 {
205 DB_ENV *dbenv1, *dbenv2, *dbenv3;
206 DB_SITE *dbsite;
207 u_int32_t flags;
208 int ret;
209 u_int *ports;
210
211 #define CHECK(call) \
212 do { \
213 if ((ret = (call)) != 0) { \
214 fprintf(stderr, "error %d from %s", ret, #call); \
215 goto err; \
216 } \
217 } while (0);
218
219 ports = g->ports;
220
221 dbenv1 = dbenv2 = dbenv3 = NULL;
222 CHECK(db_env_create(&dbenv1, 0));
223 CHECK(fortify(dbenv1, g));
224 dbenv1->set_errpfx(dbenv1, "ENV1");
225 dbenv1->set_errcall(dbenv1, myerrcall);
226 flags = DB_INIT_REP | DB_INIT_LOG | DB_INIT_LOCK | DB_INIT_MPOOL |
227 DB_INIT_TXN | DB_RECOVER | DB_THREAD | DB_CREATE;
228 setup_envdir("DIR1", 1);
229 CHECK(dbenv1->open(dbenv1, "DIR1", flags, 0));
230
231 CHECK(dbenv1->rep_set_config(dbenv1, DB_REPMGR_CONF_ELECTIONS, 0));
232 CHECK(dbenv1->repmgr_site(dbenv1, "localhost", ports[0], &dbsite, 0));
233 CHECK(dbsite->set_config(dbsite, DB_LOCAL_SITE, 1));
234 CHECK(dbsite->close(dbsite));
235 CHECK(dbenv1->set_event_notify(dbenv1, notify));
236 CHECK(dbenv1->repmgr_msg_dispatch(dbenv1, msg_disp, 0));
237 CHECK(dbenv1->repmgr_start(dbenv1, 2, DB_REP_MASTER));
238
239 CHECK(db_env_create(&dbenv2, 0));
240 CHECK(fortify(dbenv2, g));
241 dbenv2->set_errpfx(dbenv2, "ENV2");
242 dbenv2->set_errcall(dbenv2, myerrcall);
243 setup_envdir("DIR2", 1);
244 CHECK(dbenv2->open(dbenv2, "DIR2", flags, 0));
245 CHECK(dbenv2->rep_set_config(dbenv2, DB_REPMGR_CONF_ELECTIONS, 0));
246
247 CHECK(dbenv2->repmgr_site(dbenv2, "localhost", ports[1], &dbsite, 0));
248 CHECK(dbsite->set_config(dbsite, DB_LOCAL_SITE, 1));
249 CHECK(dbsite->close(dbsite));
250 CHECK(dbenv2->repmgr_site(dbenv2, "localhost", ports[0], &dbsite, 0));
251 CHECK(dbsite->set_config(dbsite, DB_BOOTSTRAP_HELPER, 1));
252 CHECK(dbsite->close(dbsite));
253 CHECK(dbenv2->set_event_notify(dbenv2, notify));
254 CHECK(dbenv2->repmgr_start(dbenv2, 2, DB_REP_CLIENT));
255
256 await_condition(is_started, dbenv2, 60);
257 if (!is_started(dbenv2)) {
258 dbenv2->errx(dbenv2, "startup done not achieved in 60 seconds");
259 ret = DB_TIMEOUT;
260 goto err;
261 }
262
263 CHECK(db_env_create(&dbenv3, 0));
264 CHECK(fortify(dbenv3, g));
265 dbenv3->set_errpfx(dbenv3, "ENV3");
266 dbenv3->set_errcall(dbenv3, myerrcall);
267 CHECK(dbenv3->repmgr_msg_dispatch(dbenv3, msg_disp2, 0));
268 setup_envdir("DIR3", 1);
269 CHECK(dbenv3->open(dbenv3, "DIR3", flags, 0));
270 CHECK(dbenv3->rep_set_config(dbenv3, DB_REPMGR_CONF_ELECTIONS, 0));
271
272 CHECK(dbenv3->repmgr_site(dbenv3, "localhost", ports[2], &dbsite, 0));
273 CHECK(dbsite->set_config(dbsite, DB_LOCAL_SITE, 1));
274 CHECK(dbsite->close(dbsite));
275 CHECK(dbenv3->repmgr_site(dbenv3, "localhost", ports[0], &dbsite, 0));
276 CHECK(dbsite->set_config(dbsite, DB_BOOTSTRAP_HELPER, 1));
277 CHECK(dbsite->close(dbsite));
278 CHECK(dbenv3->set_event_notify(dbenv3, notify));
279 CHECK(dbenv3->repmgr_start(dbenv3, 2, DB_REP_CLIENT));
280
281 await_condition(is_started, dbenv3, 60);
282 if (!is_started(dbenv3)) {
283 dbenv3->errx(dbenv3, "startup done not achieved in 60 seconds");
284 ret = DB_TIMEOUT;
285 goto err;
286 }
287
288 *envp1 = dbenv1;
289 *envp2 = dbenv2;
290 *envp3 = dbenv3;
291 return (0);
292
293 err:
294 if (dbenv3 != NULL)
295 td(dbenv3);
296 if (dbenv2 != NULL)
297 td(dbenv2);
298 if (dbenv1 != NULL)
299 td(dbenv1);
300 return (ret);
301 }
302
303 static void
td(dbenv)304 td(dbenv)
305 DB_ENV *dbenv;
306 {
307 struct env_info *info;
308
309 dbenv->set_errcall(dbenv, NULL);
310 dbenv->set_event_notify(dbenv, NULL);
311
312 info = dbenv->app_private;
313 dbenv->close(dbenv, 0);
314 if (info != NULL) {
315 clear_rpt_int(info->rpt);
316 free(info->rpt);
317 free(info);
318 }
319 }
320
321 static void
clear_rpt_int(rpt)322 clear_rpt_int(rpt)
323 struct report *rpt;
324 {
325 int i;
326
327 for (i = 0; i < rpt->dbt_count; i++)
328 free(rpt->dbt[i].data);
329 rpt->dbt_count = 0;
330
331 for (i = 0; i < rpt->msg_count; i++)
332 free(rpt->msg[i]);
333 rpt->msg_count = 0;
334
335 rpt->done = 0;
336 }
337
338 static void
clear_rpt(dbenv)339 clear_rpt(dbenv)
340 DB_ENV *dbenv;
341 {
342 struct env_info *info;
343 struct report *rpt;
344
345 info = dbenv->app_private;
346 rpt = info->rpt;
347 clear_rpt_int(rpt);
348 }
349
350 static int
env_done(ctx)351 env_done(ctx)
352 void *ctx;
353 {
354 DB_ENV *dbenv = ctx;
355 struct report *rpt = get_rpt(dbenv);
356
357 return (rpt->done);
358 }
359
360 static void
await_done(dbenv)361 await_done(dbenv)
362 DB_ENV *dbenv;
363 {
364 await_condition(env_done, dbenv, 60);
365 assert(env_done(dbenv));
366 }
367
368 static int
has_msgs(ctx)369 has_msgs(ctx)
370 void *ctx;
371 {
372 struct msginfo *inf = ctx;
373 DB_ENV *dbenv = inf->dbenv;
374 struct report *rpt = get_rpt(dbenv);
375
376 return (rpt->msg_count == inf->count);
377 }
378
379 static struct report *
get_rpt(dbenv)380 get_rpt(dbenv)
381 const DB_ENV *dbenv;
382 {
383 struct env_info *info;
384
385 if ((info = dbenv->app_private) == NULL)
386 return (NULL);
387 return (info->rpt);
388 }
389
TestChannelFeature(CuTest * ct)390 int TestChannelFeature(CuTest *ct) {
391 /* Run this test only when replication is supported. */
392 #ifdef HAVE_REPLICATION
393 DB_ENV *dbenv1, *dbenv2, *dbenv3;
394 DB_CHANNEL *ch;
395 DB_REP_STAT *stats;
396 DB_SITE *dbsite;
397 DBT dbt, rdbts[10], resp;
398 struct channel_test_globals *g;
399 struct report *rpt;
400 struct reports rpts;
401 struct msginfo info;
402 char *p;
403 void *pointer, *vp, *buffer;
404 u_int8_t short_buf[4];
405 size_t sz;
406 int done, eid, ret;
407 u_int ports[3];
408
409 #ifdef _WIN32
410 setvbuf(stdout, NULL, _IONBF, 0);
411 #endif
412 printf("this is a test for repmgr channels feature\n");
413
414 g = ct->context;
415 ret = get_avail_ports(ports, 3);
416 CuAssertTrue(ct, (ret == 0));
417
418 g->ports = ports;
419 g->ports_cnt = 3;
420
421 printf("use ports: {%u, %u, %u}\n", ports[0], ports[1], ports[2]);
422
423 /*
424 * The ports[0] will be the local port for dbenv1, ports[1] for dbenv2,
425 * and ports[2] for dbenv3.
426 */
427 CuAssertTrue(ct, (ret = setup(&dbenv1, &dbenv2, &dbenv3, g) == 0));
428
429 /*
430 * For this first section, we're sending to ENV2.
431 */
432 CuAssertTrue(ct,
433 (ret = dbenv1->repmgr_site(dbenv1,
434 "localhost", ports[1], &dbsite, 0)) == 0);
435 CuAssertTrue(ct, (ret = dbsite->get_eid(dbsite, &eid)) == 0);
436 CuAssertTrue(ct, (ret = dbsite->close(dbsite)) == 0);
437 CuAssertTrue(ct, (ret = dbenv1->repmgr_channel(dbenv1, eid, &ch, 0)) == 0);
438
439 memset(&dbt, 0, sizeof(dbt));
440 p = "foobar";
441 dbt.data = p;
442 dbt.size = (u_int32_t)strlen(p) + 1;
443 memset(&resp, 0, sizeof(resp));
444 resp.flags = DB_DBT_MALLOC;
445 printf("1. send async msg with no msg dispatch in place\n");
446 clear_rpt(dbenv2);
447 CuAssertTrue(ct, (ret = ch->send_msg(ch, &dbt, 1, 0)) == 0);
448
449 /* Wait til dbenv2 has reported 1 msg. */
450 info.dbenv = dbenv2;
451 info.count = 1;
452 await_condition(has_msgs, &info, 60);
453 rpt = get_rpt(dbenv2);
454 CuAssertTrue(ct, rpt->msg_count == 1);
455 CuAssertTrue(ct, mystrcmp(rpt->msg[0],
456 "No message dispatch call-back function has been configured") == 0);
457
458 printf("2. send request with no msg dispatch in place\n");
459 clear_rpt(dbenv2);
460 ret = ch->send_request(ch, &dbt, 1, &resp, 0, 0);
461 CuAssertTrue(ct, ret == DB_NOSERVER);
462 if (resp.data != NULL)
463 free(resp.data);
464 await_condition(has_msgs, &info, 60);
465 CuAssertTrue(ct, rpt->msg_count == 1);
466 CuAssertTrue(ct, mystrcmp(rpt->msg[0],
467 "No message dispatch call-back function has been configured") == 0);
468
469 CuAssertTrue(ct, (ret = dbenv2->repmgr_msg_dispatch(dbenv2, msg_disp, 0)) == 0);
470
471 printf("3. send request where recip forgot resp\n");
472 clear_rpt(dbenv2);
473 ret = ch->send_request(ch, &dbt, 1, &resp, 0, 0);
474 CuAssertTrue(ct, ret == DB_KEYEMPTY);
475 if (resp.data != NULL)
476 free(resp.data);
477 await_done(dbenv2);
478 CuAssertTrue(ct, rpt->msg_count == 1);
479 CuAssertTrue(ct, mystrcmp(rpt->msg[0],
480 "Application failed to provide a response") == 0);
481
482 printf("4. now with dispatch fn installed, send a simple async msg\n");
483 clear_rpt(dbenv2);
484 test_data_init(&dbt, "Mr. Watson -- come here -- I want to see you.");
485 CuAssertTrue(ct, (ret = ch->send_msg(ch, &dbt, 1, 0)) == 0);
486 await_done(dbenv2);
487 CuAssertTrue(ct, rpt->dbt_count == 1);
488 check_dbt_string(&rpt->dbt[0],
489 "Mr. Watson -- come here -- I want to see you.");
490 CuAssertTrue(ct, rpt->msg_count == 0);
491
492 printf("5. send a multi-seg request\n");
493 clear_rpt(dbenv2);
494 memset(&resp, 0, sizeof(resp));
495 resp.flags = DB_DBT_MALLOC;
496 test_data_init(&rdbts[0], "I wish I were a fish");
497 test_data_init(&rdbts[1], "I wish I were a bass");
498 test_data_init(&rdbts[2],
499 "I'd climb up on a slippery rock and slide down on my ... hands and knees");
500 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 3, &resp, 0, 0)) == 0);
501 check_dbt_string(&resp, "this is the answer to the request");
502 if (resp.data)
503 free(resp.data);
504 await_done(dbenv2);
505 CuAssertTrue(ct, rpt->dbt_count == 3);
506 check_dbt_string(&rpt->dbt[0], "I wish I were a fish");
507 check_dbt_string(&rpt->dbt[1], "I wish I were a bass");
508 check_dbt_string(&rpt->dbt[2],
509 "I'd climb up on a slippery rock and slide down on my ... hands and knees");
510 CuAssertTrue(ct, rpt->msg_count == 0);
511
512 test_zeroes(ch, dbenv2, ct);
513
514 printf("7. send request with too-small USERMEM buffer\n");
515 clear_rpt(dbenv2);
516 resp.data = short_buf;
517 resp.ulen = sizeof(short_buf);
518 resp.flags = DB_DBT_USERMEM;
519 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 3, &resp, 0, 0)) == DB_BUFFER_SMALL);
520 await_done(dbenv2);
521 CuAssertTrue(ct, rpt->msg_count == 1);
522 CuAssertTrue(ct, mystrcmp(rpt->msg[0],
523 "originator's USERMEM buffer too small") == 0);
524 CuAssertTrue(ct, rpt->ret == EINVAL);
525
526 #define BUFLEN 20000
527 buffer = malloc(BUFLEN);
528 if (buffer == NULL)
529 return (2);
530 resp.data = buffer;
531 resp.ulen = BUFLEN;
532 resp.flags = DB_DBT_USERMEM;
533
534 printf("8. send USERMEM request without necessary DB_MULTIPLE\n");
535 clear_rpt(dbenv2);
536 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 2, &resp, 0, 0)) == DB_BUFFER_SMALL);
537 await_done(dbenv2);
538 CuAssertTrue(ct, rpt->msg_count == 1);
539 CuAssertTrue(ct, mystrcmp(rpt->msg[0],
540 "originator does not accept multi-segment response") == 0);
541 CuAssertTrue(ct, rpt->ret == EINVAL);
542
543 printf("9. send USERMEM request with DB_MULTIPLE\n");
544 clear_rpt(dbenv2);
545 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 2, &resp, 0, DB_MULTIPLE)) == 0);
546 DB_MULTIPLE_INIT(pointer, &resp);
547 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
548 CuAssertTrue(ct, rpt->ret == 0);
549 CuAssertTrue(ct, strcmp((char*)vp, "roses are red") == 0);
550 CuAssertTrue(ct, sz == strlen((char*)vp) + 1);
551 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
552 CuAssertTrue(ct, strcmp((char*)vp, "violets are blue") == 0);
553 CuAssertTrue(ct, sz == strlen((char*)vp) + 1);
554 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
555 CuAssertTrue(ct, pointer == NULL);
556
557 ch->close(ch, 0);
558
559
560 /* ------------------------------- */
561
562
563 CuAssertTrue(ct, (ret = dbenv2->repmgr_channel(dbenv2, DB_EID_MASTER, &ch, 0)) == 0);
564 CuAssertTrue(ct, (ret = dbenv1->repmgr_msg_dispatch(dbenv1, msg_disp2, 0)) == 0);
565
566 // do a request to master
567 // switch masters
568 // do a request to new master
569 printf("(now we try a couple of operations on a master channel)\n");
570
571 printf("10. send request to original master\n");
572 rpt = get_rpt(dbenv1);
573 clear_rpt(dbenv1);
574 resp.data = buffer;
575 resp.ulen = BUFLEN;
576 resp.flags = DB_DBT_USERMEM;
577 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 1, &resp, 0, 0)) == 0);
578 check_dbt_string(&resp, "ENV1");
579 await_done(dbenv1);
580 CuAssertTrue(ct, rpt->ret == 0);
581 CuAssertTrue(ct, rpt->dbt_count == 1);
582 check_dbt_string(&rpt->dbt[0], "I wish I were a fish");
583
584 printf("switch master and wait for our client to see the change\n");
585 ((struct env_info *)dbenv2->app_private)->startupdone = 0;
586 CuAssertTrue(ct, (ret = dbenv1->repmgr_start(dbenv1, 0, DB_REP_CLIENT)) == 0);
587 sleep(1); /* workaround for 19329 */
588 for (done = 0; ; ) {
589 /*
590 * Become master, and then make sure it really happened.
591 * Occasionally a race develops, where we're still holding on to
592 * the msg lockout at env3 at this point, in which case the
593 * rep_start() call (underlying our repmgr_start() call here) is
594 * simply dropped on the floor.
595 */
596 CuAssertTrue(ct, (ret = dbenv3->repmgr_start(dbenv3,
597 0, DB_REP_MASTER)) == 0);
598 CuAssertTrue(ct, (ret = dbenv3->rep_stat(dbenv3,
599 &stats, 0)) == 0);
600 done = stats->st_status == DB_REP_MASTER;
601 free(stats);
602 if (done)
603 break;
604 sleep(1);
605 };
606
607 /*
608 * !!!
609 * Workaround for 19297: wait until verify dance is complete at env2,
610 * because (just a little bit) later we're going to switch master again,
611 * to env2. If rep_start(MASTER) at env2 happens while processing
612 * VERIFY match record, core rep ignores the rep_start() (even though it
613 * returns 0).
614 */
615 LOCK_MUTEX(&g->mtx);
616 while (!((struct env_info *)dbenv2->app_private)->startupdone) {
617 cond_wait(&g->cond, &g->mtx);
618 }
619 // TODO: fix these macros so that this ridiculous hack isn't necessary
620 #ifndef _WIN32
621 UNLOCK_MUTEX(&g->mtx);
622 #endif
623
624
625 printf("11. send request which should go to new master (only)\n");
626 clear_rpt(dbenv1);
627 clear_rpt(dbenv3);
628 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 1, &resp, 0, 0)) == 0);
629 check_dbt_string(&resp, "ENV3");
630 rpt = get_rpt(dbenv3);
631 await_done(dbenv3);
632 CuAssertTrue(ct, rpt->ret == 0);
633 CuAssertTrue(ct, rpt->dbt_count == 1);
634 check_dbt_string(&rpt->dbt[0], "I wish I were a fish");
635 rpt = get_rpt(dbenv1);
636 CuAssertTrue(ct, !rpt->done); /* old master shouldn't have recvd anything */
637
638 printf("switch master again, to ``self''\n");
639 CuAssertTrue(ct, (ret = dbenv3->repmgr_start(dbenv3, 0, DB_REP_CLIENT)) == 0);
640 CuAssertTrue(ct, (ret = dbenv2->repmgr_start(dbenv2, 0, DB_REP_MASTER)) == 0);
641 /* No need to wait for env2 to see that env2 has become master. */
642
643 clear_rpt(dbenv1);
644 clear_rpt(dbenv2);
645 clear_rpt(dbenv3);
646 printf("12. send to self, async\n");
647 CuAssertTrue(ct, (ret = ch->send_msg(ch, &dbt, 1, 0)) == 0);
648 await_done(dbenv2);
649 rpt = get_rpt(dbenv2);
650 CuAssertTrue(ct, rpt->dbt_count == 1);
651 check_dbt_string(&rpt->dbt[0],
652 "Mr. Watson -- come here -- I want to see you.");
653 CuAssertTrue(ct, rpt->msg_count == 0);
654 printf(" (check that other two sites didn't receive it)\n");
655 sleep(1);
656 CuAssertTrue(ct, !get_rpt(dbenv1)->done);
657 CuAssertTrue(ct, !get_rpt(dbenv3)->done);
658
659 printf("13. send-to-self request\n");
660 clear_rpt(dbenv2);
661 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 2, &resp, 0, DB_MULTIPLE)) == 0);
662 DB_MULTIPLE_INIT(pointer, &resp);
663 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
664 CuAssertTrue(ct, rpt->ret == 0);
665 CuAssertTrue(ct, strcmp((char*)vp, "roses are red") == 0);
666 CuAssertTrue(ct, sz == strlen((char*)vp) + 1);
667 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
668 CuAssertTrue(ct, strcmp((char*)vp, "violets are blue") == 0);
669 CuAssertTrue(ct, sz == strlen((char*)vp) + 1);
670 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
671 CuAssertTrue(ct, pointer == NULL);
672
673 /*
674 * re-test the 0-length cases, in the send-to-self context (the
675 * implementation has a bunch of separate code)
676 */
677 test_zeroes(ch, dbenv2, ct);
678
679 ch->close(ch, 0);
680
681 /* ---------------------------------------- */
682
683 // If you go from env2 to env, we know that it's ports[0]
684 //
685 CuAssertTrue(ct, (ret = dbenv1->repmgr_msg_dispatch(dbenv1, msg_disp3, 0)) == 0);
686 CuAssertTrue(ct,
687 (ret = dbenv2->repmgr_site(dbenv2,
688 "localhost", ports[0], &dbsite, 0)) == 0);
689 CuAssertTrue(ct, (ret = dbsite->get_eid(dbsite, &eid)) == 0);
690 CuAssertTrue(ct, (ret = dbsite->close(dbsite)) == 0);
691 CuAssertTrue(ct, (ret = dbenv2->repmgr_channel(dbenv2, eid, &ch, 0)) == 0);
692
693 printf("14. send request to site that has been shut down\n");
694 td(dbenv1);
695 memset(&resp, 0, sizeof(resp));
696 resp.flags = DB_DBT_MALLOC;
697 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 2, &resp, 0, 0)) ==
698 DB_REP_UNAVAIL);
699 if (resp.data != NULL)
700 free(resp.data);
701
702 // TODO: a much more interesting case is to have the remote site shut
703 // down while waiting for the response, because that exercises some
704 // clean-up code. But I guess that requires running in a couple of
705 // threads.
706
707 ch->close(ch, 0);
708
709 printf("15. try to connect to a down site\n");
710 CuAssertTrue(ct, (ret = dbenv2->repmgr_channel(dbenv2, eid, &ch, 0)) == DB_REP_UNAVAIL);
711
712 printf("16. try to connect to a non-existent EID\n");
713 CuAssertTrue(ct, (ret = dbenv2->repmgr_channel(dbenv2, 1732, &ch, 0)) == EINVAL);
714
715 printf("17. connect master to self from the start\n");
716 CuAssertTrue(ct, (ret = dbenv2->repmgr_channel(dbenv2, DB_EID_MASTER, &ch, 0)) == 0);
717 CuAssertTrue(ct, (ret = dbenv2->repmgr_msg_dispatch(dbenv2, msg_disp2, 0)) == 0);
718 rpt = get_rpt(dbenv2);
719 clear_rpt(dbenv2);
720 resp.data = buffer;
721 resp.ulen = BUFLEN;
722 resp.flags = DB_DBT_USERMEM;
723 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 1, &resp, 0, 0)) == 0);
724 check_dbt_string(&resp, "ENV2");
725 await_done(dbenv2);
726 CuAssertTrue(ct, rpt->ret == 0);
727 CuAssertTrue(ct, rpt->dbt_count == 1);
728 check_dbt_string(&rpt->dbt[0], "I wish I were a fish");
729
730 ch->close(ch, 0);
731
732 /*
733 * Send an async message from env2 to env3, at which point env3 will
734 * reply by returning two async messages back to env2.
735 */
736 printf("18. test async replies to (async) messages\n");
737 CuAssertTrue(ct, (ret = dbenv3->repmgr_msg_dispatch(dbenv3, msg_disp3, 0)) == 0);
738 CuAssertTrue(ct, (ret = dbenv2->repmgr_msg_dispatch(dbenv2, msg_disp4, 0)) == 0);
739 CuAssertTrue(ct,
740 (ret = dbenv2->repmgr_site(dbenv2,
741 "localhost", ports[2], &dbsite, 0)) == 0);
742 CuAssertTrue(ct, (ret = dbsite->get_eid(dbsite, &eid)) == 0);
743 CuAssertTrue(ct, (ret = dbsite->close(dbsite)) == 0);
744 CuAssertTrue(ct, (ret = dbenv2->repmgr_channel(dbenv2, eid, &ch, 0)) == 0);
745 rpt = get_rpt(dbenv3);
746 clear_rpt(dbenv3);
747 ((struct env_info *)dbenv2->app_private)->rpts = &rpts;
748 memset(&rpts, 0, sizeof(rpts));
749 mutex_init(&rpts.m);
750 CuAssertTrue(ct, (ret = ch->send_msg(ch, rdbts, 1, 0)) == 0);
751 await_done(dbenv3);
752 CuAssertTrue(ct, rpt->ret == 0);
753 CuAssertTrue(ct, rpt->dbt_count == 1);
754 check_dbt_string(&rpt->dbt[0], "I wish I were a fish");
755 CuAssertTrue(ct, await_condition(two_done, dbenv2, 10));
756 CuAssertTrue(ct, rpts.rpt[0].done);
757 CuAssertTrue(ct, rpts.rpt[0].dbt_count == 1);
758 check_dbt_string(&rpts.rpt[0].dbt[0], "roses may be pink");
759
760 CuAssertTrue(ct, rpts.rpt[1].done);
761 CuAssertTrue(ct, rpts.rpt[1].dbt_count == 1);
762 check_dbt_string(&rpts.rpt[1].dbt[0], "I think");
763 clear_rpt_int(&rpts.rpt[0]);
764 clear_rpt_int(&rpts.rpt[1]);
765
766 ch->close(ch, 0);
767 sleep(1); /* wait for "EOF on connection" msg before cleaning, below */
768 // This kluge disappears when GM fixes that err msg to become an event
769
770 printf("19. test illegal calls from the msg disp function\n");
771 clear_rpt(dbenv3);
772 CuAssertTrue(ct, (ret = dbenv3->repmgr_msg_dispatch(dbenv3, msg_disp5, 0)) == 0);
773 CuAssertTrue(ct, (ret = dbenv2->repmgr_channel(dbenv2, eid, &ch, 0)) == 0);
774 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 1, &resp, 0, 0)) == 0);
775 await_done(dbenv3);
776 rpt = get_rpt(dbenv3);
777 CuAssertTrue(ct, rpt->ret == EINVAL);
778 CuAssertTrue(ct, rpt->msg_count == 3);
779 CuAssertTrue(ct, mystrcmp(rpt->msg[0],
780 "set_timeout() invalid on DB_CHANNEL supplied to msg dispatch function") == 0);
781 CuAssertTrue(ct, mystrcmp(rpt->msg[1],
782 "close() invalid on DB_CHANNEL supplied to msg dispatch function") == 0);
783 CuAssertTrue(ct, mystrcmp(rpt->msg[2],
784 "send_request() invalid on DB_CHANNEL supplied to msg dispatch function") == 0);
785 ch->close(ch, 0);
786
787 free(buffer);
788
789 td(dbenv2);
790 td(dbenv3);
791 #else
792 printf("TestChannelFeature is not supported by the build.\n");
793 #endif /* HAVE_REPLICATION */
794 return (0);
795 }
796
797 static int
two_done(ctx)798 two_done(ctx)
799 void *ctx;
800 {
801 DB_ENV *dbenv = ctx;
802 struct reports *rpts = ((struct env_info *)dbenv->app_private)->rpts;
803
804 return (rpts->count == 2 && rpts->rpt[0].done && rpts->rpt[1].done);
805 }
806
807 /* return 1 ("true") for a match, 0 ("false") otherwise */
808 static int
check_dbt_string(dbt,s)809 check_dbt_string(dbt, s)
810 DBT *dbt;
811 const char *s;
812 {
813 if (dbt->size != strlen(s))
814 return (0);
815 if (dbt->size == 0)
816 return (1);
817 return (strcmp((char*)dbt->data, s) == 0);
818 }
819
820 static int
is_started(ctx)821 is_started(ctx)
822 void *ctx;
823 {
824 DB_ENV *dbenv = ctx;
825 DB_REP_STAT *st;
826 u_int32_t ans;
827 int ret;
828
829 if ((ret = dbenv->rep_stat(dbenv, &st, 0)) != 0) {
830 dbenv->err(dbenv, ret, "rep_stat");
831 return (0);
832 }
833 ans = st->st_startup_complete;
834 free(st);
835 return (ans);
836 }
837
838 static int
await_condition(pred,ctx,limit)839 await_condition(pred, ctx, limit)
840 PRED pred;
841 void *ctx;
842 long limit;
843 {
844 #ifndef _WIN32
845 struct timeval t;
846 #endif
847 time_t tim;
848
849 tim = time(NULL) + limit;
850 while (time(NULL) < tim) {
851 if ((*pred)(ctx))
852 return (1);
853 // sleep 1/10th of a second at a time
854 // (maybe Windows can use select() too, if include Winsock2.h)
855 #ifdef _WIN32
856 Sleep(100);
857 #else
858 t.tv_sec = 0;
859 t.tv_usec = 100000;
860 select(0, NULL, NULL, NULL, &t);
861 #endif
862 }
863 return (0);
864 }
865
866
867 static void
notify(dbenv,event,unused)868 notify(dbenv, event, unused)
869 DB_ENV *dbenv;
870 u_int32_t event;
871 void *unused;
872 {
873 struct channel_test_globals *g;
874 struct env_info *info;
875
876 if (event == DB_EVENT_PANIC) {
877 fprintf(stderr, "BDB panic");
878 abort();
879 } else if (event == DB_EVENT_REP_STARTUPDONE) {
880 info = dbenv->app_private;
881 g = info->g;
882 LOCK_MUTEX(&g->mtx);
883 info->startupdone = 1;
884 cond_wake(&g->cond);
885 UNLOCK_MUTEX(&g->mtx);
886 }
887 }
888
889 static void
msg_disp(dbenv,ch,request,nseg,flags)890 msg_disp(dbenv, ch, request, nseg, flags)
891 DB_ENV *dbenv;
892 DB_CHANNEL *ch;
893 DBT *request;
894 u_int32_t nseg;
895 u_int32_t flags;
896 {
897 CuTest *ct;
898 struct report *rpt = get_rpt(dbenv);
899 DBT answer, mult[3];
900 char *p;
901 size_t sz;
902 u_int32_t i;
903 int ret;
904
905 ct = ((struct env_info *)dbenv->app_private)->g->test;
906 CuAssertTrue(ct, nseg < MAX_SEGS);
907 for (i = 0; i < nseg; i++) {
908 if ((sz = (rpt->dbt[rpt->dbt_count].size = request[i].size)) > 0) {
909 CuAssertTrue(ct, (rpt->dbt[rpt->dbt_count].data = malloc(sz)) != NULL);
910 memcpy(rpt->dbt[rpt->dbt_count].data,
911 request[i].data, sz);
912 } else
913 rpt->dbt[rpt->dbt_count].data = NULL;
914 rpt->dbt_count++;
915 }
916
917 ret = 0;
918 if (flags & DB_REPMGR_NEED_RESPONSE) {
919 if (nseg == 2) {
920 /* Try a multi-segment response. */
921 memset(&mult, 0, sizeof(mult));
922 p = "roses are red";
923 mult[0].data = p;
924 mult[0].size = (u_int32_t)strlen(p) + 1;
925 p = "violets are blue";
926 mult[1].data = p;
927 mult[1].size = (u_int32_t)strlen(p) + 1;
928 ret = ch->send_msg(ch, &mult[0], 2, 0);
929 } else if (nseg == 1) {
930 // pretend to ``forget'' to respond
931 } else if (nseg == 4) {
932 // send a response of zero segments
933 ret = ch->send_msg(ch, &answer, 0, 0);
934 } else if (nseg == 5) {
935 // send a response with a segment of zero length
936 memset(&answer, 0, sizeof(answer));
937 answer.size = 0;
938 ret = ch->send_msg(ch, &answer, 1, 0);
939
940 // TODO: we still need to try this with the DB_MULTIPLE approach too
941 } else if (nseg == 6) {
942 // patience, ...
943 /* Try a multi-segment response. */
944 memset(&mult, 0, sizeof(mult));
945 p = "roses are red";
946 mult[0].data = p;
947 mult[0].size = (u_int32_t)strlen(p) + 1;
948 p = "violets are blue";
949 mult[1].size = 0;
950 mult[2].data = p;
951 mult[2].size = (u_int32_t)strlen(p) + 1;
952 ret = ch->send_msg(ch, &mult[0], 3, 0);
953
954 } else {
955 memset(&answer, 0, sizeof(answer));
956 p = "this is the answer to the request";
957 answer.data = p;
958 answer.size = (u_int32_t)strlen(p) + 1;
959 ret = ch->send_msg(ch, &answer, 1, 0);
960 }
961 }
962 rpt->ret = ret;
963 rpt->done = 1;
964 }
965
966 static void
msg_disp2(dbenv,ch,request,nseg,flags)967 msg_disp2(dbenv, ch, request, nseg, flags)
968 DB_ENV *dbenv;
969 DB_CHANNEL *ch;
970 DBT *request;
971 u_int32_t nseg;
972 u_int32_t flags;
973 {
974 CuTest *ct;
975 struct report *rpt = get_rpt(dbenv);
976 DBT answer;
977 const char *p;
978 char buf[100];
979 size_t sz;
980 u_int32_t i;
981 int ret;
982
983 ct = ((struct env_info *)dbenv->app_private)->g->test;
984 CuAssertTrue(ct, nseg < MAX_SEGS);
985 for (i = 0; i < nseg; i++) {
986 if ((sz = (rpt->dbt[rpt->dbt_count].size = request[i].size)) > 0) {
987 CuAssertTrue(ct, (rpt->dbt[rpt->dbt_count].data = malloc(sz)) != NULL);
988 memcpy(rpt->dbt[rpt->dbt_count].data,
989 request[i].data, sz);
990 } else
991 rpt->dbt[rpt->dbt_count].data = NULL;
992 rpt->dbt_count++;
993 }
994
995 if (flags & DB_REPMGR_NEED_RESPONSE) {
996 memset(&answer, 0, sizeof(answer));
997 dbenv->get_errpfx(dbenv, &p);
998 strncpy(buf, p, sizeof(buf));
999 answer.data = buf;
1000 answer.size = (u_int32_t)strlen(p) + 1;
1001 if (answer.size > sizeof(buf))
1002 answer.size = sizeof(buf);
1003 ret = ch->send_msg(ch, &answer, 1, 0);
1004 }
1005 rpt->ret = ret;
1006 rpt->done = 1;
1007 }
1008
1009 /* Test async replies to (async) messages. */
1010 static void
msg_disp3(dbenv,ch,request,nseg,flags)1011 msg_disp3(dbenv, ch, request, nseg, flags)
1012 DB_ENV *dbenv;
1013 DB_CHANNEL *ch;
1014 DBT *request;
1015 u_int32_t nseg;
1016 u_int32_t flags;
1017 {
1018 CuTest *ct;
1019 struct report *rpt = get_rpt(dbenv);
1020 DBT answer;
1021 char *p;
1022 size_t sz;
1023 u_int32_t i;
1024 int ret;
1025
1026 ct = ((struct env_info *)dbenv->app_private)->g->test;
1027 CuAssertTrue(ct, nseg < MAX_SEGS);
1028 for (i = 0; i < nseg; i++) {
1029 if ((sz = (rpt->dbt[rpt->dbt_count].size = request[i].size)) > 0) {
1030 CuAssertTrue(ct, (rpt->dbt[rpt->dbt_count].data = malloc(sz)) != NULL);
1031 memcpy(rpt->dbt[rpt->dbt_count].data,
1032 request[i].data, sz);
1033 } else
1034 rpt->dbt[rpt->dbt_count].data = NULL;
1035 rpt->dbt_count++;
1036 }
1037
1038 ret = 0;
1039
1040 // TODO: test that multiple calls to send_msg are not allowed on a request.
1041 CuAssertTrue(ct, !(flags & DB_REPMGR_NEED_RESPONSE));
1042
1043 memset(&answer, 0, sizeof(answer));
1044 p = "roses may be pink";
1045 answer.data = p;
1046 answer.size = (u_int32_t)strlen(p) + 1;
1047 ret = ch->send_msg(ch, &answer, 1, 0);
1048
1049 if (ret == 0) {
1050 p = "I think";
1051 answer.data = p;
1052 answer.size = (u_int32_t)strlen(p) + 1;
1053 ret = ch->send_msg(ch, &answer, 1, 0);
1054 }
1055 rpt->ret = ret;
1056 rpt->done = 1;
1057 }
1058 static void
msg_disp4(dbenv,ch,request,nseg,flags)1059 msg_disp4(dbenv, ch, request, nseg, flags)
1060 DB_ENV *dbenv;
1061 DB_CHANNEL *ch;
1062 DBT *request;
1063 u_int32_t nseg;
1064 u_int32_t flags;
1065 {
1066 CuTest *ct;
1067 struct reports *rpts = ((struct env_info *)dbenv->app_private)->rpts;
1068 struct report *rpt;
1069 size_t sz;
1070 u_int32_t i;
1071
1072 ct = ((struct env_info *)dbenv->app_private)->g->test;
1073 LOCK_MUTEX(&rpts->m);
1074 rpt = &rpts->rpt[rpts->count++];
1075 UNLOCK_MUTEX(&rpts->m);
1076
1077
1078 CuAssertTrue(ct, !(flags & DB_REPMGR_NEED_RESPONSE));
1079 CuAssertTrue(ct, nseg < MAX_SEGS);
1080 for (i = 0; i < nseg; i++) {
1081 if ((sz = (rpt->dbt[rpt->dbt_count].size = request[i].size)) > 0) {
1082 CuAssertTrue(ct, (rpt->dbt[rpt->dbt_count].data = malloc(sz)) != NULL);
1083 memcpy(rpt->dbt[rpt->dbt_count].data,
1084 request[i].data, sz);
1085 } else
1086 rpt->dbt[rpt->dbt_count].data = NULL;
1087 rpt->dbt_count++;
1088 }
1089
1090 rpt->done = 1;
1091 }
1092
1093 static void
msg_disp5(dbenv,ch,request,nseg,flags)1094 msg_disp5(dbenv, ch, request, nseg, flags)
1095 DB_ENV *dbenv;
1096 DB_CHANNEL *ch;
1097 DBT *request;
1098 u_int32_t nseg;
1099 u_int32_t flags;
1100 {
1101 struct report *rpt = get_rpt(dbenv);
1102 DBT answer;
1103 u_int8_t buf[100];
1104 char *p;
1105 int ret;
1106
1107 memset(&answer, 0, sizeof(answer));
1108 answer.flags = DB_DBT_USERMEM;
1109 answer.ulen = sizeof(buf);
1110 answer.data = buf;
1111 if ((ret = ch->set_timeout(ch, 45000000)) != EINVAL ||
1112 (ret = ch->close(ch, 0)) != EINVAL)
1113 rpt->ret = ret;
1114 else
1115 rpt->ret = ch->send_request(ch, request, nseg, &answer, 0, 0);
1116
1117 memset(&answer, 0, sizeof(answer));
1118 p = "roses may be pink";
1119 answer.data = p;
1120 answer.size = (u_int32_t)strlen(p) + 1;
1121 ret = ch->send_msg(ch, &answer, 1, 0);
1122
1123 rpt->done = 1;
1124 }
1125
1126 static void
test_data_init(dbt,data)1127 test_data_init(dbt, data)
1128 DBT *dbt;
1129 char *data;
1130 {
1131 memset(dbt, 0, sizeof(*dbt));
1132 dbt->data = data;
1133 dbt->size = (u_int32_t)strlen(data) + 1;
1134 }
1135
1136 static void
test_zeroes(ch,dest,ct)1137 test_zeroes(ch, dest, ct)
1138 DB_CHANNEL *ch;
1139 DB_ENV *dest; /* destination env handle */
1140 CuTest *ct;
1141 {
1142 DBT resp;
1143 DBT rdbts[6];
1144 struct report *rpt;
1145 void *pointer, *vp;
1146 size_t sz;
1147 int i, ret;
1148
1149 memset(&resp, 0, sizeof(resp));
1150 resp.flags = DB_DBT_MALLOC;
1151
1152 #define DATA0 "Dear kindly judge, your honor"
1153 #define DATA1 "my parents treat me rough"
1154 #define DATA2 "with all their marijuana"
1155 #define DATA3 "they won't give me a puff"
1156 #define DATA4 "The didn't wanna have me, but somehow I was had"
1157 #define DATA5 "Leapin' lizards, that's why I'm so bad!"
1158
1159 #undef ADD_TEST_DATA
1160 #define ADD_TEST_DATA(x) do { test_data_init(&rdbts[i++], (x)); } while (0);
1161
1162 i = 0;
1163 ADD_TEST_DATA(DATA0);
1164 ADD_TEST_DATA(DATA1);
1165 ADD_TEST_DATA(DATA2);
1166 ADD_TEST_DATA(DATA3);
1167 ADD_TEST_DATA(DATA4);
1168 ADD_TEST_DATA(DATA5);
1169
1170 rpt = get_rpt(dest);
1171
1172 printf("6. send zero-segment request\n");
1173 clear_rpt(dest);
1174 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 0, &resp, 0, 0)) == 0);
1175 CuAssertTrue(ct, rpt->dbt_count == 0);
1176 CuAssertTrue(ct, rpt->msg_count == 0);
1177 check_dbt_string(&resp, "this is the answer to the request");
1178 if (resp.data)
1179 free(resp.data);
1180
1181 printf("6.a) send request with a zero-length segment (now why would anyone want to do that?)\n");
1182 clear_rpt(dest);
1183 rdbts[1].size = 0;
1184 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 3, &resp, 0, 0)) == 0);
1185 await_done(dest);
1186 CuAssertTrue(ct, rpt->dbt_count == 3);
1187 check_dbt_string(&rpt->dbt[0], DATA0);
1188 check_dbt_string(&rpt->dbt[1], "");
1189 check_dbt_string(&rpt->dbt[2], DATA2);
1190 CuAssertTrue(ct, rpt->msg_count == 0);
1191 check_dbt_string(&resp, "this is the answer to the request");
1192 if (resp.data)
1193 free(resp.data);
1194 i = 1; ADD_TEST_DATA(DATA1); /* restore perturbed test data */
1195
1196 printf("6.b) get a zero-length response\n");
1197 clear_rpt(dest);
1198 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 4, &resp, 0, 0)) == 0);
1199 await_done(dest);
1200 CuAssertTrue(ct, rpt->dbt_count == 4);
1201 CuAssertTrue(ct, rpt->msg_count == 0);
1202 CuAssertTrue(ct, rpt->ret == 0);
1203 CuAssertTrue(ct, resp.size == 0);
1204 if (resp.data)
1205 free(resp.data);
1206
1207 printf("6.c) get a zero-length response (alternate version)\n");
1208 clear_rpt(dest);
1209 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 5, &resp, 0, 0)) == 0);
1210 await_done(dest);
1211 CuAssertTrue(ct, rpt->dbt_count == 5);
1212 CuAssertTrue(ct, rpt->msg_count == 0);
1213 CuAssertTrue(ct, rpt->ret == 0);
1214 CuAssertTrue(ct, resp.size == 0);
1215 if (resp.data)
1216 free(resp.data);
1217
1218 printf("6.d) get a zero-length response (DB_MULTIPLE, zero segments)\n");
1219 clear_rpt(dest);
1220 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 4, &resp, 0, DB_MULTIPLE)) == 0);
1221 await_done(dest);
1222 CuAssertTrue(ct, rpt->msg_count == 0);
1223 CuAssertTrue(ct, rpt->ret == 0);
1224 DB_MULTIPLE_INIT(pointer, &resp);
1225 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
1226 CuAssertTrue(ct, pointer == NULL);
1227 if (resp.data)
1228 free(resp.data);
1229
1230 printf("6.e) get a zero-length response (DB_MULTIPLE, a zero-length segment)\n");
1231 clear_rpt(dest);
1232 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 5, &resp, 0, DB_MULTIPLE)) == 0);
1233 await_done(dest);
1234 CuAssertTrue(ct, rpt->msg_count == 0);
1235 CuAssertTrue(ct, rpt->ret == 0);
1236 DB_MULTIPLE_INIT(pointer, &resp);
1237 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
1238 CuAssertTrue(ct, sz == 0);
1239 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
1240 CuAssertTrue(ct, pointer == NULL);
1241 if (resp.data)
1242 free(resp.data);
1243
1244 printf("6.f) get a zero-length response (DB_MULTIPLE, a zero-length segment in the middle)\n");
1245 clear_rpt(dest);
1246 CuAssertTrue(ct, (ret = ch->send_request(ch, rdbts, 6, &resp, 0, DB_MULTIPLE)) == 0);
1247 await_done(dest);
1248 CuAssertTrue(ct, rpt->msg_count == 0);
1249 CuAssertTrue(ct, rpt->ret == 0);
1250 DB_MULTIPLE_INIT(pointer, &resp);
1251 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
1252 CuAssertTrue(ct, rpt->ret == 0);
1253 CuAssertTrue(ct, strcmp((char*)vp, "roses are red") == 0);
1254 CuAssertTrue(ct, sz == strlen((char*)vp) + 1);
1255 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
1256 CuAssertTrue(ct, sz == 0);
1257 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
1258 CuAssertTrue(ct, strcmp((char*)vp, "violets are blue") == 0);
1259 CuAssertTrue(ct, sz == strlen((char*)vp) + 1);
1260 DB_MULTIPLE_NEXT(pointer, &resp, vp, sz);
1261 CuAssertTrue(ct, pointer == NULL);
1262 if (resp.data)
1263 free(resp.data);
1264 }
1265
1266 /*
1267 * Compare, but skip over BDB error msg number at beginning of `actual'.
1268 */
1269 static int
mystrcmp(actual,expected)1270 mystrcmp(actual, expected)
1271 char *actual;
1272 const char *expected;
1273 {
1274 char *p;
1275
1276 for (p = actual; *p != '\0' && !isspace(*p); p++)
1277 ;
1278 for (; *p != '\0' && isspace(*p); p++)
1279 ;
1280 return (strcmp(p, expected));
1281 }
1282
get_avail_ports(ports,count)1283 static int get_avail_ports(ports, count)
1284 u_int *ports;
1285 int count;
1286 {
1287 /* This function is used only when replication is supported. */
1288 #ifdef HAVE_REPLICATION
1289 u_int base, port, upper, curport;
1290 int ret, t_ret, incr, i;
1291 char buf[20], *rbuf, *str;
1292 socket_t s;
1293 ADDRINFO *orig_ai, *ai;
1294 #ifdef _WIN32
1295 #define in_port_t u_short
1296 #ifndef EADDRINUSE
1297 #define EADDRINUSE WSAEADDRINUSE
1298 #endif
1299 WSADATA wsaData;
1300 if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
1301 printf("WSAStartup failed with error: %d\n", ret);
1302 return (ret);
1303 }
1304 #endif
1305 base = 30100;
1306 upper = 65535;
1307
1308 /*
1309 * It is very convenient to have a very simple mapping between port
1310 * numbers and sites. So usually, we search a sequence of ports
1311 * starting from (10 * N + 1). To avoid redundant check on a port,
1312 * we set the incr to be times of 10 and just bigger or equal to count.
1313 */
1314 incr = 10 * ((count + 9) / 10);
1315
1316 /*
1317 * The format for BDBPORTRANGE should be base:upper,
1318 * either of base or upper can be empty, and if empty,
1319 * we will use the default value for it.
1320 * If no colon, the whole is considered to be base.
1321 */
1322 rbuf = buf;
1323 if ((ret = __os_getenv(NULL, "BDBPORTRANGE", &rbuf, sizeof(buf))) != 0)
1324 goto end;
1325 if (rbuf != NULL && rbuf[0] != '\0') {
1326 if ((str = strsep(&rbuf, ":")) != NULL && str[0] != '\0')
1327 base = (u_int)atoi(str);
1328 if (rbuf != NULL && rbuf[0] != '\0')
1329 upper = (u_int)atoi(rbuf);
1330 }
1331
1332 for (port = base + 1; (port + incr) <= upper; port += incr) {
1333 curport = port;
1334 i = incr;
1335
1336 while (i-- > 0) {
1337 if (ret = __repmgr_getaddr(NULL, "localhost", curport,
1338 AI_PASSIVE, &orig_ai) != 0)
1339 goto end;
1340
1341 for (ai = orig_ai; ai != NULL; ai = ai->ai_next) {
1342 if ((s = socket(ai->ai_family, ai->ai_socktype,
1343 ai->ai_protocol)) == INVALID_SOCKET)
1344 continue;
1345
1346 if (bind(s, ai->ai_addr,
1347 (socklen_t)ai->ai_addrlen) != 0) {
1348 ret = net_errno;
1349 (void)closesocket(s);
1350 s = INVALID_SOCKET;
1351 continue;
1352 }
1353
1354 ret = 0;
1355 goto clean;
1356 }
1357 if (ret == 0)
1358 ret = net_errno;
1359 clean:
1360 if (s != INVALID_SOCKET)
1361 (void)closesocket(s);
1362 __os_freeaddrinfo(NULL, orig_ai);
1363 if (ret != 0 && ret != EADDRINUSE)
1364 goto end;
1365 else if (ret != 0)
1366 break;
1367 curport++;
1368 }
1369
1370 /* We've found the port sequence now */
1371 if (ret == 0) {
1372 for (i = 0; i < count; i++)
1373 ports[i] = port + i;
1374 break;
1375 }
1376 }
1377 end:
1378 #ifdef _WIN32
1379 if (WSACleanup() == SOCKET_ERROR) {
1380 t_ret = net_errno;
1381 printf("WSACleanup failed with error: %d\n", t_ret);
1382 if (ret == 0)
1383 ret = t_ret;
1384 }
1385 #endif
1386
1387 return (ret);
1388 #else
1389 return (0);
1390 #endif /* HAVE_REPLICATION */
1391 }
1392
1393