2 Unix SMB/CIFS implementation.
3 Test for a messaging_read bug
4 Copyright (C) Volker Lendecke 2014
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "torture/proto.h"
22 #include "lib/util/tevent_unix.h"
25 struct msg_count_state {
26 struct tevent_context *ev;
27 struct messaging_context *msg_ctx;
32 static void msg_count_done(struct tevent_req *subreq);
34 static struct tevent_req *msg_count_send(TALLOC_CTX *mem_ctx,
35 struct tevent_context *ev,
36 struct messaging_context *msg_ctx,
40 struct tevent_req *req, *subreq;
41 struct msg_count_state *state;
43 req = tevent_req_create(mem_ctx, &state, struct msg_count_state);
48 state->msg_ctx = msg_ctx;
49 state->msg_type = msg_type;
52 subreq = messaging_read_send(state, state->ev, state->msg_ctx,
54 if (tevent_req_nomem(subreq, req)) {
55 return tevent_req_post(req, ev);
57 tevent_req_set_callback(subreq, msg_count_done, req);
61 static void msg_count_done(struct tevent_req *subreq)
63 struct tevent_req *req = tevent_req_callback_data(
64 subreq, struct tevent_req);
65 struct msg_count_state *state = tevent_req_data(
66 req, struct msg_count_state);
69 ret = messaging_read_recv(subreq, NULL, NULL);
71 if (tevent_req_error(req, ret)) {
76 subreq = messaging_read_send(state, state->ev, state->msg_ctx,
78 if (tevent_req_nomem(subreq, req)) {
81 tevent_req_set_callback(subreq, msg_count_done, req);
84 bool run_messaging_read1(int dummy)
86 struct tevent_context *ev = NULL;
87 struct messaging_context *msg_ctx = NULL;
88 struct tevent_req *req1 = NULL;
90 struct tevent_req *req2 = NULL;
96 ev = samba_tevent_context_init(talloc_tos());
98 fprintf(stderr, "tevent_context_init failed\n");
101 msg_ctx = messaging_init(ev, ev);
102 if (msg_ctx == NULL) {
103 fprintf(stderr, "messaging_init failed\n");
107 req1 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count1);
109 fprintf(stderr, "msg_count_send failed\n");
112 req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count2);
114 fprintf(stderr, "msg_count_send failed\n");
117 status = messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
118 MSG_SMB_NOTIFY, NULL, 0);
119 if (!NT_STATUS_IS_OK(status)) {
120 fprintf(stderr, "messaging_send_buf failed: %s\n",
125 for (i=0; i<2; i++) {
126 if (tevent_loop_once(ev) != 0) {
127 fprintf(stderr, "tevent_loop_once failed\n");
132 printf("%u/%u\n", count1, count2);
134 if ((count1 != 1) || (count2 != 1)){
135 fprintf(stderr, "Got %u/%u msgs, expected 1 each\n",
144 TALLOC_FREE(msg_ctx);
149 struct msg_free_state {
150 struct tevent_req **to_free;
153 static void msg_free_done(struct tevent_req *subreq);
155 static struct tevent_req *msg_free_send(TALLOC_CTX *mem_ctx,
156 struct tevent_context *ev,
157 struct messaging_context *msg_ctx,
159 struct tevent_req **to_free)
161 struct tevent_req *req, *subreq;
162 struct msg_free_state *state;
164 req = tevent_req_create(mem_ctx, &state, struct msg_free_state);
168 state->to_free = to_free;
170 subreq = messaging_read_send(state, ev, msg_ctx, msg_type);
171 if (tevent_req_nomem(subreq, req)) {
172 return tevent_req_post(req, ev);
174 tevent_req_set_callback(subreq, msg_free_done, req);
178 static void msg_free_done(struct tevent_req *subreq)
180 struct tevent_req *req = tevent_req_callback_data(
181 subreq, struct tevent_req);
182 struct msg_free_state *state = tevent_req_data(
183 req, struct msg_free_state);
186 ret = messaging_read_recv(subreq, NULL, NULL);
188 if (tevent_req_error(req, ret)) {
191 TALLOC_FREE(*state->to_free);
192 tevent_req_done(req);
195 bool run_messaging_read2(int dummy)
197 struct tevent_context *ev = NULL;
198 struct messaging_context *msg_ctx = NULL;
199 struct tevent_req *req1 = NULL;
200 struct tevent_req *req2 = NULL;
205 ev = samba_tevent_context_init(talloc_tos());
207 fprintf(stderr, "tevent_context_init failed\n");
210 msg_ctx = messaging_init(ev, ev);
211 if (msg_ctx == NULL) {
212 fprintf(stderr, "messaging_init failed\n");
216 req1 = msg_free_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &req2);
218 fprintf(stderr, "msg_count_send failed\n");
221 req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count);
223 fprintf(stderr, "msg_count_send failed\n");
226 status = messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
227 MSG_SMB_NOTIFY, NULL, 0);
228 if (!NT_STATUS_IS_OK(status)) {
229 fprintf(stderr, "messaging_send_buf failed: %s\n",
234 if (!tevent_req_poll(req1, ev) != 0) {
235 fprintf(stderr, "tevent_req_poll failed\n");
240 fprintf(stderr, "Got %u msgs, expected none\n", count);
247 TALLOC_FREE(msg_ctx);
252 struct msg_pingpong_state {
256 static void msg_pingpong_done(struct tevent_req *subreq);
258 static struct tevent_req *msg_pingpong_send(TALLOC_CTX *mem_ctx,
259 struct tevent_context *ev,
260 struct messaging_context *msg_ctx,
261 struct server_id dst)
263 struct tevent_req *req, *subreq;
264 struct msg_pingpong_state *state;
267 req = tevent_req_create(mem_ctx, &state, struct msg_pingpong_state);
272 status = messaging_send_buf(msg_ctx, dst, MSG_PING, NULL, 0);
273 if (!NT_STATUS_IS_OK(status)) {
274 tevent_req_error(req, map_errno_from_nt_status(status));
275 return tevent_req_post(req, ev);
278 subreq = messaging_read_send(state, ev, msg_ctx, MSG_PONG);
279 if (tevent_req_nomem(subreq, req)) {
280 return tevent_req_post(req, ev);
282 tevent_req_set_callback(subreq, msg_pingpong_done, req);
286 static void msg_pingpong_done(struct tevent_req *subreq)
288 struct tevent_req *req = tevent_req_callback_data(
289 subreq, struct tevent_req);
292 ret = messaging_read_recv(subreq, NULL, NULL);
295 tevent_req_error(req, ret);
298 tevent_req_done(req);
301 static int msg_pingpong_recv(struct tevent_req *req)
305 if (tevent_req_is_unix_error(req, &err)) {
311 static int msg_pingpong(struct messaging_context *msg_ctx,
312 struct server_id dst)
314 struct tevent_context *ev;
315 struct tevent_req *req;
318 ev = tevent_context_init(msg_ctx);
322 req = msg_pingpong_send(ev, ev, msg_ctx, dst);
326 if (!tevent_req_poll(req, ev)) {
330 ret = msg_pingpong_recv(req);
336 static void ping_responder_exit(struct tevent_context *ev,
337 struct tevent_fd *fde,
341 bool *done = private_data;
343 printf("Child: received write on exit-pipe\n");
348 static void ping_responder(int ready_pipe, int exit_pipe)
350 struct tevent_context *ev;
351 struct messaging_context *msg_ctx;
352 struct tevent_fd *exit_handler;
356 ev = samba_tevent_context_init(talloc_tos());
358 fprintf(stderr, "child tevent_context_init failed\n");
361 msg_ctx = messaging_init(ev, ev);
362 if (msg_ctx == NULL) {
363 fprintf(stderr, "child messaging_init failed\n");
366 exit_handler = tevent_add_fd(ev, ev, exit_pipe, TEVENT_FD_READ,
367 ping_responder_exit, &done);
368 if (exit_handler == NULL) {
369 fprintf(stderr, "child tevent_add_fd failed\n");
373 if (write(ready_pipe, &c, 1) != 1) {
374 fprintf(stderr, "child messaging_init failed\n");
380 ret = tevent_loop_once(ev);
382 fprintf(stderr, "child tevent_loop_once failed\n");
387 printf("Child: done, exiting...\n");
389 TALLOC_FREE(msg_ctx);
393 bool run_messaging_read3(int dummy)
395 struct tevent_context *ev = NULL;
396 struct messaging_context *msg_ctx = NULL;
403 struct server_id dst;
406 if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
407 perror("pipe failed");
413 perror("fork failed");
418 close(ready_pipe[0]);
420 ping_responder(ready_pipe[1], exit_pipe[0]);
423 close(ready_pipe[1]);
426 if (read(ready_pipe[0], &c, 1) != 1) {
427 perror("read failed");
431 ev = samba_tevent_context_init(talloc_tos());
433 fprintf(stderr, "tevent_context_init failed\n");
436 msg_ctx = messaging_init(ev, ev);
437 if (msg_ctx == NULL) {
438 fprintf(stderr, "messaging_init failed\n");
442 dst = messaging_server_id(msg_ctx);
445 ret = msg_pingpong(msg_ctx, dst);
447 fprintf(stderr, "msg_pingpong failed\n");
451 printf("Parent: telling child to exit\n");
453 written = write(exit_pipe[1], &c, 1);
455 perror("write to exit_pipe failed");
459 ret = waitpid(child, NULL, 0);
461 perror("waitpid failed");
465 printf("Parent: child exited. Done\n");
469 TALLOC_FREE(msg_ctx);
477 * test transferring a big payload.
480 #define MSG_TORTURE_READ4 0xF104
482 static bool read4_child(int ready_fd)
484 struct tevent_context *ev = NULL;
485 struct messaging_context *msg_ctx = NULL;
486 TALLOC_CTX *frame = talloc_stackframe();
489 struct tevent_req *subreq;
492 struct messaging_rec *rec;
495 ev = samba_tevent_context_init(frame);
497 fprintf(stderr, "child: tevent_context_init failed\n");
501 msg_ctx = messaging_init(ev, ev);
502 if (msg_ctx == NULL) {
503 fprintf(stderr, "child: messaging_init failed\n");
507 printf("child: telling parent we're ready to receive messages\n");
509 /* Tell the parent we are ready to receive mesages. */
510 bytes = write(ready_fd, &c, 1);
512 perror("child: failed to write to ready_fd");
516 printf("child: waiting for messages\n");
518 subreq = messaging_read_send(frame, /* TALLOC_CTX */
521 if (subreq == NULL) {
522 fprintf(stderr, "child: messaging_read_send failed\n");
526 ok = tevent_req_poll(subreq, ev);
528 fprintf(stderr, "child: tevent_req_poll failed\n");
532 printf("child: receiving message\n");
534 ret = messaging_read_recv(subreq, frame, &rec);
537 fprintf(stderr, "child: messaging_read_recv failed\n");
541 printf("child: received message\n");
543 /* Tell the parent we are done. */
544 bytes = write(ready_fd, &c, 1);
546 perror("child: failed to write to ready_fd");
550 printf("child: done\n");
559 struct child_done_state {
564 static void child_done_cb(struct tevent_context *ev,
565 struct tevent_fd *fde,
569 struct child_done_state *state =
570 (struct child_done_state *)private_data;
574 bytes = read(state->fd, &c, 1);
576 perror("parent: read from ready_fd failed");
582 static bool read4_parent(pid_t child_pid, int ready_fd)
584 struct tevent_context *ev = NULL;
585 struct messaging_context *msg_ctx = NULL;
589 struct server_id dst;
590 TALLOC_CTX *frame = talloc_stackframe();
595 struct tevent_fd *child_done_fde;
596 struct child_done_state child_state;
598 /* wait until the child is ready to receive messages */
599 bytes = read(ready_fd, &c, 1);
601 perror("parent: read from ready_fd failed");
605 printf("parent: child is ready to receive messages\n");
607 ev = samba_tevent_context_init(frame);
609 fprintf(stderr, "parent: tevent_context_init failed\n");
613 msg_ctx = messaging_init(ev, ev);
614 if (msg_ctx == NULL) {
615 fprintf(stderr, "parent: messaging_init failed\n");
619 child_state.fd = ready_fd;
620 child_state.done = false;
622 child_done_fde = tevent_add_fd(ev, ev, ready_fd, TEVENT_FD_READ,
623 child_done_cb, &child_state);
624 if (child_done_fde == NULL) {
626 "parent: failed tevent_add_fd for child done\n");
631 * Send a 1M payload with the message.
633 blob = data_blob_talloc_zero(frame, 1000*1000);
634 iov.iov_base = blob.data;
635 iov.iov_len = blob.length;
637 dst = messaging_server_id(msg_ctx);
640 printf("parent: sending message to child\n");
642 status = messaging_send_iov(msg_ctx, dst, MSG_TORTURE_READ4, &iov, 1,
644 if (!NT_STATUS_IS_OK(status)) {
645 fprintf(stderr, "parent: messaging_send_iov failed: %s\n",
650 printf("parent: waiting for child to confirm\n");
652 while (!child_state.done) {
653 ret = tevent_loop_once(ev);
655 fprintf(stderr, "parent: tevent_loop_once failed\n");
660 printf("parent: child confirmed\n");
662 ret = waitpid(child_pid, NULL, 0);
664 perror("parent: waitpid failed");
668 printf("parent: done\n");
677 bool run_messaging_read4(int dummy)
684 ret = pipe(ready_pipe);
686 perror("parent: pipe failed for ready_pipe");
691 if (child_pid == -1) {
692 perror("fork failed");
693 } else if (child_pid == 0) {
694 close(ready_pipe[0]);
695 retval = read4_child(ready_pipe[1]);
697 close(ready_pipe[1]);
698 retval = read4_parent(child_pid, ready_pipe[0]);