diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/test-istream-unix.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/src/lib/test-istream-unix.c b/src/lib/test-istream-unix.c new file mode 100644 index 0000000..e1fb649 --- /dev/null +++ b/src/lib/test-istream-unix.c @@ -0,0 +1,187 @@ +/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "net.h" +#include "fdpass.h" +#include "istream.h" +#include "istream-unix.h" + +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +static int send_fd, send_fd2; + +static void write_one(int fd) +{ + if (write(fd, "1", 1) < 0) + i_fatal("write() failed: %m"); +} + +static void read_one(int fd) +{ + char buf; + + if (read(fd, &buf, 1) < 0) + i_fatal("read() failed: m"); +} + +static void +test_server_read_nofd(struct istream *input, unsigned int idx) +{ + const unsigned char *data; + size_t size; + + test_assert_idx(i_stream_read_more(input, &data, &size) == 1, idx); + i_stream_skip(input, 1); + test_assert_idx(i_stream_unix_get_read_fd(input) == -1, idx); +} + +static void +test_server_read_fd(struct istream *input, int wanted_fd, unsigned int idx) +{ + struct stat st1, st2; + const unsigned char *data; + size_t size; + int recv_fd; + + test_assert_idx(i_stream_read_more(input, &data, &size) == 1, idx); + i_stream_skip(input, 1); + test_assert_idx((recv_fd = i_stream_unix_get_read_fd(input)) != -1, idx); + if (recv_fd != -1) { + if (fstat(recv_fd, &st1) < 0 || fstat(wanted_fd, &st2) < 0) + i_fatal("fstat() failed: %m"); + test_assert_idx(st1.st_ino == st2.st_ino, idx); + i_close_fd(&recv_fd); + } +} + +static void test_istream_unix_server(int fd) +{ + struct istream *input; + const unsigned char *data; + size_t size; + + input = i_stream_create_unix(fd, 1024); + /* 1) simple read */ + test_server_read_nofd(input, 1); + write_one(fd); + + /* 2) fd was sent but we won't get it */ + test_server_read_nofd(input, 2); + /* we still shouldn't have the fd */ + i_stream_set_blocking(input, FALSE); + i_stream_unix_set_read_fd(input); + test_assert(i_stream_read_more(input, &data, &size) == 0); + test_assert(i_stream_unix_get_read_fd(input) == -1); + i_stream_set_blocking(input, TRUE); + write_one(fd); + + /* 3) the previous fd should be lost now */ + test_server_read_nofd(input, 3); + write_one(fd); + + /* 4) we should get the fd now */ + test_server_read_fd(input, send_fd2, 4); + write_one(fd); + + /* 5) the previous fd shouldn't be returned anymore */ + i_stream_unix_set_read_fd(input); + test_server_read_nofd(input, 5); + write_one(fd); + + /* 6) with i_stream_unix_unset_read_fd() we shouldn't get fd anymore */ + i_stream_unix_unset_read_fd(input); + test_server_read_nofd(input, 6); + write_one(fd); + + /* 7-8) two fds were sent, but we'll get only the first one */ + i_stream_unix_set_read_fd(input); + test_server_read_fd(input, send_fd, 7); + test_server_read_nofd(input, 8); + write_one(fd); + + /* 9-10) two fds were sent, and we'll get them both */ + i_stream_unix_set_read_fd(input); + test_server_read_fd(input, send_fd, 9); + i_stream_unix_set_read_fd(input); + test_server_read_fd(input, send_fd2, 10); + write_one(fd); + + i_stream_destroy(&input); + i_close_fd(&fd); +} + +static void test_istream_unix_client(int fd) +{ + /* 1) */ + write_one(fd); + read_one(fd); + + /* 2) */ + if (fd_send(fd, send_fd, "1", 1) < 0) + i_fatal("fd_send() failed: %m"); + read_one(fd); + + /* 3) */ + write_one(fd); + read_one(fd); + + /* 4) */ + if (fd_send(fd, send_fd2, "1", 1) < 0) + i_fatal("fd_send() failed: %m"); + read_one(fd); + + /* 5) */ + write_one(fd); + read_one(fd); + + /* 6) */ + if (fd_send(fd, send_fd, "1", 1) < 0) + i_fatal("fd_send() failed: %m"); + read_one(fd); + + /* 7-8) */ + if (fd_send(fd, send_fd, "1", 1) < 0) + i_fatal("fd_send() failed: %m"); + if (fd_send(fd, send_fd2, "1", 1) < 0) + i_fatal("fd_send() failed: %m"); + read_one(fd); + + /* 9-10) */ + if (fd_send(fd, send_fd, "1", 1) < 0) + i_fatal("fd_send() failed: %m"); + if (fd_send(fd, send_fd2, "1", 1) < 0) + i_fatal("fd_send() failed: %m"); + read_one(fd); + + i_close_fd(&fd); +} + +void test_istream_unix(void) +{ + int fd[2]; + + test_begin("istream unix"); + if ((send_fd = open("/dev/null", O_RDONLY)) == -1) + i_fatal("open(/dev/null) failed: %m"); + if ((send_fd2 = open("/dev/zero", O_RDONLY)) == -1) + i_fatal("open(/dev/zero) failed: %m"); + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) + i_fatal("socketpair() failed: %m"); + switch (fork()) { + case -1: + i_fatal("fork() failed: %m"); + case 0: + i_close_fd(&fd[0]); + test_istream_unix_client(fd[1]); + test_exit(0); + default: + i_close_fd(&fd[1]); + test_istream_unix_server(fd[0]); + break; + } + i_close_fd(&send_fd); + i_close_fd(&send_fd2); + test_end(); +} |