2 * Unix SMB/CIFS implementation.
3 * Test for a messaging_send_all bug
4 * Copyright (C) Volker Lendecke 2017
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"
24 #include "lib/async_req/async_sock.h"
25 #include "lib/util/sys_rw.h"
27 static pid_t
fork_responder(struct messaging_context
*msg_ctx
,
30 struct tevent_context
*ev
= messaging_tevent_context(msg_ctx
);
31 struct tevent_req
*req
;
40 ret
= pipe(ready_pipe
);
42 perror("pipe failed");
47 if (child_pid
== -1) {
48 perror("fork failed");
57 nread
= read(ready_pipe
[0], &c
, 1);
60 perror("read failed");
69 status
= messaging_reinit(msg_ctx
);
70 if (!NT_STATUS_IS_OK(status
)) {
71 fprintf(stderr
, "messaging_reinit failed: %s\n",
77 nwritten
= sys_write(ready_pipe
[1], &c
, 1);
79 fprintf(stderr
, "write failed: %s\n", strerror(errno
));
85 req
= wait_for_read_send(ev
, ev
, exit_pipe
[0], false);
87 fprintf(stderr
, "wait_for_read_send failed\n");
91 ok
= tevent_req_poll_unix(req
, ev
, &err
);
93 fprintf(stderr
, "tevent_req_poll_unix failed: %s\n",
101 struct messaging_send_all_state
{
102 struct tevent_context
*ev
;
103 struct messaging_context
*msg
;
108 static void collect_pong_received(struct tevent_req
*subreq
);
110 static struct tevent_req
*collect_pong_send(TALLOC_CTX
*mem_ctx
,
111 struct tevent_context
*ev
,
112 struct messaging_context
*msg
,
113 const pid_t
*senders
,
116 struct tevent_req
*req
, *subreq
;
117 struct messaging_send_all_state
*state
;
119 req
= tevent_req_create(mem_ctx
, &state
,
120 struct messaging_send_all_state
);
124 state
->senders
= talloc_memdup(
125 state
, senders
, num_senders
* sizeof(pid_t
));
126 if (tevent_req_nomem(state
->senders
, req
)) {
127 return tevent_req_post(req
, ev
);
132 subreq
= messaging_read_send(state
, state
->ev
, state
->msg
, MSG_PONG
);
133 if (tevent_req_nomem(subreq
, req
)) {
134 return tevent_req_post(req
, ev
);
136 tevent_req_set_callback(subreq
, collect_pong_received
, req
);
140 static void collect_pong_received(struct tevent_req
*subreq
)
142 struct tevent_req
*req
= tevent_req_callback_data(
143 subreq
, struct tevent_req
);
144 struct messaging_send_all_state
*state
= tevent_req_data(
145 req
, struct messaging_send_all_state
);
146 size_t num_senders
= talloc_array_length(state
->senders
);
148 struct messaging_rec
*rec
;
151 ret
= messaging_read_recv(subreq
, state
, &rec
);
153 if (tevent_req_error(req
, ret
)) {
158 * We need to make sure we don't receive our own broadcast!
161 if (rec
->src
.pid
== (uint64_t)getpid()) {
162 fprintf(stderr
, "Received my own broadcast!\n");
163 tevent_req_error(req
, EMULTIHOP
);
167 for (i
=0; i
<num_senders
; i
++) {
168 if (state
->senders
[i
] == (pid_t
)rec
->src
.pid
) {
169 printf("got message from %"PRIu64
"\n", rec
->src
.pid
);
170 state
->senders
[i
] = 0;
171 state
->num_received
+= 1;
176 if (state
->num_received
== num_senders
) {
178 tevent_req_done(req
);
182 subreq
= messaging_read_send(state
, state
->ev
, state
->msg
, MSG_PONG
);
183 if (tevent_req_nomem(subreq
, req
)) {
186 tevent_req_set_callback(subreq
, collect_pong_received
, req
);
189 static int collect_pong_recv(struct tevent_req
*req
)
191 return tevent_req_simple_recv_unix(req
);
194 extern int torture_nprocs
;
196 bool run_messaging_send_all(int dummy
)
198 struct tevent_context
*ev
= NULL
;
199 struct messaging_context
*msg_ctx
= NULL
;
201 pid_t children
[MAX(5, torture_nprocs
)];
202 struct tevent_req
*req
;
207 ev
= samba_tevent_context_init(talloc_tos());
209 fprintf(stderr
, "tevent_context_init failed\n");
212 msg_ctx
= messaging_init(ev
, ev
);
213 if (msg_ctx
== NULL
) {
214 fprintf(stderr
, "messaging_init failed\n");
217 ret
= pipe(exit_pipe
);
219 perror("parent: pipe failed for exit_pipe");
223 for (i
=0; i
<ARRAY_SIZE(children
); i
++) {
224 children
[i
] = fork_responder(msg_ctx
, exit_pipe
);
225 if (children
[i
] == -1) {
226 fprintf(stderr
, "fork_responder(%zu) failed\n", i
);
231 req
= collect_pong_send(ev
, ev
, msg_ctx
, children
,
232 ARRAY_SIZE(children
));
234 perror("collect_pong failed");
238 ok
= tevent_req_set_endtime(req
, ev
,
239 tevent_timeval_current_ofs(10, 0));
241 perror("tevent_req_set_endtime failed");
245 messaging_send_all(msg_ctx
, MSG_PING
, NULL
, 0);
247 ok
= tevent_req_poll_unix(req
, ev
, &err
);
249 perror("tevent_req_poll_unix failed");
253 ret
= collect_pong_recv(req
);
257 fprintf(stderr
, "collect_pong_send returned %s\n",
264 for (i
=0; i
<ARRAY_SIZE(children
); i
++) {
269 child
= waitpid(children
[i
], &status
, 0);
270 } while ((child
== -1) && (errno
== EINTR
));
272 if (child
!= children
[i
]) {
273 printf("waitpid(%d) failed\n", children
[i
]);