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
!= 0)) {
135 fprintf(stderr
, "Got %u/%u msgs, expected 1/0\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
{
253 struct messaging_context
*msg_ctx
;
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 server_id dst
)
262 struct tevent_req
*req
, *subreq
;
263 struct msg_pingpong_state
*state
;
266 req
= tevent_req_create(mem_ctx
, &state
, struct msg_pingpong_state
);
271 if (!tevent_req_set_endtime(req
, ev
, timeval_current_ofs(10, 0))) {
272 return tevent_req_post(req
, ev
);
275 state
->msg_ctx
= messaging_init(state
, ev
);
276 if (tevent_req_nomem(state
->msg_ctx
, req
)) {
277 return tevent_req_post(req
, ev
);
280 status
= messaging_send_buf(state
->msg_ctx
, dst
, MSG_PING
, NULL
, 0);
281 if (!NT_STATUS_IS_OK(status
)) {
282 DBG_DEBUG("messaging_send_buf failed: %s\n", nt_errstr(status
));
283 tevent_req_error(req
, map_errno_from_nt_status(status
));
284 return tevent_req_post(req
, ev
);
287 subreq
= messaging_read_send(state
, ev
, state
->msg_ctx
, MSG_PONG
);
288 if (tevent_req_nomem(subreq
, req
)) {
289 return tevent_req_post(req
, ev
);
291 tevent_req_set_callback(subreq
, msg_pingpong_done
, req
);
295 static void msg_pingpong_done(struct tevent_req
*subreq
)
297 struct tevent_req
*req
= tevent_req_callback_data(
298 subreq
, struct tevent_req
);
301 ret
= messaging_read_recv(subreq
, NULL
, NULL
);
304 tevent_req_error(req
, ret
);
307 tevent_req_done(req
);
310 static int msg_pingpong_recv(struct tevent_req
*req
)
314 if (tevent_req_is_unix_error(req
, &err
)) {
320 static int msg_pingpong(struct server_id dst
)
322 struct tevent_context
*ev
;
323 struct tevent_req
*req
;
326 ev
= tevent_context_init(talloc_tos());
330 req
= msg_pingpong_send(ev
, ev
, dst
);
334 if (!tevent_req_poll(req
, ev
)) {
338 ret
= msg_pingpong_recv(req
);
344 static void ping_responder_exit(struct tevent_context
*ev
,
345 struct tevent_fd
*fde
,
349 bool *done
= private_data
;
351 printf("Child: received write on exit-pipe\n");
356 static void ping_responder(int ready_pipe
, int exit_pipe
)
358 struct tevent_context
*ev
;
359 struct messaging_context
*msg_ctx
;
360 struct tevent_fd
*exit_handler
;
364 ev
= samba_tevent_context_init(talloc_tos());
366 fprintf(stderr
, "child tevent_context_init failed\n");
369 msg_ctx
= messaging_init(ev
, ev
);
370 if (msg_ctx
== NULL
) {
371 fprintf(stderr
, "child messaging_init failed\n");
374 exit_handler
= tevent_add_fd(ev
, ev
, exit_pipe
, TEVENT_FD_READ
,
375 ping_responder_exit
, &done
);
376 if (exit_handler
== NULL
) {
377 fprintf(stderr
, "child tevent_add_fd failed\n");
381 if (write(ready_pipe
, &c
, 1) != 1) {
382 fprintf(stderr
, "child messaging_init failed\n");
388 ret
= tevent_loop_once(ev
);
390 fprintf(stderr
, "child tevent_loop_once failed\n");
395 printf("Child: done, exiting...\n");
397 TALLOC_FREE(msg_ctx
);
401 bool run_messaging_read3(int dummy
)
403 struct tevent_context
*ev
= NULL
;
404 struct messaging_context
*msg_ctx
= NULL
;
411 struct server_id dst
;
414 if ((pipe(ready_pipe
) != 0) || (pipe(exit_pipe
) != 0)) {
415 perror("pipe failed");
421 perror("fork failed");
426 close(ready_pipe
[0]);
428 ping_responder(ready_pipe
[1], exit_pipe
[0]);
431 close(ready_pipe
[1]);
434 if (read(ready_pipe
[0], &c
, 1) != 1) {
435 perror("read failed");
439 ev
= samba_tevent_context_init(talloc_tos());
441 fprintf(stderr
, "tevent_context_init failed\n");
445 dst
= (struct server_id
){ .pid
= child
, .vnn
= NONCLUSTER_VNN
, };
447 for (i
=0; i
<100; i
++) {
448 ret
= msg_pingpong(dst
);
450 fprintf(stderr
, "msg_pingpong failed\n");
455 printf("Parent: telling child to exit\n");
457 written
= write(exit_pipe
[1], &c
, 1);
459 perror("write to exit_pipe failed");
463 ret
= waitpid(child
, NULL
, 0);
465 perror("waitpid failed");
469 printf("Parent: child exited. Done\n");
473 TALLOC_FREE(msg_ctx
);
481 * test transferring a big payload.
484 #define MSG_TORTURE_READ4 0xF104
486 static bool read4_child(int ready_fd
)
488 struct tevent_context
*ev
= NULL
;
489 struct messaging_context
*msg_ctx
= NULL
;
490 TALLOC_CTX
*frame
= talloc_stackframe();
493 struct tevent_req
*subreq
;
496 struct messaging_rec
*rec
;
499 ev
= samba_tevent_context_init(frame
);
501 fprintf(stderr
, "child: tevent_context_init failed\n");
505 msg_ctx
= messaging_init(ev
, ev
);
506 if (msg_ctx
== NULL
) {
507 fprintf(stderr
, "child: messaging_init failed\n");
511 printf("child: telling parent we're ready to receive messages\n");
513 /* Tell the parent we are ready to receive messages. */
514 bytes
= write(ready_fd
, &c
, 1);
516 perror("child: failed to write to ready_fd");
520 printf("child: waiting for messages\n");
522 subreq
= messaging_read_send(frame
, /* TALLOC_CTX */
525 if (subreq
== NULL
) {
526 fprintf(stderr
, "child: messaging_read_send failed\n");
530 ok
= tevent_req_poll(subreq
, ev
);
532 fprintf(stderr
, "child: tevent_req_poll failed\n");
536 printf("child: receiving message\n");
538 ret
= messaging_read_recv(subreq
, frame
, &rec
);
541 fprintf(stderr
, "child: messaging_read_recv failed\n");
545 printf("child: received message\n");
547 /* Tell the parent we are done. */
548 bytes
= write(ready_fd
, &c
, 1);
550 perror("child: failed to write to ready_fd");
554 printf("child: done\n");
563 struct child_done_state
{
568 static void child_done_cb(struct tevent_context
*ev
,
569 struct tevent_fd
*fde
,
573 struct child_done_state
*state
=
574 (struct child_done_state
*)private_data
;
578 bytes
= read(state
->fd
, &c
, 1);
580 perror("parent: read from ready_fd failed");
586 static bool read4_parent(pid_t child_pid
, int ready_fd
)
588 struct tevent_context
*ev
= NULL
;
589 struct messaging_context
*msg_ctx
= NULL
;
593 struct server_id dst
;
594 TALLOC_CTX
*frame
= talloc_stackframe();
599 struct tevent_fd
*child_done_fde
;
600 struct child_done_state child_state
;
602 /* wait until the child is ready to receive messages */
603 bytes
= read(ready_fd
, &c
, 1);
605 perror("parent: read from ready_fd failed");
609 printf("parent: child is ready to receive messages\n");
611 ev
= samba_tevent_context_init(frame
);
613 fprintf(stderr
, "parent: tevent_context_init failed\n");
617 msg_ctx
= messaging_init(ev
, ev
);
618 if (msg_ctx
== NULL
) {
619 fprintf(stderr
, "parent: messaging_init failed\n");
623 child_state
.fd
= ready_fd
;
624 child_state
.done
= false;
626 child_done_fde
= tevent_add_fd(ev
, ev
, ready_fd
, TEVENT_FD_READ
,
627 child_done_cb
, &child_state
);
628 if (child_done_fde
== NULL
) {
630 "parent: failed tevent_add_fd for child done\n");
635 * Send a 1M payload with the message.
637 blob
= data_blob_talloc_zero(frame
, 1000*1000);
638 iov
.iov_base
= blob
.data
;
639 iov
.iov_len
= blob
.length
;
641 dst
= messaging_server_id(msg_ctx
);
644 printf("parent: sending message to child\n");
646 status
= messaging_send_iov(msg_ctx
, dst
, MSG_TORTURE_READ4
, &iov
, 1,
648 if (!NT_STATUS_IS_OK(status
)) {
649 fprintf(stderr
, "parent: messaging_send_iov failed: %s\n",
654 printf("parent: waiting for child to confirm\n");
656 while (!child_state
.done
) {
657 ret
= tevent_loop_once(ev
);
659 fprintf(stderr
, "parent: tevent_loop_once failed\n");
664 printf("parent: child confirmed\n");
666 ret
= waitpid(child_pid
, NULL
, 0);
668 perror("parent: waitpid failed");
672 printf("parent: done\n");
681 bool run_messaging_read4(int dummy
)
688 ret
= pipe(ready_pipe
);
690 perror("parent: pipe failed for ready_pipe");
695 if (child_pid
== -1) {
696 perror("fork failed");
697 } else if (child_pid
== 0) {
698 close(ready_pipe
[0]);
699 retval
= read4_child(ready_pipe
[1]);
701 close(ready_pipe
[1]);
702 retval
= read4_parent(child_pid
, ready_pipe
[0]);