messaging: add an overflow check
[Samba.git] / source4 / lib / messaging / tests / messaging.c
blob783850ae326269a828a44020d956df1ec38a3fc6
1 /*
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/>.
22 #include "includes.h"
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"
31 #include "lib/crypto/md5.h"
33 static uint32_t msg_pong;
35 static void ping_message(struct imessaging_context *msg, void *private_data,
36 uint32_t msg_type, struct server_id src, DATA_BLOB *data)
38 NTSTATUS status;
39 status = imessaging_send(msg, src, msg_pong, data);
40 if (!NT_STATUS_IS_OK(status)) {
41 printf("pong failed - %s\n", nt_errstr(status));
45 static void pong_message(struct imessaging_context *msg, void *private_data,
46 uint32_t msg_type, struct server_id src, DATA_BLOB *data)
48 int *count = (int *)private_data;
49 (*count)++;
52 static void exit_message(struct imessaging_context *msg, void *private_data,
53 uint32_t msg_type, struct server_id src, DATA_BLOB *data)
55 talloc_free(private_data);
56 exit(0);
60 test ping speed
62 static bool test_ping_speed(struct torture_context *tctx)
64 struct tevent_context *ev;
65 struct imessaging_context *msg_client_ctx;
66 struct imessaging_context *msg_server_ctx;
67 int ping_count = 0;
68 int pong_count = 0;
69 struct timeval tv;
70 int timelimit = torture_setting_int(tctx, "timelimit", 10);
71 uint32_t msg_ping, msg_exit;
73 lpcfg_set_cmdline(tctx->lp_ctx, "pid directory", "piddir.tmp");
75 ev = tctx->ev;
77 msg_server_ctx = imessaging_init(tctx,
78 tctx->lp_ctx, cluster_id(0, 1),
79 ev);
81 torture_assert(tctx, msg_server_ctx != NULL, "Failed to init ping messaging context");
83 imessaging_register_tmp(msg_server_ctx, NULL, ping_message, &msg_ping);
84 imessaging_register_tmp(msg_server_ctx, tctx, exit_message, &msg_exit);
86 msg_client_ctx = imessaging_init(tctx,
87 tctx->lp_ctx,
88 cluster_id(0, 2),
89 ev);
91 torture_assert(tctx, msg_client_ctx != NULL,
92 "msg_client_ctx imessaging_init() failed");
94 imessaging_register_tmp(msg_client_ctx, &pong_count, pong_message, &msg_pong);
96 tv = timeval_current();
98 torture_comment(tctx, "Sending pings for %d seconds\n", timelimit);
99 while (timeval_elapsed(&tv) < timelimit) {
100 DATA_BLOB data;
101 NTSTATUS status1, status2;
103 data.data = discard_const_p(uint8_t, "testing");
104 data.length = strlen((const char *)data.data);
106 status1 = imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_ping, &data);
107 status2 = imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_ping, NULL);
109 torture_assert_ntstatus_ok(tctx, status1, "msg1 failed");
110 ping_count++;
112 torture_assert_ntstatus_ok(tctx, status2, "msg2 failed");
113 ping_count++;
115 while (ping_count > pong_count + 20) {
116 tevent_loop_once(ev);
120 torture_comment(tctx, "waiting for %d remaining replies (done %d)\n",
121 ping_count - pong_count, pong_count);
122 while (timeval_elapsed(&tv) < 30 && pong_count < ping_count) {
123 tevent_loop_once(ev);
126 torture_comment(tctx, "sending exit\n");
127 imessaging_send(msg_client_ctx, cluster_id(0, 1), msg_exit, NULL);
129 torture_assert_int_equal(tctx, ping_count, pong_count, "ping test failed");
131 torture_comment(tctx, "ping rate of %.0f messages/sec\n",
132 (ping_count+pong_count)/timeval_elapsed(&tv));
134 talloc_free(msg_client_ctx);
135 talloc_free(msg_server_ctx);
137 return true;
140 static bool test_messaging_overflow(struct torture_context *tctx)
142 struct imessaging_context *msg_ctx;
143 ssize_t nwritten, nread;
144 pid_t child;
145 char c = 0;
146 int up_pipe[2], down_pipe[2];
147 int i, ret, child_status;
149 ret = pipe(up_pipe);
150 torture_assert(tctx, ret == 0, "pipe failed");
151 ret = pipe(down_pipe);
152 torture_assert(tctx, ret == 0, "pipe failed");
154 child = fork();
155 if (child < 0) {
156 torture_fail(tctx, "fork failed");
159 if (child == 0) {
160 ret = tevent_re_initialise(tctx->ev);
161 torture_assert(tctx, ret == 0, "tevent_re_initialise failed");
163 msg_ctx = imessaging_init(tctx, tctx->lp_ctx,
164 cluster_id(getpid(), 0),
165 tctx->ev);
166 torture_assert(tctx, msg_ctx != NULL,
167 "imessaging_init failed");
169 do {
170 nwritten = write(up_pipe[1], &c, 1);
171 } while ((nwritten == -1) && (errno == EINTR));
173 ret = close(down_pipe[1]);
175 do {
176 nread = read(down_pipe[0], &c, 1);
177 } while ((nread == -1) && (errno == EINTR));
179 exit(0);
182 do {
183 nread = read(up_pipe[0], &c, 1);
184 } while ((nread == -1) && (errno == EINTR));
186 msg_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(getpid(), 0),
187 tctx->ev);
188 torture_assert(tctx, msg_ctx != NULL, "imessaging_init failed");
190 for (i=0; i<1000; i++) {
191 NTSTATUS status;
192 status = imessaging_send(msg_ctx, cluster_id(child, 0),
193 MSG_PING, NULL);
194 torture_assert_ntstatus_ok(tctx, status,
195 "imessaging_send failed");
198 tevent_loop_once(tctx->ev);
200 talloc_free(msg_ctx);
202 ret = close(down_pipe[1]);
203 torture_assert(tctx, ret == 0, "close failed");
205 ret = waitpid(child, &child_status, 0);
206 torture_assert(tctx, ret == child, "wrong child exited");
207 torture_assert(tctx, child_status == 0, "child failed");
209 poll(NULL, 0, 500);
211 return true;
214 struct overflow_parent_child {
215 MD5_CTX md5ctx;
216 bool done;
219 static void overflow_md5_child_handler(struct imessaging_context *msg,
220 void *private_data,
221 uint32_t msg_type,
222 struct server_id server_id,
223 DATA_BLOB *data)
225 struct overflow_parent_child *state = private_data;
227 if (data->length == 0) {
228 state->done = true;
229 return;
232 MD5Update(&state->md5ctx, data->data, data->length);
235 struct overflow_child_parent {
236 uint8_t final[16];
237 bool done;
240 static void overflow_md5_parent_handler(struct imessaging_context *msg_ctx,
241 void *private_data,
242 uint32_t msg_type,
243 struct server_id server_id,
244 DATA_BLOB *data)
246 struct overflow_child_parent *state = private_data;
248 if (data->length != sizeof(state->final)) {
249 memset(state->final, 0, sizeof(state->final));
250 state->done = true;
251 return;
253 memcpy(state->final, data->data, 16);
254 state->done = true;
257 static bool test_messaging_overflow_check(struct torture_context *tctx)
259 struct imessaging_context *msg_ctx;
260 ssize_t nwritten, nread;
261 pid_t child;
262 char c = 0;
263 int up_pipe[2], down_pipe[2];
264 int i, ret, child_status;
265 MD5_CTX md5ctx;
266 uint8_t final[16];
267 struct overflow_child_parent child_msg = { .done = false };
268 NTSTATUS status;
270 ret = pipe(up_pipe);
271 torture_assert(tctx, ret == 0, "pipe failed");
272 ret = pipe(down_pipe);
273 torture_assert(tctx, ret == 0, "pipe failed");
275 child = fork();
276 if (child < 0) {
277 torture_fail(tctx, "fork failed");
280 if (child == 0) {
281 struct overflow_parent_child child_state = { .done = false };
282 DATA_BLOB retblob = { .data = final, .length = sizeof(final) };
284 ret = tevent_re_initialise(tctx->ev);
285 torture_assert(tctx, ret == 0, "tevent_re_initialise failed");
287 MD5Init(&child_state.md5ctx);
289 msg_ctx = imessaging_init(tctx, tctx->lp_ctx,
290 cluster_id(getpid(), 0),
291 tctx->ev);
292 torture_assert(tctx, msg_ctx != NULL,
293 "imessaging_init failed");
295 status = imessaging_register(msg_ctx, &child_state,
296 MSG_TMP_BASE-1,
297 overflow_md5_child_handler);
298 torture_assert(tctx, NT_STATUS_IS_OK(status),
299 "imessaging_register failed");
301 do {
302 nwritten = write(up_pipe[1], &c, 1);
303 } while ((nwritten == -1) && (errno == EINTR));
305 ret = close(down_pipe[1]);
306 torture_assert(tctx, ret == 0, "close failed");
308 do {
309 nread = read(down_pipe[0], &c, 1);
310 } while ((nread == -1) && (errno == EINTR));
312 while (!child_state.done) {
313 tevent_loop_once(tctx->ev);
316 MD5Final(final, &child_state.md5ctx);
318 status = imessaging_send(msg_ctx,
319 cluster_id(getppid(), 0),
320 MSG_TMP_BASE-2,
321 &retblob);
322 torture_assert(tctx, NT_STATUS_IS_OK(status),
323 "imessaging_send failed");
325 exit(0);
328 do {
329 nread = read(up_pipe[0], &c, 1);
330 } while ((nread == -1) && (errno == EINTR));
332 msg_ctx = imessaging_init(tctx, tctx->lp_ctx, cluster_id(getpid(), 0),
333 tctx->ev);
334 torture_assert(tctx, msg_ctx != NULL, "imessaging_init failed");
336 status = imessaging_register(msg_ctx,
337 &child_msg,
338 MSG_TMP_BASE-2,
339 overflow_md5_parent_handler);
340 torture_assert(tctx,
341 NT_STATUS_IS_OK(status),
342 "imessaging_register failed");
344 MD5Init(&md5ctx);
346 for (i=0; i<1000; i++) {
347 size_t len = ((random() % 100) + 1);
348 uint8_t buf[len];
349 DATA_BLOB blob = { .data = buf, .length = len };
351 generate_random_buffer(buf, len);
353 MD5Update(&md5ctx, buf, len);
355 status = imessaging_send(msg_ctx, cluster_id(child, 0),
356 MSG_TMP_BASE-1, &blob);
357 torture_assert_ntstatus_ok(tctx, status,
358 "imessaging_send failed");
361 status = imessaging_send(msg_ctx, cluster_id(child, 0),
362 MSG_TMP_BASE-1, NULL);
363 torture_assert_ntstatus_ok(tctx, status,
364 "imessaging_send failed");
366 MD5Final(final, &md5ctx);
368 do {
369 nwritten = write(down_pipe[1], &c, 1);
370 } while ((nwritten == -1) && (errno == EINTR));
372 while (!child_msg.done) {
373 tevent_loop_once(tctx->ev);
376 ret = close(down_pipe[1]);
377 torture_assert(tctx, ret == 0, "close failed");
379 talloc_free(msg_ctx);
381 ret = waitpid(child, &child_status, 0);
382 torture_assert(tctx, ret == child, "wrong child exited");
383 torture_assert(tctx, child_status == 0, "child failed");
385 if (memcmp(final, child_msg.final, 16) != 0) {
386 dump_data_file(final, 16, false, stderr);
387 dump_data_file(child_msg.final, 16, false, stderr);
388 fflush(stderr);
389 torture_fail(tctx, "checksum comparison failed");
392 return true;
395 struct torture_suite *torture_local_messaging(TALLOC_CTX *mem_ctx)
397 struct torture_suite *s = torture_suite_create(mem_ctx, "messaging");
398 torture_suite_add_simple_test(s, "overflow", test_messaging_overflow);
399 torture_suite_add_simple_test(s, "overflow_check",
400 test_messaging_overflow_check);
401 torture_suite_add_simple_test(s, "ping_speed", test_ping_speed);
402 return s;