2 Unix SMB/CIFS implementation.
4 local test for messaging code
6 Copyright (C) Andrew Tridgell 2004
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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "lib/events/events.h"
24 #include "lib/messaging/irpc.h"
25 #include "torture/torture.h"
26 #include "cluster/cluster.h"
27 #include "param/param.h"
28 #include "torture/local/proto.h"
29 #include "system/select.h"
30 #include "system/filesys.h"
32 #include <gnutls/gnutls.h>
33 #include <gnutls/crypto.h>
35 static uint32_t msg_pong;
37 static void ping_message(struct imessaging_context *msg,
48 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
52 status = imessaging_send(msg, src, msg_pong, data);
53 if (!NT_STATUS_IS_OK(status)) {
54 printf("pong failed - %s\n", nt_errstr(status));
58 static void pong_message(struct imessaging_context *msg,
66 int *count = (int *)private_data;
69 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
76 static void exit_message(struct imessaging_context *msg,
85 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
89 talloc_free(private_data);
96 static bool test_ping_speed(struct torture_context *tctx)
98 struct tevent_context *ev;
99 struct imessaging_context *msg_client_ctx;
100 struct imessaging_context *msg_server_ctx;
104 int timelimit = torture_setting_int(tctx, "timelimit", 10);
105 uint32_t msg_ping, msg_exit;
107 lpcfg_set_cmdline(tctx->lp_ctx, "pid directory", "piddir.tmp");
111 msg_server_ctx = imessaging_init(tctx,
112 tctx->lp_ctx, cluster_id(0, 1),
115 torture_assert(tctx, msg_server_ctx != NULL, "Failed to init ping messaging context");
117 imessaging_register_tmp(msg_server_ctx, NULL, ping_message, &msg_ping);
118 imessaging_register_tmp(msg_server_ctx, tctx, exit_message, &msg_exit);
120 msg_client_ctx = imessaging_init(tctx,
125 torture_assert(tctx, msg_client_ctx != NULL,
126 "msg_client_ctx imessaging_init() failed");
128 imessaging_register_tmp(msg_client_ctx, &pong_count, pong_message, &msg_pong);
130 tv = timeval_current();
132 torture_comment(tctx, "Sending pings for %d seconds\n", timelimit);
133 while (timeval_elapsed(&tv) < timelimit) {
135 NTSTATUS status1, status2;
137 data.data = discard_const_p(uint8_t, "testing");
138 data.length = strlen((const char *)data.data);
140 status1 = imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_ping, &data);
141 status2 = imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_ping, NULL);
143 torture_assert_ntstatus_ok(tctx, status1, "msg1 failed");
146 torture_assert_ntstatus_ok(tctx, status2, "msg2 failed");
149 while (ping_count > pong_count + 20) {
150 tevent_loop_once(ev);
154 torture_comment(tctx, "waiting for %d remaining replies (done %d)\n",
155 ping_count - pong_count, pong_count);
156 while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) {
157 tevent_loop_once(ev);
160 torture_comment(tctx, "sending exit\n");
161 imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_exit, NULL);
163 torture_assert_int_equal(tctx, ping_count, pong_count, "ping test failed");
165 torture_comment(tctx, "ping rate of %.0f messages/sec\n",
166 (ping_count+pong_count)/timeval_elapsed(&tv));
168 talloc_free(msg_client_ctx);
169 talloc_free(msg_server_ctx);
174 static bool test_messaging_overflow(struct torture_context *tctx)
176 struct imessaging_context *msg_ctx;
177 ssize_t nwritten, nread;
180 int up_pipe[2], down_pipe[2];
181 int i, ret, child_status;
184 torture_assert(tctx, ret == 0, "pipe failed");
185 ret = pipe(down_pipe);
186 torture_assert(tctx, ret == 0, "pipe failed");
190 torture_fail(tctx, "fork failed");
194 ret = tevent_re_initialise(tctx->ev);
195 torture_assert(tctx, ret == 0, "tevent_re_initialise failed");
197 msg_ctx = imessaging_init(tctx, tctx->lp_ctx,
198 cluster_id(getpid(), 0),
200 torture_assert(tctx, msg_ctx != NULL,
201 "imessaging_init failed");
204 nwritten = write(up_pipe[1], &c, 1);
205 } while ((nwritten == -1) && (errno == EINTR));
207 ret = close(down_pipe[1]);
208 torture_assert(tctx, ret == 0, "close failed");
211 nread = read(down_pipe[0], &c, 1);
212 } while ((nread == -1) && (errno == EINTR));
218 nread = read(up_pipe[0], &c, 1);
219 } while ((nread == -1) && (errno == EINTR));
221 msg_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(getpid(), 0),
223 torture_assert(tctx, msg_ctx != NULL, "imessaging_init failed");
225 for (i=0; i<1000; i++) {
227 status = imessaging_send(msg_ctx, cluster_id(child, 0),
229 torture_assert_ntstatus_ok(tctx, status,
230 "imessaging_send failed");
233 tevent_loop_once(tctx->ev);
235 talloc_free(msg_ctx);
237 ret = close(down_pipe[1]);
238 torture_assert(tctx, ret == 0, "close failed");
240 ret = waitpid(child, &child_status, 0);
241 torture_assert(tctx, ret == child, "wrong child exited");
242 torture_assert(tctx, child_status == 0, "child failed");
249 struct overflow_parent_child {
250 gnutls_hash_hd_t md5_hash_hnd;
254 static void overflow_md5_child_handler(struct imessaging_context *msg,
257 struct server_id server_id,
262 struct overflow_parent_child *state = private_data;
265 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
269 if (data->length == 0) {
274 gnutls_hash(state->md5_hash_hnd, data->data, data->length);
277 struct overflow_child_parent {
282 static void overflow_md5_parent_handler(struct imessaging_context *msg_ctx,
285 struct server_id server_id,
290 struct overflow_child_parent *state = private_data;
293 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
297 if (data->length != sizeof(state->final)) {
298 memset(state->final, 0, sizeof(state->final));
302 memcpy(state->final, data->data, 16);
306 static bool test_messaging_overflow_check(struct torture_context *tctx)
308 struct imessaging_context *msg_ctx;
309 ssize_t nwritten, nread;
312 int up_pipe[2], down_pipe[2];
313 int i, ret, child_status;
314 gnutls_hash_hd_t hash_hnd;
316 struct overflow_child_parent child_msg = { .done = false };
320 torture_assert(tctx, ret == 0, "pipe failed");
321 ret = pipe(down_pipe);
322 torture_assert(tctx, ret == 0, "pipe failed");
326 torture_fail(tctx, "fork failed");
330 struct overflow_parent_child child_state = { .done = false };
331 DATA_BLOB retblob = { .data = final, .length = sizeof(final) };
333 ret = tevent_re_initialise(tctx->ev);
334 torture_assert(tctx, ret == 0, "tevent_re_initialise failed");
336 gnutls_hash_init(&child_state.md5_hash_hnd, GNUTLS_DIG_MD5);
338 msg_ctx = imessaging_init(tctx, tctx->lp_ctx,
339 cluster_id(getpid(), 0),
341 torture_assert(tctx, msg_ctx != NULL,
342 "imessaging_init failed");
344 status = imessaging_register(msg_ctx, &child_state,
346 overflow_md5_child_handler);
347 torture_assert(tctx, NT_STATUS_IS_OK(status),
348 "imessaging_register failed");
351 nwritten = write(up_pipe[1], &c, 1);
352 } while ((nwritten == -1) && (errno == EINTR));
354 ret = close(down_pipe[1]);
355 torture_assert(tctx, ret == 0, "close failed");
358 nread = read(down_pipe[0], &c, 1);
359 } while ((nread == -1) && (errno == EINTR));
361 while (!child_state.done) {
362 tevent_loop_once(tctx->ev);
365 gnutls_hash_deinit(child_state.md5_hash_hnd, final);
367 status = imessaging_send(msg_ctx,
368 cluster_id(getppid(), 0),
371 torture_assert(tctx, NT_STATUS_IS_OK(status),
372 "imessaging_send failed");
378 nread = read(up_pipe[0], &c, 1);
379 } while ((nread == -1) && (errno == EINTR));
381 msg_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(getpid(), 0),
383 torture_assert(tctx, msg_ctx != NULL, "imessaging_init failed");
385 status = imessaging_register(msg_ctx,
388 overflow_md5_parent_handler);
390 NT_STATUS_IS_OK(status),
391 "imessaging_register failed");
393 gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
395 for (i=0; i<1000; i++) {
396 size_t len = ((random() % 100) + 1);
398 DATA_BLOB blob = { .data = buf, .length = len };
400 generate_random_buffer(buf, len);
402 gnutls_hash(hash_hnd, buf, len);
404 status = imessaging_send(msg_ctx, cluster_id(child, 0),
405 MSG_TMP_BASE-1, &blob);
406 torture_assert_ntstatus_ok(tctx, status,
407 "imessaging_send failed");
410 status = imessaging_send(msg_ctx, cluster_id(child, 0),
411 MSG_TMP_BASE-1, NULL);
412 torture_assert_ntstatus_ok(tctx, status,
413 "imessaging_send failed");
415 gnutls_hash_deinit(hash_hnd, final);
418 nwritten = write(down_pipe[1], &c, 1);
419 } while ((nwritten == -1) && (errno == EINTR));
421 while (!child_msg.done) {
422 tevent_loop_once(tctx->ev);
425 ret = close(down_pipe[1]);
426 torture_assert(tctx, ret == 0, "close failed");
428 talloc_free(msg_ctx);
430 ret = waitpid(child, &child_status, 0);
431 torture_assert(tctx, ret == child, "wrong child exited");
432 torture_assert(tctx, child_status == 0, "child failed");
434 if (memcmp(final, child_msg.final, 16) != 0) {
435 dump_data_file(final, 16, false, stderr);
436 dump_data_file(child_msg.final, 16, false, stderr);
438 torture_fail(tctx, "checksum comparison failed");
444 struct test_multi_ctx {
445 struct torture_context *tctx;
446 struct imessaging_context *server_ctx;
447 struct imessaging_context *client_ctx[4];
455 static void multi_ctx_server_handler(struct imessaging_context *msg,
458 struct server_id server_id,
463 struct test_multi_ctx *state = private_data;
467 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
471 torture_assert_goto(state->tctx, state->num_missing >= 1,
473 "num_missing should be at least 1.");
474 state->num_missing -= 1;
476 torture_assert_goto(state->tctx, !state->got_server,
478 "already got server.");
479 state->got_server = true;
482 * We free the context itself and most likely reuse
483 * the memory immediately.
485 TALLOC_FREE(state->server_ctx);
486 str = generate_random_str(state->tctx, 128);
487 torture_assert_goto(state->tctx, str != NULL,
489 "generate_random_str()");
495 static void multi_ctx_client_0_1_handler(struct imessaging_context *msg,
498 struct server_id server_id,
503 struct test_multi_ctx *state = private_data;
507 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
511 torture_assert_goto(state->tctx, state->num_missing >= 2,
513 "num_missing should be at least 2.");
514 state->num_missing -= 2;
516 torture_assert_goto(state->tctx, !state->got_client_0_1,
518 "already got client_0_1.");
519 state->got_client_0_1 = true;
522 * We free two contexts and most likely reuse
523 * the memory immediately.
525 TALLOC_FREE(state->client_ctx[0]);
526 str = generate_random_str(state->tctx, 128);
527 torture_assert_goto(state->tctx, str != NULL,
529 "generate_random_str()");
530 TALLOC_FREE(state->client_ctx[1]);
531 str = generate_random_str(state->tctx, 128);
532 torture_assert_goto(state->tctx, str != NULL,
534 "generate_random_str()");
540 static void multi_ctx_client_2_3_handler(struct imessaging_context *msg,
543 struct server_id server_id,
548 struct test_multi_ctx *state = private_data;
552 DBG_WARNING("Received %zu fds, ignoring message\n", num_fds);
556 torture_assert_goto(state->tctx, state->num_missing >= 2,
558 "num_missing should be at least 2.");
559 state->num_missing -= 2;
561 torture_assert_goto(state->tctx, !state->got_client_2_3,
563 "already got client_2_3.");
564 state->got_client_2_3 = true;
567 * We free two contexts and most likely reuse
568 * the memory immediately.
570 TALLOC_FREE(state->client_ctx[2]);
571 str = generate_random_str(state->tctx, 128);
572 torture_assert_goto(state->tctx, str != NULL,
574 "generate_random_str()");
575 TALLOC_FREE(state->client_ctx[3]);
576 str = generate_random_str(state->tctx, 128);
577 torture_assert_goto(state->tctx, str != NULL,
579 "generate_random_str()");
585 static bool test_multi_ctx(struct torture_context *tctx)
587 struct test_multi_ctx state = {
594 lpcfg_set_cmdline(tctx->lp_ctx, "pid directory", "piddir.tmp");
597 * We use cluster_id(0, 0) as that gets for
600 state.server_ctx = imessaging_init(tctx,
604 torture_assert(tctx, state.server_ctx != NULL,
605 "Failed to init messaging context");
607 status = imessaging_register(state.server_ctx, &state,
609 multi_ctx_server_handler);
610 torture_assert(tctx, NT_STATUS_IS_OK(status), "imessaging_register failed");
612 state.client_ctx[0] = imessaging_init(tctx,
616 torture_assert(tctx, state.client_ctx[0] != NULL,
617 "msg_client_ctx imessaging_init() failed");
618 status = imessaging_register(state.client_ctx[0], &state,
620 multi_ctx_client_0_1_handler);
621 torture_assert(tctx, NT_STATUS_IS_OK(status), "imessaging_register failed");
622 state.client_ctx[1] = imessaging_init(tctx,
626 torture_assert(tctx, state.client_ctx[1] != NULL,
627 "msg_client_ctx imessaging_init() failed");
628 status = imessaging_register(state.client_ctx[1], &state,
630 multi_ctx_client_0_1_handler);
631 torture_assert(tctx, NT_STATUS_IS_OK(status), "imessaging_register failed");
632 state.client_ctx[2] = imessaging_init(tctx,
636 torture_assert(tctx, state.client_ctx[2] != NULL,
637 "msg_client_ctx imessaging_init() failed");
638 status = imessaging_register(state.client_ctx[2], &state,
640 multi_ctx_client_2_3_handler);
641 torture_assert(tctx, NT_STATUS_IS_OK(status), "imessaging_register failed");
642 state.client_ctx[3] = imessaging_init(tctx,
646 torture_assert(tctx, state.client_ctx[3] != NULL,
647 "msg_client_ctx imessaging_init() failed");
648 status = imessaging_register(state.client_ctx[3], &state,
650 multi_ctx_client_2_3_handler);
651 torture_assert(tctx, NT_STATUS_IS_OK(status), "imessaging_register failed");
654 * Send one message that need to arrive on 3 ( 5 - 2 ) handlers.
656 state.num_missing = 5;
658 status = imessaging_send(state.server_ctx,
660 MSG_TMP_BASE-1, NULL);
661 torture_assert_ntstatus_ok(tctx, status, "msg failed");
663 tv = timeval_current();
664 while (timeval_elapsed(&tv) < 30 && state.num_missing > 0 && state.ok) {
667 ret = tevent_loop_once(tctx->ev);
668 torture_assert_int_equal(tctx, ret, 0, "tevent_loop_once()");
675 torture_assert_int_equal(tctx, state.num_missing, 0,
676 "wrong message count");
678 torture_assert(tctx, state.got_client_0_1, "got_client_0_1");
679 torture_assert(tctx, state.got_client_2_3, "got_client_2_3");
680 torture_assert(tctx, state.got_server, "got_server");
685 struct torture_suite *torture_local_messaging(TALLOC_CTX *mem_ctx)
687 struct torture_suite *s = torture_suite_create(mem_ctx, "messaging");
688 torture_suite_add_simple_test(s, "overflow", test_messaging_overflow);
689 torture_suite_add_simple_test(s, "overflow_check",
690 test_messaging_overflow_check);
691 torture_suite_add_simple_test(s, "ping_speed", test_ping_speed);
692 torture_suite_add_simple_test(s, "multi_ctx", test_multi_ctx);