s3:torture: in LOCAL-MESSAGING-READ3, print some messages to child
[kai/samba-autobuild/.git] / source3 / torture / test_messaging_read.c
1 /*
2    Unix SMB/CIFS implementation.
3    Test for a messaging_read bug
4    Copyright (C) Volker Lendecke 2014
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "torture/proto.h"
22 #include "lib/util/tevent_unix.h"
23 #include "messages.h"
24
25 struct msg_count_state {
26         struct tevent_context *ev;
27         struct messaging_context *msg_ctx;
28         uint32_t msg_type;
29         unsigned *count;
30 };
31
32 static void msg_count_done(struct tevent_req *subreq);
33
34 static struct tevent_req *msg_count_send(TALLOC_CTX *mem_ctx,
35                                          struct tevent_context *ev,
36                                          struct messaging_context *msg_ctx,
37                                          uint32_t msg_type,
38                                          unsigned *count)
39 {
40         struct tevent_req *req, *subreq;
41         struct msg_count_state *state;
42
43         req = tevent_req_create(mem_ctx, &state, struct msg_count_state);
44         if (req == NULL) {
45                 return NULL;
46         }
47         state->ev = ev;
48         state->msg_ctx = msg_ctx;
49         state->msg_type = msg_type;
50         state->count = count;
51
52         subreq = messaging_read_send(state, state->ev, state->msg_ctx,
53                                      state->msg_type);
54         if (tevent_req_nomem(subreq, req)) {
55                 return tevent_req_post(req, ev);
56         }
57         tevent_req_set_callback(subreq, msg_count_done, req);
58         return req;
59 }
60
61 static void msg_count_done(struct tevent_req *subreq)
62 {
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);
67         int ret;
68
69         ret = messaging_read_recv(subreq, NULL, NULL);
70         TALLOC_FREE(subreq);
71         if (tevent_req_error(req, ret)) {
72                 return;
73         }
74         *state->count += 1;
75
76         subreq = messaging_read_send(state, state->ev, state->msg_ctx,
77                                      state->msg_type);
78         if (tevent_req_nomem(subreq, req)) {
79                 return;
80         }
81         tevent_req_set_callback(subreq, msg_count_done, req);
82 }
83
84 bool run_messaging_read1(int dummy)
85 {
86         struct tevent_context *ev = NULL;
87         struct messaging_context *msg_ctx = NULL;
88         struct tevent_req *req1 = NULL;
89         unsigned count1 = 0;
90         struct tevent_req *req2 = NULL;
91         unsigned count2 = 0;
92         NTSTATUS status;
93         bool retval = false;
94         int i;
95
96         ev = samba_tevent_context_init(talloc_tos());
97         if (ev == NULL) {
98                 fprintf(stderr, "tevent_context_init failed\n");
99                 goto fail;
100         }
101         msg_ctx = messaging_init(ev, ev);
102         if (msg_ctx == NULL) {
103                 fprintf(stderr, "messaging_init failed\n");
104                 goto fail;
105         }
106
107         req1 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count1);
108         if (req1 == NULL) {
109                 fprintf(stderr, "msg_count_send failed\n");
110                 goto fail;
111         }
112         req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count2);
113         if (req1 == NULL) {
114                 fprintf(stderr, "msg_count_send failed\n");
115                 goto fail;
116         }
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",
121                         nt_errstr(status));
122                 goto fail;
123         }
124
125         for (i=0; i<2; i++) {
126                 if (tevent_loop_once(ev) != 0) {
127                         fprintf(stderr, "tevent_loop_once failed\n");
128                         goto fail;
129                 }
130         }
131
132         printf("%u/%u\n", count1, count2);
133
134         if ((count1 != 1) || (count2 != 1)){
135                 fprintf(stderr, "Got %u/%u msgs, expected 1 each\n",
136                         count1, count2);
137                 goto fail;
138         }
139
140         retval = true;
141 fail:
142         TALLOC_FREE(req1);
143         TALLOC_FREE(req2);
144         TALLOC_FREE(msg_ctx);
145         TALLOC_FREE(ev);
146         return retval;
147 }
148
149 struct msg_free_state {
150         struct tevent_req **to_free;
151 };
152
153 static void msg_free_done(struct tevent_req *subreq);
154
155 static struct tevent_req *msg_free_send(TALLOC_CTX *mem_ctx,
156                                         struct tevent_context *ev,
157                                         struct messaging_context *msg_ctx,
158                                         uint32_t msg_type,
159                                         struct tevent_req **to_free)
160 {
161         struct tevent_req *req, *subreq;
162         struct msg_free_state *state;
163
164         req = tevent_req_create(mem_ctx, &state, struct msg_free_state);
165         if (req == NULL) {
166                 return NULL;
167         }
168         state->to_free = to_free;
169
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);
173         }
174         tevent_req_set_callback(subreq, msg_free_done, req);
175         return req;
176 }
177
178 static void msg_free_done(struct tevent_req *subreq)
179 {
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);
184         int ret;
185
186         ret = messaging_read_recv(subreq, NULL, NULL);
187         TALLOC_FREE(subreq);
188         if (tevent_req_error(req, ret)) {
189                 return;
190         }
191         TALLOC_FREE(*state->to_free);
192         tevent_req_done(req);
193 }
194
195 bool run_messaging_read2(int dummy)
196 {
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;
201         unsigned count = 0;
202         NTSTATUS status;
203         bool retval = false;
204
205         ev = samba_tevent_context_init(talloc_tos());
206         if (ev == NULL) {
207                 fprintf(stderr, "tevent_context_init failed\n");
208                 goto fail;
209         }
210         msg_ctx = messaging_init(ev, ev);
211         if (msg_ctx == NULL) {
212                 fprintf(stderr, "messaging_init failed\n");
213                 goto fail;
214         }
215
216         req1 = msg_free_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &req2);
217         if (req1 == NULL) {
218                 fprintf(stderr, "msg_count_send failed\n");
219                 goto fail;
220         }
221         req2 = msg_count_send(ev, ev, msg_ctx, MSG_SMB_NOTIFY, &count);
222         if (req1 == NULL) {
223                 fprintf(stderr, "msg_count_send failed\n");
224                 goto fail;
225         }
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",
230                         nt_errstr(status));
231                 goto fail;
232         }
233
234         if (!tevent_req_poll(req1, ev) != 0) {
235                 fprintf(stderr, "tevent_req_poll failed\n");
236                 goto fail;
237         }
238
239         if (count != 0) {
240                 fprintf(stderr, "Got %u msgs, expected none\n", count);
241                 goto fail;
242         }
243
244         retval = true;
245 fail:
246         TALLOC_FREE(req1);
247         TALLOC_FREE(msg_ctx);
248         TALLOC_FREE(ev);
249         return retval;
250 }
251
252 struct msg_pingpong_state {
253         uint8_t dummy;
254 };
255
256 static void msg_pingpong_done(struct tevent_req *subreq);
257
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)
262 {
263         struct tevent_req *req, *subreq;
264         struct msg_pingpong_state *state;
265         NTSTATUS status;
266
267         req = tevent_req_create(mem_ctx, &state, struct msg_pingpong_state);
268         if (req == NULL) {
269                 return NULL;
270         }
271
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);
276         }
277
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);
281         }
282         tevent_req_set_callback(subreq, msg_pingpong_done, req);
283         return req;
284 }
285
286 static void msg_pingpong_done(struct tevent_req *subreq)
287 {
288         struct tevent_req *req = tevent_req_callback_data(
289                 subreq, struct tevent_req);
290         int ret;
291
292         ret = messaging_read_recv(subreq, NULL, NULL);
293         TALLOC_FREE(subreq);
294         if (ret != 0) {
295                 tevent_req_error(req, ret);
296                 return;
297         }
298         tevent_req_done(req);
299 }
300
301 static int msg_pingpong_recv(struct tevent_req *req)
302 {
303         int err;
304
305         if (tevent_req_is_unix_error(req, &err)) {
306                 return err;
307         }
308         return 0;
309 }
310
311 static int msg_pingpong(struct messaging_context *msg_ctx,
312                         struct server_id dst)
313 {
314         struct tevent_context *ev;
315         struct tevent_req *req;
316         int ret = ENOMEM;
317
318         ev = tevent_context_init(msg_ctx);
319         if (ev == NULL) {
320                 goto fail;
321         }
322         req = msg_pingpong_send(ev, ev, msg_ctx, dst);
323         if (req == NULL) {
324                 goto fail;
325         }
326         if (!tevent_req_poll(req, ev)) {
327                 ret = errno;
328                 goto fail;
329         }
330         ret = msg_pingpong_recv(req);
331 fail:
332         TALLOC_FREE(ev);
333         return ret;
334 }
335
336 static void ping_responder_exit(struct tevent_context *ev,
337                                 struct tevent_fd *fde,
338                                 uint16_t flags,
339                                 void *private_data)
340 {
341         bool *done = private_data;
342
343         printf("Child: received write on exit-pipe\n");
344
345         *done = true;
346 }
347
348 static void ping_responder(int ready_pipe, int exit_pipe)
349 {
350         struct tevent_context *ev;
351         struct messaging_context *msg_ctx;
352         struct tevent_fd *exit_handler;
353         char c = 0;
354         bool done = false;
355
356         ev = samba_tevent_context_init(talloc_tos());
357         if (ev == NULL) {
358                 fprintf(stderr, "child tevent_context_init failed\n");
359                 exit(1);
360         }
361         msg_ctx = messaging_init(ev, ev);
362         if (msg_ctx == NULL) {
363                 fprintf(stderr, "child messaging_init failed\n");
364                 exit(1);
365         }
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");
370                 exit(1);
371         }
372
373         if (write(ready_pipe, &c, 1) != 1) {
374                 fprintf(stderr, "child messaging_init failed\n");
375                 exit(1);
376         }
377
378         while (!done) {
379                 int ret;
380                 ret = tevent_loop_once(ev);
381                 if (ret != 0) {
382                         fprintf(stderr, "child tevent_loop_once failed\n");
383                         exit(1);
384                 }
385         }
386
387         printf("Child: done, exiting...\n");
388
389         TALLOC_FREE(msg_ctx);
390         TALLOC_FREE(ev);
391 }
392
393 bool run_messaging_read3(int dummy)
394 {
395         struct tevent_context *ev = NULL;
396         struct messaging_context *msg_ctx = NULL;
397         bool retval = false;
398         pid_t child;
399         int ready_pipe[2];
400         int exit_pipe[2];
401         int ret;
402         char c;
403         struct server_id dst;
404         ssize_t written;
405
406         if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
407                 perror("pipe failed");
408                 return false;
409         }
410
411         child = fork();
412         if (child == -1) {
413                 perror("fork failed");
414                 return false;
415         }
416
417         if (child == 0) {
418                 close(ready_pipe[0]);
419                 close(exit_pipe[1]);
420                 ping_responder(ready_pipe[1], exit_pipe[0]);
421                 exit(0);
422         }
423         close(ready_pipe[1]);
424         close(exit_pipe[0]);
425
426         if (read(ready_pipe[0], &c, 1) != 1) {
427                 perror("read failed");
428                 return false;
429         }
430
431         ev = samba_tevent_context_init(talloc_tos());
432         if (ev == NULL) {
433                 fprintf(stderr, "tevent_context_init failed\n");
434                 goto fail;
435         }
436         msg_ctx = messaging_init(ev, ev);
437         if (msg_ctx == NULL) {
438                 fprintf(stderr, "messaging_init failed\n");
439                 goto fail;
440         }
441
442         dst = messaging_server_id(msg_ctx);
443         dst.pid = child;
444
445         ret = msg_pingpong(msg_ctx, dst);
446         if (ret != 0){
447                 fprintf(stderr, "msg_pingpong failed\n");
448                 goto fail;
449         }
450
451         printf("Parent: telling child to exit\n");
452
453         written = write(exit_pipe[1], &c, 1);
454         if (written != 1) {
455                 perror("write to exit_pipe failed");
456                 goto fail;
457         }
458
459         ret = waitpid(child, NULL, 0);
460         if (ret == -1) {
461                 perror("waitpid failed");
462                 goto fail;
463         }
464
465         printf("Parent: child exited. Done\n");
466
467         retval = true;
468 fail:
469         TALLOC_FREE(msg_ctx);
470         TALLOC_FREE(ev);
471         return retval;
472 }