bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include "test-lib.h"
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include "net.h"
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include "fdpass.h"
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include "istream.h"
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include "istream-unix.h"
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include <unistd.h>
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include <fcntl.h>
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen#include <sys/stat.h>
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenstatic int send_fd, send_fd2;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenstatic void write_one(int fd)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen{
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen if (write(fd, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("write() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen}
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenstatic void read_one(int fd)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen{
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen char buf;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen if (read(fd, &buf, 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("read() failed: m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen}
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenstatic void
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainentest_server_read_nofd(struct istream *input, unsigned int idx)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen{
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen const unsigned char *data;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen size_t size;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody test_assert_idx(i_stream_read_more(input, &data, &size) == 1, idx);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_skip(input, 1);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_assert_idx(i_stream_unix_get_read_fd(input) == -1, idx);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen}
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenstatic void
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainentest_server_read_fd(struct istream *input, int wanted_fd, unsigned int idx)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen{
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen struct stat st1, st2;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen const unsigned char *data;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen size_t size;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen int recv_fd;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody test_assert_idx(i_stream_read_more(input, &data, &size) == 1, idx);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_skip(input, 1);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_assert_idx((recv_fd = i_stream_unix_get_read_fd(input)) != -1, idx);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen if (recv_fd != -1) {
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen if (fstat(recv_fd, &st1) < 0 || fstat(wanted_fd, &st2) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fstat() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_assert_idx(st1.st_ino == st2.st_ino, idx);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_close_fd(&recv_fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen }
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen}
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenstatic void test_istream_unix_server(int fd)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen{
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen struct istream *input;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen const unsigned char *data;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen size_t size;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen input = i_stream_create_unix(fd, 1024);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 1) simple read */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_nofd(input, 1);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 2) fd was sent but we won't get it */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_nofd(input, 2);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* we still shouldn't have the fd */
874f31bbdca027b71371f03ea3646c31f0a05c01Timo Sirainen i_stream_set_blocking(input, FALSE);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_unix_set_read_fd(input);
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody test_assert(i_stream_read_more(input, &data, &size) == 0);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_assert(i_stream_unix_get_read_fd(input) == -1);
874f31bbdca027b71371f03ea3646c31f0a05c01Timo Sirainen i_stream_set_blocking(input, TRUE);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 3) the previous fd should be lost now */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_nofd(input, 3);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 4) we should get the fd now */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_fd(input, send_fd2, 4);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 5) the previous fd shouldn't be returned anymore */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_unix_set_read_fd(input);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_nofd(input, 5);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 6) with i_stream_unix_unset_read_fd() we shouldn't get fd anymore */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_unix_unset_read_fd(input);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_nofd(input, 6);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 7-8) two fds were sent, but we'll get only the first one */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_unix_set_read_fd(input);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_fd(input, send_fd, 7);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_nofd(input, 8);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 9-10) two fds were sent, and we'll get them both */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_unix_set_read_fd(input);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_fd(input, send_fd, 9);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_unix_set_read_fd(input);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_server_read_fd(input, send_fd2, 10);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_stream_destroy(&input);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_close_fd(&fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen}
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenstatic void test_istream_unix_client(int fd)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen{
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 1) */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 2) */
4c1a936be3273581135eb9ba7a1cbcdb1ffd6cc6Timo Sirainen if (fd_send(fd, send_fd, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fd_send() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 3) */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 4) */
4c1a936be3273581135eb9ba7a1cbcdb1ffd6cc6Timo Sirainen if (fd_send(fd, send_fd2, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fd_send() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 5) */
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen write_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 6) */
4c1a936be3273581135eb9ba7a1cbcdb1ffd6cc6Timo Sirainen if (fd_send(fd, send_fd, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fd_send() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 7-8) */
4c1a936be3273581135eb9ba7a1cbcdb1ffd6cc6Timo Sirainen if (fd_send(fd, send_fd, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fd_send() failed: %m");
4c1a936be3273581135eb9ba7a1cbcdb1ffd6cc6Timo Sirainen if (fd_send(fd, send_fd2, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fd_send() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen /* 9-10) */
4c1a936be3273581135eb9ba7a1cbcdb1ffd6cc6Timo Sirainen if (fd_send(fd, send_fd, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fd_send() failed: %m");
4c1a936be3273581135eb9ba7a1cbcdb1ffd6cc6Timo Sirainen if (fd_send(fd, send_fd2, "1", 1) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fd_send() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen read_one(fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_close_fd(&fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen}
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainenvoid test_istream_unix(void)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen{
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen int fd[2];
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_begin("istream unix");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen if ((send_fd = open("/dev/null", O_RDONLY)) == -1)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("open(/dev/null) failed: %m");
d4e8dbd07007fc558697c9b579f999ef535d5157Timo Sirainen if ((send_fd2 = open("/dev/zero", O_RDONLY)) == -1)
d4e8dbd07007fc558697c9b579f999ef535d5157Timo Sirainen i_fatal("open(/dev/zero) failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0)
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("socketpair() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen switch (fork()) {
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen case -1:
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_fatal("fork() failed: %m");
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen case 0:
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_close_fd(&fd[0]);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_istream_unix_client(fd[1]);
bd1e1a9720ce4617f7d97be75cffc45e905bb791Phil Carmody test_exit(0);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen default:
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_close_fd(&fd[1]);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_istream_unix_server(fd[0]);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen break;
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen }
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_close_fd(&send_fd);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen i_close_fd(&send_fd2);
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen test_end();
bf132be3fe1c9e8de84f10d0b05c0b46ca542ac4Timo Sirainen}