Index: user/ngie/more-tests/tests/sys/socket/reconnect_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/reconnect_test.c (revision 281585) +++ user/ngie/more-tests/tests/sys/socket/reconnect_test.c (revision 281586) @@ -1,132 +1,132 @@ /*- * Copyright (c) 2005 Maxim Sobolev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * The reconnect regression test is designed to catch kernel bug that may * prevent changing association of already associated datagram unix domain * socket when server side of connection has been closed. */ #include #include #include #include #include #include #include #include #include #include #include #include static char uds_name1[] = "reconnect.XXXXXXXX"; static char uds_name2[] = "reconnect.XXXXXXXX"; #define sstosa(ss) ((struct sockaddr *)(ss)) static void prepare_ifsun(struct sockaddr_un *ifsun, const char *path) { memset(ifsun, '\0', sizeof(*ifsun)); #if !defined(__linux__) && !defined(__solaris__) ifsun->sun_len = strlen(path); #endif ifsun->sun_family = AF_LOCAL; strcpy(ifsun->sun_path, path); } static int create_uds_server(const char *path) { struct sockaddr_un ifsun; int sock; prepare_ifsun(&ifsun, path); unlink(ifsun.sun_path); sock = socket(PF_LOCAL, SOCK_DGRAM, 0); if (sock == -1) err(1, "can't create socket"); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock, sizeof(sock)); if (bind(sock, sstosa(&ifsun), sizeof(ifsun)) < 0) err(1, "can't bind to a socket"); return sock; } static void connect_uds_server(int sock, const char *path) { struct sockaddr_un ifsun; int e; prepare_ifsun(&ifsun, path); e = connect(sock, sstosa(&ifsun), sizeof(ifsun)); if (e < 0) err(1, "can't connect to a socket"); } static void cleanup(void) { unlink(uds_name1); unlink(uds_name2); } int -main() +main(void) { int s_sock1, s_sock2, c_sock; atexit(cleanup); if (mkstemp(uds_name1) == -1) err(1, "mkstemp"); unlink(uds_name1); s_sock1 = create_uds_server(uds_name1); if (mkstemp(uds_name2) == -1) err(1, "mkstemp"); unlink(uds_name2); s_sock2 = create_uds_server(uds_name2); c_sock = socket(PF_LOCAL, SOCK_DGRAM, 0); if (c_sock < 0) err(1, "can't create socket"); connect_uds_server(c_sock, uds_name1); close(s_sock1); connect_uds_server(c_sock, uds_name2); exit (0); } Index: user/ngie/more-tests/tests/sys/socket/sigpipe_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/sigpipe_test.c (revision 281585) +++ user/ngie/more-tests/tests/sys/socket/sigpipe_test.c (revision 281586) @@ -1,328 +1,329 @@ /*- * Copyright (c) 2005 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include /* * This regression test is intended to verify whether or not SIGPIPE is * properly generated in several simple test cases, as well as testing * whether SO_NOSIGPIPE disables SIGPIPE, if available on the system. * SIGPIPE is generated if a write or send is attempted on a socket that has * been shutdown for write. This test runs several test cases with UNIX * domain sockets and TCP sockets to confirm that either EPIPE or SIGPIPE is * properly returned. * * For the purposes of testing TCP, an unused port number must be specified. */ +static void usage(void) __dead2; static void usage(void) { errx(-1, "usage: sigpipe [tcpport]"); } /* * Signal catcher. Set a global flag that can be tested by the caller. */ static int signaled; static int got_signal(void) { return (signaled); } static void signal_handler(int signum __unused) { signaled = 1; } static void signal_setup(const char *testname) { signaled = 0; if (signal(SIGPIPE, signal_handler) == SIG_ERR) err(-1, "%s: signal(SIGPIPE)", testname); } static void test_send(const char *testname, int sock) { ssize_t len; char ch; ch = 0; len = send(sock, &ch, sizeof(ch), 0); if (len < 0) { if (errno == EPIPE) return; err(-1, "%s: send", testname); } errx(-1, "%s: send: returned %zd", testname, len); } static void test_write(const char *testname, int sock) { ssize_t len; char ch; ch = 0; len = write(sock, &ch, sizeof(ch)); if (len < 0) { if (errno == EPIPE) return; err(-1, "%s: write", testname); } errx(-1, "%s: write: returned %zd", testname, len); } static void test_send_wantsignal(const char *testname, int sock1, int sock2) { if (shutdown(sock2, SHUT_WR) < 0) err(-1, "%s: shutdown", testname); signal_setup(testname); test_send(testname, sock2); if (!got_signal()) errx(-1, "%s: send: didn't receive SIGPIPE", testname); close(sock1); close(sock2); } #ifdef SO_NOSIGPIPE static void test_send_dontsignal(const char *testname, int sock1, int sock2) { int i; i = 1; if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0) err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname); if (shutdown(sock2, SHUT_WR) < 0) err(-1, "%s: shutdown", testname); signal_setup(testname); test_send(testname, sock2); if (got_signal()) errx(-1, "%s: send: got SIGPIPE", testname); close(sock1); close(sock2); } #endif static void test_write_wantsignal(const char *testname, int sock1, int sock2) { if (shutdown(sock2, SHUT_WR) < 0) err(-1, "%s: shutdown", testname); signal_setup(testname); test_write(testname, sock2); if (!got_signal()) errx(-1, "%s: write: didn't receive SIGPIPE", testname); close(sock1); close(sock2); } #ifdef SO_NOSIGPIPE static void test_write_dontsignal(const char *testname, int sock1, int sock2) { int i; i = 1; if (setsockopt(sock2, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i)) < 0) err(-1, "%s: setsockopt(SOL_SOCKET, SO_NOSIGPIPE)", testname); if (shutdown(sock2, SHUT_WR) < 0) err(-1, "%s: shutdown", testname); signal_setup(testname); test_write(testname, sock2); if (got_signal()) errx(-1, "%s: write: got SIGPIPE", testname); close(sock1); close(sock2); } #endif static int listen_sock; static void tcp_setup(u_short port) { struct sockaddr_in sin; listen_sock = socket(PF_INET, SOCK_STREAM, 0); if (listen_sock < 0) err(-1, "tcp_setup: listen"); bzero(&sin, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_port = htons(port); if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(-1, "tcp_setup: bind"); if (listen(listen_sock, -1) < 0) err(-1, "tcp_setup: listen"); } static void tcp_teardown(void) { close(listen_sock); } static void tcp_pair(u_short port, int sock[2]) { int accept_sock, connect_sock; struct sockaddr_in sin; socklen_t len; connect_sock = socket(PF_INET, SOCK_STREAM, 0); if (connect_sock < 0) err(-1, "tcp_pair: socket"); bzero(&sin, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_port = htons(port); if (connect(connect_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(-1, "tcp_pair: connect"); sleep(1); /* Time for TCP to settle. */ len = sizeof(sin); accept_sock = accept(listen_sock, (struct sockaddr *)&sin, &len); if (accept_sock < 0) err(-1, "tcp_pair: accept"); sleep(1); /* Time for TCP to settle. */ sock[0] = accept_sock; sock[1] = connect_sock; } int main(int argc, char *argv[]) { char *dummy; int sock[2]; long port; if (argc == 1) { srandomdev(); /* Pick a random unprivileged port 1025-65535 */ port = MAX((int)random() % 65535, 1025); } else if (argc == 2) { port = strtol(argv[1], &dummy, 10); if (port < 0 || port > 65535 || *dummy != '\0') usage(); } else usage(); #ifndef SO_NOSIGPIPE warnx("sigpipe: SO_NOSIGPIPE not defined, skipping some tests"); #endif /* * UNIX domain socketpair(). */ if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); test_send_wantsignal("test_send_wantsignal(PF_LOCAL)", sock[0], sock[1]); #ifdef SO_NOSIGPIPE if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); test_send_dontsignal("test_send_dontsignal(PF_LOCAL)", sock[0], sock[1]); #endif if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); test_write_wantsignal("test_write_wantsignal(PF_LOCAL)", sock[0], sock[1]); #ifdef SO_NOSIGPIPE if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sock) < 0) err(-1, "socketpair(PF_LOCAL, SOCK_STREAM)"); test_write_dontsignal("test_write_dontsignal(PF_LOCAL)", sock[0], sock[1]); #endif /* * TCP. */ tcp_setup(port); tcp_pair(port, sock); test_send_wantsignal("test_send_wantsignal(PF_INET)", sock[0], sock[1]); #ifdef SO_NOSIGPIPE tcp_pair(port, sock); test_send_dontsignal("test_send_dontsignal(PF_INET)", sock[0], sock[1]); #endif tcp_pair(port, sock); test_write_wantsignal("test_write_wantsignal(PF_INET)", sock[0], sock[1]); #ifdef SO_NOSIGPIPE tcp_pair(port, sock); test_write_dontsignal("test_write_dontsignal(PF_INET)", sock[0], sock[1]); #endif tcp_teardown(); fprintf(stderr, "PASS\n"); return (0); } Index: user/ngie/more-tests/tests/sys/socket/unix_gc_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_gc_test.c (revision 281585) +++ user/ngie/more-tests/tests/sys/socket/unix_gc_test.c (revision 281586) @@ -1,808 +1,808 @@ /*- * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * A few regression tests for UNIX domain sockets. Run from single-user mode * as it checks the openfiles sysctl to look for leaks, and we don't want that * changing due to other processes doing stuff. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int forcegc = 1; static char dpath[PATH_MAX]; static const char *test; static int getsysctl(const char *name) { size_t len; int i; len = sizeof(i); if (sysctlbyname(name, &i, &len, NULL, 0) < 0) err(-1, "%s", name); return (i); } static int getopenfiles(void) { return (getsysctl("kern.openfiles")); } static int getinflight(void) { return (getsysctl("net.local.inflight")); } static int getdeferred(void) { return (getsysctl("net.local.deferred")); } static void sendfd(int fd, int fdtosend) { struct msghdr mh; struct message { struct cmsghdr msg_hdr; int fd; } m; ssize_t len; int after_inflight, before_inflight; before_inflight = getinflight(); bzero(&mh, sizeof(mh)); bzero(&m, sizeof(m)); mh.msg_control = &m; mh.msg_controllen = sizeof(m); m.msg_hdr.cmsg_len = sizeof(m); m.msg_hdr.cmsg_level = SOL_SOCKET; m.msg_hdr.cmsg_type = SCM_RIGHTS; m.fd = fdtosend; len = sendmsg(fd, &mh, 0); if (len < 0) err(-1, "%s: sendmsg", test); after_inflight = getinflight(); if (after_inflight != before_inflight + 1) errx(-1, "%s: sendfd: before %d after %d\n", test, before_inflight, after_inflight); } static void close2(int fd1, int fd2) { close(fd1); close(fd2); } static void close3(int fd1, int fd2, int fd3) { close2(fd1, fd2); close(fd3); } static void close4(int fd1, int fd2, int fd3, int fd4) { close2(fd1, fd2); close2(fd3, fd4); } static void close5(int fd1, int fd2, int fd3, int fd4, int fd5) { close3(fd1, fd2, fd3); close2(fd4, fd5); } static int my_socket(int domain, int type, int proto) { int sock; sock = socket(domain, type, proto); if (sock < 0) err(-1, "%s: socket", test); return (sock); } static void my_bind(int sock, struct sockaddr *sa, socklen_t len) { if (bind(sock, sa, len) < 0) err(-1, "%s: bind", test); } static void my_connect(int sock, struct sockaddr *sa, socklen_t len) { if (connect(sock, sa, len) < 0 && errno != EINPROGRESS) err(-1, "%s: connect", test); } static void my_listen(int sock, int backlog) { if (listen(sock, backlog) < 0) err(-1, "%s: listen", test); } static void my_socketpair(int *sv) { if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) err(-1, "%s: socketpair", test); } static void my_getsockname(int s, struct sockaddr *sa, socklen_t *salen) { if (getsockname(s, sa, salen) < 0) err(-1, "%s: getsockname", test); } static void setnonblock(int s) { if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) err(-1, "%s: fcntl(F_SETFL, O_NONBLOCK)", test); } static void alloc3fds(int *s, int *sv) { if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) err(-1, "%s: socket", test); if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) err(-1, "%s: socketpair", test); } static void alloc5fds(int *s, int *sva, int *svb) { if ((*s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) err(-1, "%s: socket", test); if (socketpair(PF_UNIX, SOCK_STREAM, 0, sva) < 0) err(-1, "%s: socketpair", test); if (socketpair(PF_UNIX, SOCK_STREAM, 0, svb) < 0) err(-1, "%s: socketpair", test); } static void save_sysctls(int *before_inflight, int *before_openfiles) { *before_inflight = getinflight(); *before_openfiles = getopenfiles(); } /* * Try hard to make sure that the GC does in fact run before we test the * condition of things. */ static void trigger_gc(void) { int s; if (forcegc) { if ((s = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) err(-1, "trigger_gc: socket"); close(s); } sleep(1); } static void test_sysctls(int before_inflight, int before_openfiles) { int after_inflight, after_openfiles; trigger_gc(); after_inflight = getinflight(); if (after_inflight != before_inflight) warnx("%s: before inflight: %d, after inflight: %d", test, before_inflight, after_inflight); after_openfiles = getopenfiles(); if (after_openfiles != before_openfiles) warnx("%s: before: %d, after: %d", test, before_openfiles, after_openfiles); } static void twosome_nothing(void) { int inflight, openfiles; int sv[2]; /* * Create a pair, close in one order. */ test = "twosome_nothing1"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); my_socketpair(sv); close2(sv[0], sv[1]); test_sysctls(inflight, openfiles); /* * Create a pair, close in the other order. */ test = "twosome_nothing2"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); my_socketpair(sv); close2(sv[0], sv[1]); test_sysctls(inflight, openfiles); } /* * Using a socket pair, send various endpoints over the pair and close in * various orders. */ static void twosome_drop_work(const char *testname, int sendvia, int tosend, int closefirst) { int inflight, openfiles; int sv[2]; printf("%s\n", testname); test = testname; save_sysctls(&inflight, &openfiles); my_socketpair(sv); sendfd(sv[sendvia], sv[tosend]); if (closefirst == 0) close2(sv[0], sv[1]); else close2(sv[1], sv[0]); test_sysctls(inflight, openfiles); } static void twosome_drop(void) { /* * In various combations, some wastefully symmetric, create socket * pairs and send one or another endpoint over one or another * endpoint, closing the endpoints in various orders. */ twosome_drop_work("twosome_drop1", 0, 0, 0); twosome_drop_work("twosome_drop2", 0, 0, 1); twosome_drop_work("twosome_drop3", 0, 1, 0); twosome_drop_work("twosome_drop4", 0, 1, 1); twosome_drop_work("twosome_drop5", 1, 0, 0); twosome_drop_work("twosome_drop6", 1, 0, 1); twosome_drop_work("twosome_drop7", 1, 1, 0); twosome_drop_work("twosome_drop8", 1, 1, 1); } static void threesome_nothing(void) { int inflight, openfiles; int s, sv[2]; test = "threesome_nothing"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc3fds(&s, sv); close3(s, sv[0], sv[1]); test_sysctls(inflight, openfiles); } /* * threesome_drop: create a pair and a spare, send the spare over the pair, and * close in various orders and make sure all the fds went away. */ static void threesome_drop(void) { int inflight, openfiles; int s, sv[2]; /* * threesome_drop1: close sent send receive */ test = "threesome_drop1"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc3fds(&s, sv); sendfd(sv[0], s); close3(s, sv[0], sv[1]); test_sysctls(inflight, openfiles); /* * threesome_drop2: close sent receive send */ test = "threesome_drop2"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc3fds(&s, sv); sendfd(sv[0], s); close3(s, sv[1], sv[0]); test_sysctls(inflight, openfiles); /* * threesome_drop3: close receive sent send */ test = "threesome_drop3"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc3fds(&s, sv); sendfd(sv[0], s); close3(sv[1], s, sv[0]); test_sysctls(inflight, openfiles); /* * threesome_drop4: close receive send sent */ test = "threesome_drop4"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc3fds(&s, sv); sendfd(sv[0], s); close3(sv[1], sv[0], s); test_sysctls(inflight, openfiles); /* * threesome_drop5: close send receive sent */ test = "threesome_drop5"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc3fds(&s, sv); sendfd(sv[0], s); close3(sv[0], sv[1], s); test_sysctls(inflight, openfiles); /* * threesome_drop6: close send sent receive */ test = "threesome_drop6"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc3fds(&s, sv); close3(sv[0], s, sv[1]); test_sysctls(inflight, openfiles); } /* * Fivesome tests: create two socket pairs and a spare, send the spare over * the first socket pair, then send the first socket pair over the second * socket pair, and GC. Do various closes at various points to exercise * various cases. */ static void fivesome_nothing(void) { int inflight, openfiles; int spare, sva[2], svb[2]; test = "fivesome_nothing"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc5fds(&spare, sva, svb); close5(spare, sva[0], sva[1], svb[0], svb[1]); test_sysctls(inflight, openfiles); } static void fivesome_drop_work(const char *testname, int close_spare_after_send, int close_sva_after_send) { int inflight, openfiles; int spare, sva[2], svb[2]; printf("%s\n", testname); test = testname; save_sysctls(&inflight, &openfiles); alloc5fds(&spare, sva, svb); /* * Send spare over sva. */ sendfd(sva[0], spare); if (close_spare_after_send) close(spare); /* * Send sva over svb. */ sendfd(svb[0], sva[0]); sendfd(svb[0], sva[1]); if (close_sva_after_send) close2(sva[0], sva[1]); close2(svb[0], svb[1]); if (!close_sva_after_send) close2(sva[0], sva[1]); if (!close_spare_after_send) close(spare); test_sysctls(inflight, openfiles); } static void fivesome_drop(void) { fivesome_drop_work("fivesome_drop1", 0, 0); fivesome_drop_work("fivesome_drop2", 0, 1); fivesome_drop_work("fivesome_drop3", 1, 0); fivesome_drop_work("fivesome_drop4", 1, 1); } /* * Create a somewhat nasty dual-socket socket intended to upset the garbage * collector if mark-and-sweep is wrong. */ static void complex_cycles(void) { int inflight, openfiles; int spare, sva[2], svb[2]; test = "complex_cycles"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); alloc5fds(&spare, sva, svb); sendfd(sva[0], svb[0]); sendfd(sva[0], svb[1]); sendfd(svb[0], sva[0]); sendfd(svb[0], sva[1]); sendfd(svb[0], spare); sendfd(sva[0], spare); close5(spare, sva[0], sva[1], svb[0], svb[1]); test_sysctls(inflight, openfiles); } /* * Listen sockets can also be passed over UNIX domain sockets, so test * various cases, including ones where listen sockets have waiting sockets * hanging off them... */ static void listen_nothing(void) { struct sockaddr_un sun; struct sockaddr_in sin; int inflight, openfiles; int s; test = "listen_nothing_unp"; printf("%s\n", test); bzero(&sun, sizeof(sun)); sun.sun_family = AF_LOCAL; sun.sun_len = sizeof(sun); snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test); save_sysctls(&inflight, &openfiles); s = my_socket(PF_LOCAL, SOCK_STREAM, 0); my_bind(s, (struct sockaddr *)&sun, sizeof(sun)); my_listen(s, -1); close(s); (void)unlink(sun.sun_path); test_sysctls(inflight, openfiles); test = "listen_nothing_inet"; printf("%s\n", test); bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_port = htons(0); save_sysctls(&inflight, &openfiles); s = my_socket(PF_INET, SOCK_STREAM, 0); my_bind(s, (struct sockaddr *)&sin, sizeof(sin)); my_listen(s, -1); close(s); test_sysctls(inflight, openfiles); } /* * Send a listen UDP socket over a UNIX domain socket. * * Send a listen TCP socket over a UNIX domain socket. * * Do each twice, with closing of the listen socket vs. socketpair in * different orders. */ static void listen_drop(void) { struct sockaddr_un sun; struct sockaddr_in sin; int inflight, openfiles; int s, sv[2]; bzero(&sun, sizeof(sun)); sun.sun_family = AF_LOCAL; sun.sun_len = sizeof(sun); /* * Close listen socket first. */ test = "listen_drop_unp1"; printf("%s\n", test); snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test); save_sysctls(&inflight, &openfiles); s = my_socket(PF_LOCAL, SOCK_STREAM, 0); my_bind(s, (struct sockaddr *)&sun, sizeof(sun)); my_listen(s, -1); my_socketpair(sv); sendfd(sv[0], s); close3(s, sv[0], sv[1]); test_sysctls(inflight, openfiles); /* * Close socketpair first. */ test = "listen_drop_unp2"; printf("%s\n", test); snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", dpath, test); save_sysctls(&inflight, &openfiles); s = my_socket(PF_LOCAL, SOCK_STREAM, 0); my_bind(s, (struct sockaddr *)&sun, sizeof(sun)); my_listen(s, -1); my_socketpair(sv); sendfd(sv[0], s); close3(sv[0], sv[1], s); test_sysctls(inflight, openfiles); sin.sin_family = AF_INET; sin.sin_len = sizeof(sin); sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sin.sin_port = htons(0); /* * Close listen socket first. */ test = "listen_drop_inet1"; printf("%s\n", test); bzero(&sun, sizeof(sun)); save_sysctls(&inflight, &openfiles); s = my_socket(PF_INET, SOCK_STREAM, 0); my_bind(s, (struct sockaddr *)&sin, sizeof(sin)); my_listen(s, -1); my_socketpair(sv); sendfd(sv[0], s); close3(s, sv[0], sv[1]); test_sysctls(inflight, openfiles); /* * Close socketpair first. */ test = "listen_drop_inet2"; printf("%s\n", test); bzero(&sun, sizeof(sun)); save_sysctls(&inflight, &openfiles); s = my_socket(PF_INET, SOCK_STREAM, 0); my_bind(s, (struct sockaddr *)&sin, sizeof(sin)); my_listen(s, -1); my_socketpair(sv); sendfd(sv[0], s); close3(sv[0], sv[1], s); test_sysctls(inflight, openfiles); } /* * Up things a notch with listen sockets: add connections that can be * accepted to the listen queues. */ static void listen_connect_nothing(void) { struct sockaddr_in sin; int slisten, sconnect, sv[2]; int inflight, openfiles; socklen_t len; test = "listen_connect_nothing"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); slisten = my_socket(PF_INET, SOCK_STREAM, 0); my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin)); my_listen(slisten, -1); my_socketpair(sv); len = sizeof(sin); my_getsockname(slisten, (struct sockaddr *)&sin, &len); sconnect = my_socket(PF_INET, SOCK_STREAM, 0); setnonblock(sconnect); my_connect(sconnect, (struct sockaddr *)&sin, len); sleep(1); close4(slisten, sconnect, sv[0], sv[1]); test_sysctls(inflight, openfiles); } static void listen_connect_drop(void) { struct sockaddr_in sin; int slisten, sconnect, sv[2]; int inflight, openfiles; socklen_t len; test = "listen_connect_drop"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); slisten = my_socket(PF_INET, SOCK_STREAM, 0); my_bind(slisten, (struct sockaddr *)&sin, sizeof(sin)); my_listen(slisten, -1); my_socketpair(sv); len = sizeof(sin); my_getsockname(slisten, (struct sockaddr *)&sin, &len); sconnect = my_socket(PF_INET, SOCK_STREAM, 0); setnonblock(sconnect); my_connect(sconnect, (struct sockaddr *)&sin, len); sleep(1); sendfd(sv[0], slisten); close3(slisten, sv[0], sv[1]); sleep(1); close(sconnect); test_sysctls(inflight, openfiles); } static void recursion(void) { int fd[2], ff[2]; int inflight, openfiles, deferred, deferred1; test = "recursion"; printf("%s\n", test); save_sysctls(&inflight, &openfiles); deferred = getdeferred(); my_socketpair(fd); for (;;) { if (socketpair(PF_UNIX, SOCK_STREAM, 0, ff) == -1) { if (errno == EMFILE || errno == ENFILE) break; err(-1, "socketpair"); } sendfd(ff[0], fd[0]); sendfd(ff[0], fd[1]); close2(fd[1], fd[0]); fd[0] = ff[0]; fd[1] = ff[1]; } close2(fd[0], fd[1]); sleep(1); test_sysctls(inflight, openfiles); deferred1 = getdeferred(); if (deferred != deferred1) errx(-1, "recursion: deferred before %d after %d", deferred, deferred1); } #define RMDIR "rm -Rf " int -main(int argc, char *argv[]) +main(void) { char cmd[sizeof(RMDIR) + PATH_MAX]; int serrno; pid_t pid; strlcpy(dpath, "unpgc.XXXXXXXX", sizeof(dpath)); if (mkdtemp(dpath) == NULL) err(-1, "mkdtemp"); /* * Set up a parent process to GC temporary storage when we're done. */ pid = fork(); if (pid < 0) { serrno = errno; (void)rmdir(dpath); errno = serrno; err(-1, "fork"); } if (pid > 0) { signal(SIGINT, SIG_IGN); while (waitpid(pid, NULL, 0) != pid); snprintf(cmd, sizeof(cmd), "%s %s", RMDIR, dpath); (void)system(cmd); exit(0); } printf("Start: inflight %d open %d\n", getinflight(), getopenfiles()); twosome_nothing(); twosome_drop(); threesome_nothing(); threesome_drop(); fivesome_nothing(); fivesome_drop(); complex_cycles(); listen_nothing(); listen_drop(); listen_connect_nothing(); listen_connect_drop(); recursion(); printf("Finish: inflight %d open %d\n", getinflight(), getopenfiles()); return (0); } Index: user/ngie/more-tests/tests/sys/socket/unix_passfd_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/unix_passfd_test.c (revision 281585) +++ user/ngie/more-tests/tests/sys/socket/unix_passfd_test.c (revision 281586) @@ -1,395 +1,395 @@ /*- * Copyright (c) 2005 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * UNIX domain sockets allow file descriptors to be passed via "ancillary * data", or control messages. This regression test is intended to exercise * this facility, both performing some basic tests that it operates, and also * causing some kernel edge cases to execute, such as garbage collection when * there are cyclic file descriptor references. Right now we test only with * stream sockets, but ideally we'd also test with datagram sockets. */ static void domainsocketpair(int *fdp) { ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) != -1, "socketpair(PF_UNIX, SOCK_STREAM, ..) failed: %s, ", strerror(errno)); } static void closesocketpair(int *fdp) { close(fdp[0]); close(fdp[1]); } static void tempfile(int *fdp) { char path[PATH_MAX]; int fd; snprintf(path, PATH_MAX, "unix_passfd.XXXXXXXXXXXXXXX"); fd = mkstemp(path); ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno)); (void)unlink(path); *fdp = fd; } static void dofstat(int fd, struct stat *sb) { ATF_REQUIRE_MSG(fstat(fd, sb) != -1, "fstat failed: %s", strerror(errno)); } static void samefile(struct stat *sb1, struct stat *sb2) { ATF_REQUIRE_EQ_MSG(sb1->st_dev, sb2->st_dev, "different devices (%d != %d)", sb1->st_dev, sb2->st_dev); ATF_REQUIRE_EQ_MSG(sb1->st_dev, sb2->st_dev, "different inodes (%u != %u)", sb1->st_ino, sb2->st_ino); } static void sendfd_payload(int sockfd, int sendfd, void *payload, size_t paylen) { struct iovec iovec; char message[CMSG_SPACE(sizeof(int))]; struct cmsghdr *cmsghdr; struct msghdr msghdr; ssize_t len; bzero(&msghdr, sizeof(msghdr)); bzero(&message, sizeof(message)); msghdr.msg_control = message; msghdr.msg_controllen = sizeof(message); iovec.iov_base = payload; iovec.iov_len = paylen; msghdr.msg_iov = &iovec; msghdr.msg_iovlen = 1; cmsghdr = (struct cmsghdr *)message; cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); cmsghdr->cmsg_level = SOL_SOCKET; cmsghdr->cmsg_type = SCM_RIGHTS; *(int *)CMSG_DATA(cmsghdr) = sendfd; len = sendmsg(sockfd, &msghdr, 0); ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno)); ATF_REQUIRE_MSG((size_t)len == paylen, "mismatch with amount of data sent via sendmsg (%zd != %zu)", len, paylen); } static void -sendfd(int sockfd, int sendfd) +sendfd(int sock_fd, int send_fd) { char ch; - return (sendfd_payload(sockfd, sendfd, &ch, sizeof(ch))); + return (sendfd_payload(sock_fd, send_fd, &ch, sizeof(ch))); } static void recvfd_payload(int sockfd, int *recvfd, void *buf, size_t buflen) { struct cmsghdr *cmsghdr; char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)]; struct msghdr msghdr; struct iovec iovec; ssize_t len; bzero(&msghdr, sizeof(msghdr)); msghdr.msg_control = message; msghdr.msg_controllen = sizeof(message); iovec.iov_base = buf; iovec.iov_len = buflen; msghdr.msg_iov = &iovec; msghdr.msg_iovlen = 1; len = recvmsg(sockfd, &msghdr, 0); ATF_REQUIRE_MSG(len != -1, "recvmsg failed: %s", strerror(errno)); ATF_REQUIRE_MSG((size_t)len == buflen, "mismatch with amount of data sent via recvmsg (%zd != %zu)", len, buflen); cmsghdr = CMSG_FIRSTHDR(&msghdr); ATF_REQUIRE_MSG(cmsghdr != NULL, "did not receive control message"); *recvfd = -1; for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { if (cmsghdr->cmsg_level == SOL_SOCKET && cmsghdr->cmsg_type == SCM_RIGHTS && cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { *recvfd = *(int *)CMSG_DATA(cmsghdr); ATF_REQUIRE(*recvfd != -1); } } ATF_REQUIRE_MSG(*recvfd != -1, "recvmsg did not receive a single fd message"); } static void -recvfd(int sockfd, int *recvfd) +recvfd(int sock_fd, int *recv_fd) { char ch; - return (recvfd_payload(sockfd, recvfd, &ch, sizeof(ch))); + return (recvfd_payload(sock_fd, recv_fd, &ch, sizeof(ch))); } /* * First test: put a temporary file into a UNIX domain socket, then * take it out and make sure it's the same file. First time around, * don't close the reference after sending. */ ATF_TC_WITHOUT_HEAD(simple_send_fd); ATF_TC_BODY(simple_send_fd, tc) { struct stat getfd_1_stat, putfd_1_stat; int fd[2], getfd_1, putfd_1; domainsocketpair(fd); tempfile(&putfd_1); dofstat(putfd_1, &putfd_1_stat); sendfd(fd[0], putfd_1); recvfd(fd[1], &getfd_1); dofstat(getfd_1, &getfd_1_stat); samefile(&putfd_1_stat, &getfd_1_stat); close(putfd_1); close(getfd_1); closesocketpair(fd); } /* * Second test: same as first, only close the file reference after * sending, so that the only reference is the descriptor in the UNIX * domain socket buffer. */ ATF_TC_WITHOUT_HEAD(send_and_close); ATF_TC_BODY(send_and_close, tc) { struct stat getfd_1_stat, putfd_1_stat; int fd[2], getfd_1, putfd_1; domainsocketpair(fd); tempfile(&putfd_1); dofstat(putfd_1, &putfd_1_stat); sendfd(fd[0], putfd_1); close(putfd_1); recvfd(fd[1], &getfd_1); dofstat(getfd_1, &getfd_1_stat); samefile(&putfd_1_stat, &getfd_1_stat); close(getfd_1); closesocketpair(fd); } /* * Third test: put a temporary file into a UNIX domain socket, then * close both endpoints causing garbage collection to kick off. */ ATF_TC_WITHOUT_HEAD(send_and_cancel); ATF_TC_BODY(send_and_cancel, tc) { int fd[2], putfd_1; domainsocketpair(fd); tempfile(&putfd_1); sendfd(fd[0], putfd_1); close(putfd_1); closesocketpair(fd); } /* * Send two files. Then receive them. Make sure they are returned * in the right order, and both get there. */ ATF_TC_WITHOUT_HEAD(two_files); ATF_TC_BODY(two_files, tc) { struct stat getfd_1_stat, getfd_2_stat, putfd_1_stat, putfd_2_stat; int fd[2], getfd_1, getfd_2, putfd_1, putfd_2; domainsocketpair(fd); tempfile(&putfd_1); tempfile(&putfd_2); dofstat(putfd_1, &putfd_1_stat); dofstat(putfd_2, &putfd_2_stat); sendfd(fd[0], putfd_1); sendfd(fd[0], putfd_2); close(putfd_1); close(putfd_2); recvfd(fd[1], &getfd_1); recvfd(fd[1], &getfd_2); dofstat(getfd_1, &getfd_1_stat); dofstat(getfd_2, &getfd_2_stat); samefile(&putfd_1_stat, &getfd_1_stat); samefile(&putfd_2_stat, &getfd_2_stat); close(getfd_1); close(getfd_2); closesocketpair(fd); } /* * Big bundling test. Send an endpoint of the UNIX domain socket * over itself, closing the door behind it. */ ATF_TC_WITHOUT_HEAD(bundle); ATF_TC_BODY(bundle, tc) { int fd[2], getfd_1; domainsocketpair(fd); sendfd(fd[0], fd[0]); close(fd[0]); recvfd(fd[1], &getfd_1); close(getfd_1); close(fd[1]); } /* * Big bundling test part two: Send an endpoint of the UNIX domain * socket over itself, close the door behind it, and never remove it * from the other end. */ ATF_TC_WITHOUT_HEAD(bundle_cancel); ATF_TC_BODY(bundle_cancel, tc) { int fd[2]; domainsocketpair(fd); sendfd(fd[0], fd[0]); sendfd(fd[1], fd[0]); closesocketpair(fd); } /* * Test for PR 151758: Send an character device over the UNIX * domain socket and then close both sockets to orphan the * device. */ ATF_TC_WITHOUT_HEAD(devfs_orphan); ATF_TC_BODY(devfs_orphan, tc) { int fd[2], putfd_1; domainsocketpair(fd); putfd_1 = open(_PATH_DEVNULL, O_RDONLY); ATF_REQUIRE_MSG(putfd_1 != -1, "opening %s failed: %s", _PATH_DEVNULL, strerror(errno)); sendfd(fd[0], putfd_1); close(putfd_1); closesocketpair(fd); } #define LOCAL_STREAM_SENDSPACE "net.local.stream.sendspace" /* * Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel * prepends a control message to the data. Sender sends large * payload. Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer * limit, and receiver receives truncated data. */ ATF_TC_WITHOUT_HEAD(rights_with_LOCAL_CREDS_and_large_payload); ATF_TC_BODY(rights_with_LOCAL_CREDS_and_large_payload, tc) { void *buf; int fd[2]; size_t len; u_long sendspace; const int on = 1; int getfd_1, putfd_1, rc; atf_tc_expect_fail("Bug 181741 has not been fixed yet"); len = sizeof(sendspace); rc = sysctlbyname(LOCAL_STREAM_SENDSPACE, &sendspace, &len, NULL, 0); ATF_REQUIRE_MSG(rc == 0, "sysctlbyname %s failed: %s", LOCAL_STREAM_SENDSPACE, strerror(errno)); ATF_REQUIRE((buf = malloc(sendspace)) != NULL); domainsocketpair(fd); rc = setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)); ATF_REQUIRE_MSG(rc == 0, "setsockopt failed: %s", strerror(errno)); tempfile(&putfd_1); sendfd_payload(fd[0], putfd_1, buf, sendspace); recvfd_payload(fd[1], &getfd_1, buf, sendspace); close(putfd_1); close(getfd_1); closesocketpair(fd); } ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, simple_send_fd); ATF_TP_ADD_TC(tp, send_and_close); ATF_TP_ADD_TC(tp, send_and_cancel); ATF_TP_ADD_TC(tp, two_files); ATF_TP_ADD_TC(tp, bundle); ATF_TP_ADD_TC(tp, bundle_cancel); ATF_TP_ADD_TC(tp, devfs_orphan); ATF_TP_ADD_TC(tp, rights_with_LOCAL_CREDS_and_large_payload); return (atf_no_error()); } Index: user/ngie/more-tests/tests/sys/socket/zerosend_test.c =================================================================== --- user/ngie/more-tests/tests/sys/socket/zerosend_test.c (revision 281585) +++ user/ngie/more-tests/tests/sys/socket/zerosend_test.c (revision 281586) @@ -1,342 +1,342 @@ /*- * Copyright (c) 2007 Robert N. M. Watson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void try_0send(int fd) { ssize_t len; char ch; ch = 0; len = send(fd, &ch, 0, 0); ATF_REQUIRE_MSG(len != -1, "send failed: %s", strerror(errno)); ATF_REQUIRE_MSG(len == 0, "send returned %zd (not 0): %s", len, strerror(errno)); } static void try_0write(int fd) { ssize_t len; char ch; ch = 0; len = write(fd, &ch, 0); ATF_REQUIRE_MSG(len != -1, "write failed: %s", strerror(errno)); ATF_REQUIRE_MSG(len == 0, "write returned: %zd (not 0): %s", len, strerror(errno)); } static void setup_udp(int *fdp) { struct sockaddr_in sin; int port_base, sock1, sock2; bzero(&sin, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); port_base = MAX((int)random() % 65535, 1025); sin.sin_port = htons(port_base); sock1 = socket(PF_INET, SOCK_DGRAM, 0); ATF_REQUIRE_MSG(sock1 != -1, "socket # 1 failed: %s", strerror(errno)); ATF_REQUIRE_MSG(bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) == 0, "bind # 1 failed: %s", strerror(errno)); sin.sin_port = htons(port_base + 1); ATF_REQUIRE_MSG(connect(sock1, (struct sockaddr *)&sin, sizeof(sin)) == 0, "connect # 1 failed: %s", strerror(errno)); sock2 = socket(PF_INET, SOCK_DGRAM, 0); ATF_REQUIRE_MSG(sock2 != -1, "socket # 2 failed: %s", strerror(errno)); ATF_REQUIRE_MSG(bind(sock2, (struct sockaddr *)&sin, sizeof(sin)) == 0, "bind # 2 failed: %s", strerror(errno)); sin.sin_port = htons(port_base); ATF_REQUIRE_MSG(connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) == 0, "connect # 2 failed: %s", strerror(errno)); fdp[0] = sock1; fdp[1] = sock2; fdp[2] = -1; } static void setup_tcp(int *fdp) { fd_set writefds, exceptfds; struct sockaddr_in sin; int port_base, ret, sock1, sock2, sock3; struct timeval tv; bzero(&sin, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); port_base = MAX((int)random() % 65535, 1025); /* * First set up the listen socket. */ sin.sin_port = htons(port_base); sock1 = socket(PF_INET, SOCK_STREAM, 0); ATF_REQUIRE_MSG(sock1 != -1, "socket # 1 failed: %s", strerror(errno)); ATF_REQUIRE_MSG(bind(sock1, (struct sockaddr *)&sin, sizeof(sin)) == 0, "bind # 1 failed: %s", strerror(errno)); ATF_REQUIRE_MSG(listen(sock1, -1) == 0, "listen # 1 failed: %s", strerror(errno)); /* * Now connect to it, non-blocking so that we don't deadlock against * ourselves. */ sock2 = socket(PF_INET, SOCK_STREAM, 0); ATF_REQUIRE_MSG(sock2 != -1, "socket # 2 failed: %s", strerror(errno)); ATF_REQUIRE_MSG(fcntl(sock2, F_SETFL, O_NONBLOCK) == 0, "setting socket as nonblocking failed: %s", strerror(errno)); ATF_REQUIRE_MSG( (connect(sock2, (struct sockaddr *)&sin, sizeof(sin)) == 0 || errno == EINPROGRESS), "connect # 2 failed: %s", strerror(errno)); /* * Now pick up the connection after sleeping a moment to make sure * there's been time for some packets to go back and forth. */ ATF_REQUIRE_MSG(sleep(1) == 0, "sleep(1) <= 0"); sock3 = accept(sock1, NULL, NULL); ATF_REQUIRE_MSG(sock3 != -1, "accept failed: %s", strerror(errno)); ATF_REQUIRE_MSG(sleep(1) == 0, "sleep(1) <= 0"); FD_ZERO(&writefds); FD_SET(sock2, &writefds); FD_ZERO(&exceptfds); FD_SET(sock2, &exceptfds); tv.tv_sec = 1; tv.tv_usec = 0; ret = select(sock2 + 1, NULL, &writefds, &exceptfds, &tv); ATF_REQUIRE_MSG(ret != -1, "select failed: %s", strerror(errno)); ATF_REQUIRE_MSG(!FD_ISSET(sock2, &exceptfds), "select: exception occurred with sock2"); ATF_REQUIRE_MSG(FD_ISSET(sock2, &writefds), "not writable"); close(sock1); fdp[0] = sock2; fdp[1] = sock3; fdp[2] = sock1; } static void setup_udsstream(int *fdp) { ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_STREAM, 0, fdp) == 0, "socketpair failed: %s", strerror(errno)); } static void setup_udsdgram(int *fdp) { ATF_REQUIRE_MSG(socketpair(PF_LOCAL, SOCK_DGRAM, 0, fdp) == 0, "socketpair failed: %s", strerror(errno)); } static void setup_pipe(int *fdp) { ATF_REQUIRE_MSG(pipe(fdp) == 0, "pipe failed: %s", strerror(errno)); } static void setup_fifo(int *fdp) { char path[] = "0send_fifo.XXXXXXX"; int fd1, fd2; ATF_REQUIRE_MSG(mkstemp(path) != -1, "mkstemp failed: %s", strerror(errno)); unlink(path); ATF_REQUIRE_MSG(mkfifo(path, 0600) == 0, "mkfifo(\"%s\", 0600) failed: %s", path, strerror(errno)); fd1 = open(path, O_RDONLY | O_NONBLOCK); ATF_REQUIRE_MSG(fd1 != -1, "open(\"%s\", O_RDONLY)", path); fd2 = open(path, O_WRONLY | O_NONBLOCK); ATF_REQUIRE_MSG(fd2 != -1, "open(\"%s\", O_WRONLY)", path); fdp[0] = fd2; fdp[1] = fd1; fdp[2] = -1; } static int fd[3]; static void close_fds(int *fdp) { - int i; + unsigned int i; for (i = 0; i < nitems(fdp); i++) close(fdp[i]); } ATF_TC_WITHOUT_HEAD(udp_zero_send); ATF_TC_BODY(udp_zero_send, tc) { setup_udp(fd); try_0send(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(udp_zero_write); ATF_TC_BODY(udp_zero_write, tc) { setup_udp(fd); try_0write(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(tcp_zero_send); ATF_TC_BODY(tcp_zero_send, tc) { setup_tcp(fd); try_0send(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(tcp_zero_write); ATF_TC_BODY(tcp_zero_write, tc) { setup_tcp(fd); try_0write(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(udsstream_zero_send); ATF_TC_BODY(udsstream_zero_send, tc) { setup_udsstream(fd); try_0send(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(udsstream_zero_write); ATF_TC_BODY(udsstream_zero_write, tc) { setup_udsstream(fd); try_0write(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(udsdgram_zero_send); ATF_TC_BODY(udsdgram_zero_send, tc) { setup_udsdgram(fd); try_0send(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(udsdgram_zero_write); ATF_TC_BODY(udsdgram_zero_write, tc) { setup_udsdgram(fd); try_0write(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(pipe_zero_write); ATF_TC_BODY(pipe_zero_write, tc) { setup_pipe(fd); try_0write(fd[0]); close_fds(fd); } ATF_TC_WITHOUT_HEAD(fifo_zero_write); ATF_TC_BODY(fifo_zero_write, tc) { setup_fifo(fd); try_0write(fd[0]); close_fds(fd); } ATF_TP_ADD_TCS(tp) { srandomdev(); ATF_TP_ADD_TC(tp, udp_zero_send); ATF_TP_ADD_TC(tp, udp_zero_write); ATF_TP_ADD_TC(tp, tcp_zero_send); ATF_TP_ADD_TC(tp, tcp_zero_write); ATF_TP_ADD_TC(tp, udsstream_zero_write); ATF_TP_ADD_TC(tp, udsstream_zero_send); ATF_TP_ADD_TC(tp, udsdgram_zero_write); ATF_TP_ADD_TC(tp, udsdgram_zero_send); ATF_TP_ADD_TC(tp, pipe_zero_write); ATF_TP_ADD_TC(tp, fifo_zero_write); return (atf_no_error()); }