From: Michael Adam Date: Tue, 23 Sep 2014 07:53:15 +0000 (+0200) Subject: s3:torture: work on LOCAL-MESSAGING-FDPASS2 X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=5ed8be7b2ecf13fec5c210680ef95663a63e2ed5;p=obnox%2Fsamba%2Fsamba-obnox.git s3:torture: work on LOCAL-MESSAGING-FDPASS2 - parent: fork - parent: create up and down pipes, - parent: pass read end of up pipe and write end of down pipe to child - parent: write to up pipe - child: read from up pipe - child: write to down pipe - parent: read from down pipe Signed-off-by: Michael Adam Reviewed-by: Stefan Metzmacher --- diff --git a/source3/torture/proto.h b/source3/torture/proto.h index 0402f1a7c9f..a1d4151a0d9 100644 --- a/source3/torture/proto.h +++ b/source3/torture/proto.h @@ -117,6 +117,7 @@ bool run_messaging_read1(int dummy); bool run_messaging_read2(int dummy); bool run_messaging_read3(int dummy); bool run_messaging_fdpass1(int dummy); +bool run_messaging_fdpass2(int dummy); bool run_oplock_cancel(int dummy); #endif /* __TORTURE_H__ */ diff --git a/source3/torture/test_messaging_fd_passing.c b/source3/torture/test_messaging_fd_passing.c index b860939d46e..1a296e441cc 100644 --- a/source3/torture/test_messaging_fd_passing.c +++ b/source3/torture/test_messaging_fd_passing.c @@ -75,3 +75,239 @@ fail: TALLOC_FREE(frame); return retval; } + +/** + * test fdpass2: + * + * - parent: create a child + * - parent: create a two pipes in the parent: up and down + * - parent: pass the up pipe's reading end and the down pipe's writing + * end to the child and close them + * - parent: write a number into the up pipe's writing end + * - child: read number from the passed reading fd (up) + * - child: write the read number to the passed writing fd (down) + * - parent: read number from the down pipe's reading end and compare with + * original number + */ + +#define MSG_TORTURE_FDPASS2 0xF002 + +static bool fdpass2_filter(struct messaging_rec *rec, void *private_data) +{ + if (rec->msg_type != MSG_TORTURE_FDPASS2) { + return false; + } + + if (rec->num_fds != 2) { + return false; + } + + return true; +} + +static bool fdpass2_child(int ready_fd) +{ + struct tevent_context *ev = NULL; + struct messaging_context *msg_ctx = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + bool retval = false; + uint8_t c = 1; + struct tevent_req *subreq; + int ret; + ssize_t bytes; + int up_fd, down_fd; + struct messaging_rec *rec; + bool ok; + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + fprintf(stderr, "child: tevent_context_init failed\n"); + goto done; + } + + msg_ctx = messaging_init(ev, ev); + if (msg_ctx == NULL) { + fprintf(stderr, "child: messaging_init failed\n"); + goto done; + } + + /* Tell the parent we are ready to receive mesages. */ + bytes = write(ready_fd, &c, 1); + if (bytes != 1) { + perror("child: failed to write to error_pipe"); + goto done; + } + + subreq = messaging_filtered_read_send(frame, /* TALLOC_CTX */ + ev, msg_ctx, + fdpass2_filter, NULL); + if (subreq == NULL) { + fprintf(stderr, "child: messaging_filtered_read_send failed\n"); + goto done; + } + + ok = tevent_req_poll(subreq, ev); + if (!ok) { + fprintf(stderr, "child: tevent_req_poll failed\n"); + goto done; + } + + ret = messaging_filtered_read_recv(subreq, frame, &rec); + TALLOC_FREE(subreq); + if (ret != 0) { + fprintf(stderr, "child: messaging_filtered_read_recv failed\n"); + goto done; + } + + SMB_ASSERT(rec->num_fds == 2); + + up_fd = rec->fds[0]; + down_fd = rec->fds[1]; + + bytes = read(up_fd, &c, 1); + if (bytes != 1) { + perror("child: read from up_fd failed"); + goto done; + } + + bytes = write(down_fd, &c, 1); + if (bytes != 1) { + perror("child: write to down_fd failed"); + } + + printf("child: done\n"); + + retval = true; + +done: + TALLOC_FREE(frame); + return retval; +} + +static bool fdpass2_parent(pid_t child_pid, int ready_fd) +{ + struct tevent_context *ev = NULL; + struct messaging_context *msg_ctx = NULL; + bool retval = false; + int up_pipe[2]; + int down_pipe[2]; + int pass_fds[2] = { 0 }; + int ret; + NTSTATUS status; + struct server_id dst; + TALLOC_CTX *frame = talloc_stackframe(); + uint8_t c1 = 1, c2, c; + ssize_t bytes; + struct iovec iov; + DATA_BLOB blob; + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + fprintf(stderr, "parent: tevent_context_init failed\n"); + goto done; + } + + msg_ctx = messaging_init(ev, ev); + if (msg_ctx == NULL) { + fprintf(stderr, "parent: messaging_init failed\n"); + goto done; + } + + /* wait util the child is ready to receive messages */ + bytes = read(ready_fd, &c, 1); + if (bytes != 1) { + perror("parent: read from ready_fd failed"); + goto done; + } + + ret = pipe(up_pipe); + if (ret != 0) { + perror("parent: pipe failed for up_pipe"); + goto done; + } + + ret = pipe(down_pipe); + if (ret != 0) { + perror("parent: pipe failed for down_pipe"); + goto done; + } + + pass_fds[0] = up_pipe[0]; + pass_fds[1] = down_pipe[1]; + + dst = messaging_server_id(msg_ctx); + dst.pid = child_pid; + + /* + * Send a certain payload with the fds, to test to test + * that fd-passing works when we have fragmentation and + * re-assembly of the datagrams. + */ + blob = data_blob_talloc_zero(frame, 2*1000); + iov.iov_base = blob.data; + iov.iov_len = blob.length; + + status = messaging_send_iov(msg_ctx, dst, MSG_TORTURE_FDPASS2, &iov, 1, + pass_fds, 2); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, "parent: messaging_send_iov failed: %s\n", + nt_errstr(status)); + goto done; + } + + bytes = write(up_pipe[1], &c1, 1); + if (bytes != 1) { + perror("parent: write to up pipe failed"); + goto done; + } + + bytes = read(down_pipe[0], &c2, 1); + if (bytes != 1) { + perror("parent: read from down pipe failed"); + goto done; + } + + if (c1 != c2) { + fprintf(stderr, "parent: c1[%d] != c2[%d]\n", c1, c2); + goto done; + } + + ret = waitpid(child_pid, NULL, 0); + if (ret == -1) { + perror("parent: waitpid failed"); + goto done; + } + + retval = true; + +done: + TALLOC_FREE(frame); + return retval; +} + +bool run_messaging_fdpass2(int dummy) +{ + bool retval = false; + pid_t child_pid; + int ready_pipe[2]; + int ret; + + ret = pipe(ready_pipe); + if (ret != 0) { + perror("parent: pipe failed for ready_pipe"); + return retval; + } + + child_pid = fork(); + if (child_pid == -1) { + perror("fork failed"); + } else if (child_pid == 0) { + close(ready_pipe[0]); + retval = fdpass2_child(ready_pipe[1]); + } else { + close(ready_pipe[1]); + retval = fdpass2_parent(child_pid, ready_pipe[0]); + } + + return retval; +} diff --git a/source3/torture/torture.c b/source3/torture/torture.c index b3d9237ba3a..ebc81db9d5f 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -9607,6 +9607,7 @@ static struct { { "LOCAL-MESSAGING-READ2", run_messaging_read2, 0 }, { "LOCAL-MESSAGING-READ3", run_messaging_read3, 0 }, { "LOCAL-MESSAGING-FDPASS1", run_messaging_fdpass1, 0 }, + { "LOCAL-MESSAGING-FDPASS2", run_messaging_fdpass2, 0 }, { "LOCAL-BASE64", run_local_base64, 0}, { "LOCAL-RBTREE", run_local_rbtree, 0}, { "LOCAL-MEMCACHE", run_local_memcache, 0},