libsmb: Use clistr_smb2_extract_snapshot_token() in cli_smb2_create_fnum_send()
[Samba.git] / source3 / torture / test_messaging_read.c
blob555f084c040b7effcff2bd936b656f097b6cc944
1 /*
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/>.
20 #include "includes.h"
21 #include "torture/proto.h"
22 #include "lib/util/tevent_unix.h"
23 #include "messages.h"
25 struct msg_count_state {
26 struct tevent_context *ev;
27 struct messaging_context *msg_ctx;
28 uint32_t msg_type;
29 unsigned *count;
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,
37 uint32_t msg_type,
38 unsigned *count)
40 struct tevent_req *req, *subreq;
41 struct msg_count_state *state;
43 req = tevent_req_create(mem_ctx, &state, struct msg_count_state);
44 if (req == NULL) {
45 return NULL;
47 state->ev = ev;
48 state->msg_ctx = msg_ctx;
49 state->msg_type = msg_type;
50 state->count = count;
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);
57 tevent_req_set_callback(subreq, msg_count_done, req);
58 return 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);
67 int ret;
69 ret = messaging_read_recv(subreq, NULL, NULL);
70 TALLOC_FREE(subreq);
71 if (tevent_req_error(req, ret)) {
72 return;
74 *state->count += 1;
76 subreq = messaging_read_send(state, state->ev, state->msg_ctx,
77 state->msg_type);
78 if (tevent_req_nomem(subreq, req)) {
79 return;
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;
89 unsigned count1 = 0;
90 struct tevent_req *req2 = NULL;
91 unsigned count2 = 0;
92 NTSTATUS status;
93 bool retval = false;
94 int i;
96 ev = samba_tevent_context_init(talloc_tos());
97 if (ev == NULL) {
98 fprintf(stderr, "tevent_context_init failed\n");
99 goto fail;
101 msg_ctx = messaging_init(ev, ev);
102 if (msg_ctx == NULL) {
103 fprintf(stderr, "messaging_init failed\n");
104 goto fail;
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;
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;
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;
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;
132 printf("%u/%u\n", count1, count2);
134 if ((count1 != 1) || (count2 != 0)) {
135 fprintf(stderr, "Got %u/%u msgs, expected 1/0\n",
136 count1, count2);
137 goto fail;
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;
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,
158 uint32_t msg_type,
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);
165 if (req == NULL) {
166 return NULL;
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);
175 return 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);
184 int ret;
186 ret = messaging_read_recv(subreq, NULL, NULL);
187 TALLOC_FREE(subreq);
188 if (tevent_req_error(req, ret)) {
189 return;
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;
201 unsigned count = 0;
202 NTSTATUS status;
203 bool retval = false;
205 ev = samba_tevent_context_init(talloc_tos());
206 if (ev == NULL) {
207 fprintf(stderr, "tevent_context_init failed\n");
208 goto fail;
210 msg_ctx = messaging_init(ev, ev);
211 if (msg_ctx == NULL) {
212 fprintf(stderr, "messaging_init failed\n");
213 goto fail;
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;
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;
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;
234 if (!tevent_req_poll(req1, ev) != 0) {
235 fprintf(stderr, "tevent_req_poll failed\n");
236 goto fail;
239 if (count != 0) {
240 fprintf(stderr, "Got %u msgs, expected none\n", count);
241 goto fail;
244 retval = true;
245 fail:
246 TALLOC_FREE(req1);
247 TALLOC_FREE(msg_ctx);
248 TALLOC_FREE(ev);
249 return retval;
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;
264 NTSTATUS status;
266 req = tevent_req_create(mem_ctx, &state, struct msg_pingpong_state);
267 if (req == NULL) {
268 return NULL;
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);
292 return 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);
299 int ret;
301 ret = messaging_read_recv(subreq, NULL, NULL);
302 TALLOC_FREE(subreq);
303 if (ret != 0) {
304 tevent_req_error(req, ret);
305 return;
307 tevent_req_done(req);
310 static int msg_pingpong_recv(struct tevent_req *req)
312 int err;
314 if (tevent_req_is_unix_error(req, &err)) {
315 return err;
317 return 0;
320 static int msg_pingpong(struct server_id dst)
322 struct tevent_context *ev;
323 struct tevent_req *req;
324 int ret = ENOMEM;
326 ev = tevent_context_init(talloc_tos());
327 if (ev == NULL) {
328 goto fail;
330 req = msg_pingpong_send(ev, ev, dst);
331 if (req == NULL) {
332 goto fail;
334 if (!tevent_req_poll(req, ev)) {
335 ret = errno;
336 goto fail;
338 ret = msg_pingpong_recv(req);
339 fail:
340 TALLOC_FREE(ev);
341 return ret;
344 static void ping_responder_exit(struct tevent_context *ev,
345 struct tevent_fd *fde,
346 uint16_t flags,
347 void *private_data)
349 bool *done = private_data;
351 printf("Child: received write on exit-pipe\n");
353 *done = true;
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;
361 char c = 0;
362 bool done = false;
364 ev = samba_tevent_context_init(talloc_tos());
365 if (ev == NULL) {
366 fprintf(stderr, "child tevent_context_init failed\n");
367 exit(1);
369 msg_ctx = messaging_init(ev, ev);
370 if (msg_ctx == NULL) {
371 fprintf(stderr, "child messaging_init failed\n");
372 exit(1);
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");
378 exit(1);
381 if (write(ready_pipe, &c, 1) != 1) {
382 fprintf(stderr, "child messaging_init failed\n");
383 exit(1);
386 while (!done) {
387 int ret;
388 ret = tevent_loop_once(ev);
389 if (ret != 0) {
390 fprintf(stderr, "child tevent_loop_once failed\n");
391 exit(1);
395 printf("Child: done, exiting...\n");
397 TALLOC_FREE(msg_ctx);
398 TALLOC_FREE(ev);
401 bool run_messaging_read3(int dummy)
403 struct tevent_context *ev = NULL;
404 struct messaging_context *msg_ctx = NULL;
405 bool retval = false;
406 pid_t child;
407 int ready_pipe[2];
408 int exit_pipe[2];
409 int i, ret;
410 char c;
411 struct server_id dst;
412 ssize_t written;
414 if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
415 perror("pipe failed");
416 return false;
419 child = fork();
420 if (child == -1) {
421 perror("fork failed");
422 return false;
425 if (child == 0) {
426 close(ready_pipe[0]);
427 close(exit_pipe[1]);
428 ping_responder(ready_pipe[1], exit_pipe[0]);
429 exit(0);
431 close(ready_pipe[1]);
432 close(exit_pipe[0]);
434 if (read(ready_pipe[0], &c, 1) != 1) {
435 perror("read failed");
436 return false;
439 ev = samba_tevent_context_init(talloc_tos());
440 if (ev == NULL) {
441 fprintf(stderr, "tevent_context_init failed\n");
442 goto fail;
445 dst = (struct server_id){ .pid = child, .vnn = NONCLUSTER_VNN, };
447 for (i=0; i<100; i++) {
448 ret = msg_pingpong(dst);
449 if (ret != 0){
450 fprintf(stderr, "msg_pingpong failed\n");
451 goto fail;
455 printf("Parent: telling child to exit\n");
457 written = write(exit_pipe[1], &c, 1);
458 if (written != 1) {
459 perror("write to exit_pipe failed");
460 goto fail;
463 ret = waitpid(child, NULL, 0);
464 if (ret == -1) {
465 perror("waitpid failed");
466 goto fail;
469 printf("Parent: child exited. Done\n");
471 retval = true;
472 fail:
473 TALLOC_FREE(msg_ctx);
474 TALLOC_FREE(ev);
475 return retval;
479 * read4:
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();
491 bool retval = false;
492 uint8_t c = 1;
493 struct tevent_req *subreq;
494 int ret;
495 ssize_t bytes;
496 struct messaging_rec *rec;
497 bool ok;
499 ev = samba_tevent_context_init(frame);
500 if (ev == NULL) {
501 fprintf(stderr, "child: tevent_context_init failed\n");
502 goto done;
505 msg_ctx = messaging_init(ev, ev);
506 if (msg_ctx == NULL) {
507 fprintf(stderr, "child: messaging_init failed\n");
508 goto done;
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);
515 if (bytes != 1) {
516 perror("child: failed to write to ready_fd");
517 goto done;
520 printf("child: waiting for messages\n");
522 subreq = messaging_read_send(frame, /* TALLOC_CTX */
523 ev, msg_ctx,
524 MSG_TORTURE_READ4);
525 if (subreq == NULL) {
526 fprintf(stderr, "child: messaging_read_send failed\n");
527 goto done;
530 ok = tevent_req_poll(subreq, ev);
531 if (!ok) {
532 fprintf(stderr, "child: tevent_req_poll failed\n");
533 goto done;
536 printf("child: receiving message\n");
538 ret = messaging_read_recv(subreq, frame, &rec);
539 TALLOC_FREE(subreq);
540 if (ret != 0) {
541 fprintf(stderr, "child: messaging_read_recv failed\n");
542 goto done;
545 printf("child: received message\n");
547 /* Tell the parent we are done. */
548 bytes = write(ready_fd, &c, 1);
549 if (bytes != 1) {
550 perror("child: failed to write to ready_fd");
551 goto done;
554 printf("child: done\n");
556 retval = true;
558 done:
559 TALLOC_FREE(frame);
560 return retval;
563 struct child_done_state {
564 int fd;
565 bool done;
568 static void child_done_cb(struct tevent_context *ev,
569 struct tevent_fd *fde,
570 uint16_t flags,
571 void *private_data)
573 struct child_done_state *state =
574 (struct child_done_state *)private_data;
575 char c = 0;
576 ssize_t bytes;
578 bytes = read(state->fd, &c, 1);
579 if (bytes != 1) {
580 perror("parent: read from ready_fd failed");
583 state->done = true;
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;
590 bool retval = false;
591 int ret;
592 NTSTATUS status;
593 struct server_id dst;
594 TALLOC_CTX *frame = talloc_stackframe();
595 uint8_t c;
596 ssize_t bytes;
597 struct iovec iov;
598 DATA_BLOB blob;
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);
604 if (bytes != 1) {
605 perror("parent: read from ready_fd failed");
606 goto done;
609 printf("parent: child is ready to receive messages\n");
611 ev = samba_tevent_context_init(frame);
612 if (ev == NULL) {
613 fprintf(stderr, "parent: tevent_context_init failed\n");
614 goto done;
617 msg_ctx = messaging_init(ev, ev);
618 if (msg_ctx == NULL) {
619 fprintf(stderr, "parent: messaging_init failed\n");
620 goto done;
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) {
629 fprintf(stderr,
630 "parent: failed tevent_add_fd for child done\n");
631 goto done;
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);
642 dst.pid = child_pid;
644 printf("parent: sending message to child\n");
646 status = messaging_send_iov(msg_ctx, dst, MSG_TORTURE_READ4, &iov, 1,
647 NULL, 0);
648 if (!NT_STATUS_IS_OK(status)) {
649 fprintf(stderr, "parent: messaging_send_iov failed: %s\n",
650 nt_errstr(status));
651 goto done;
654 printf("parent: waiting for child to confirm\n");
656 while (!child_state.done) {
657 ret = tevent_loop_once(ev);
658 if (ret != 0) {
659 fprintf(stderr, "parent: tevent_loop_once failed\n");
660 goto done;
664 printf("parent: child confirmed\n");
666 ret = waitpid(child_pid, NULL, 0);
667 if (ret == -1) {
668 perror("parent: waitpid failed");
669 goto done;
672 printf("parent: done\n");
674 retval = true;
676 done:
677 TALLOC_FREE(frame);
678 return retval;
681 bool run_messaging_read4(int dummy)
683 bool retval = false;
684 pid_t child_pid;
685 int ready_pipe[2];
686 int ret;
688 ret = pipe(ready_pipe);
689 if (ret != 0) {
690 perror("parent: pipe failed for ready_pipe");
691 return retval;
694 child_pid = fork();
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]);
700 } else {
701 close(ready_pipe[1]);
702 retval = read4_parent(child_pid, ready_pipe[0]);
705 return retval;