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